[
  {
    "path": ".gitignore",
    "content": "*~\n*~.*\n.DS_Store\n.LSOverride\n*.mode1v3\n*.mode2v3\n*.pbxuser\n*.perspectivev3\n*.pyc\n.tmp\nbuild\nBuild Results\nxcuserdata\n*.xcworkspace\nSources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installation Files/Extensions/*\nSources/App/Resources/Scripting/Script Files/Textual Extras Installer/Packages/MACAPPSTORE/*\nSources/App/Resources/Scripting/Script Files/Textual Extras Installer/Packages/STANDALONE/*\n!/Configurations/Build\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"Frameworks/Auto Hyperlinks\"]\n\tpath = Frameworks/Auto Hyperlinks\n\turl = https://github.com/Codeux-Software/Auto-Hyperlinks.git\n[submodule \"Frameworks/Cocoa Extensions\"]\n\tpath = Frameworks/Cocoa Extensions\n\turl = https://github.com/Codeux-Software/Cocoa-Extensions.git\n[submodule \"Frameworks/Encryption Kit\"]\n\tpath = Frameworks/Encryption Kit\n\turl = https://github.com/Codeux-Software/Encryption-Kit.git\n[submodule \"Frameworks/Static Libraries\"]\n\tpath = Frameworks/Static Libraries\n\turl = https://github.com/Codeux-Software/Static-Libraries.git\n[submodule \"Sources/Plugins/Sample Code/Swift Bot\"]\n\tpath = Sources/Plugins/Sample Code/Swift Bot\n\turl = https://github.com/Codeux/Textual-Swift-Plugin.git\n"
  },
  {
    "path": "Configurations/Build/Code Signing Identity.xcconfig",
    "content": "\n// This is the code signing identity used by all projects.\n\nCODE_SIGN_IDENTITY = Mac Developer\n\n// Set these values to empty\n\nDEVELOPMENT_TEAM = 8482Q6EPL6\nPROVISIONING_PROFILE_SPECIFIER = 8482Q6EPL6/\n"
  },
  {
    "path": "Configurations/Build/Common/Foundation Debug.xcconfig",
    "content": "\n// Foundation Debug.xcconfig acts as a base for ALL projects.\n// This configuration should NEVER contain any settings\n// which may be unique to a specific project.\n\n#include \"Foundation.xcconfig\"\n\nDEPLOYMENT_POSTPROCESSING = NO\nENABLE_NS_ASSERTIONS = YES\nENABLE_TESTABILITY = YES\nGCC_OPTIMIZATION_LEVEL = 0\nGCC_PREPROCESSOR_DEFINITIONS = DEBUG\nONLY_ACTIVE_ARCH = YES\nRUN_CLANG_STATIC_ANALYZER = NO\nSWIFT_COMPILATION_MODE = singlefile\nSWIFT_OPTIMIZATION_LEVEL = -Onone\nVERSION_INFO_BUILDER = ${USER}\n\n//\n// On Xcode 16, Textual failed to run in debug mode because\n// a \"Textual.debug.dylib\" file was missing in the @rpath\n// of extensions and services. Going to disable this feature\n// of Xcode until a later release of Xcode.\n//\n// From Xcode 16 beta 1 release notes:\n//\n// Some large or complex projects may fail to build and\n// run if they are scanning for specific Mach-O sections\n// in their binaries. (123416939)\n//\n// Workaround: Try setting the build setting ENABLE_DEBUG_DYLIB=NO.\n// This will disable the debug dylib that enables the new preview\n// execution mode. Setting this to NO will still allow you to\n// preview in Xcode 16 Seed 1 using the legacy execution mode,\n// but support for this mode will be removed in a future build.\n//\nENABLE_DEBUG_DYLIB = NO\n"
  },
  {
    "path": "Configurations/Build/Common/Foundation.xcconfig",
    "content": "\n// Foundation.xcconfig acts as a base for ALL projects.\n// This configuration should NEVER contain any settings\n// which may be unique to a specific project.\n\nALWAYS_SEARCH_USER_PATHS = NO\nAPPLY_RULES_IN_COPY_FILES = YES\nARCHS = $(ARCHS_STANDARD)\nCLANG_ANALYZER_GCD_PERFORMANCE = YES\nCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES\nCLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES\nCLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES\nCLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES\nCLANG_CXX_LANGUAGE_STANDARD = gnu++0x\nCLANG_ENABLE_MODULES = YES\nCLANG_ENABLE_OBJC_ARC = YES\nCLANG_USE_OPTIMIZATION_PROFILE = NO\nCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES\nCLANG_WARN_BOOL_CONVERSION = YES\nCLANG_WARN_COMMA = YES\nCLANG_WARN_CONSTANT_CONVERSION = YES\nCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES\nCLANG_WARN_EMPTY_BODY = YES\nCLANG_WARN_ENUM_CONVERSION = YES\nCLANG_WARN_INFINITE_RECURSION = YES\nCLANG_WARN_INT_CONVERSION = YES\nCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES\nCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES\nCLANG_WARN_OBJC_LITERAL_CONVERSION = YES\nCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES\nCLANG_WARN_RANGE_LOOP_ANALYSIS = YES\nCLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES\nCLANG_WARN_STRICT_PROTOTYPES = YES\nCLANG_WARN_SUSPICIOUS_MOVE = YES\nCLANG_WARN_UNREACHABLE_CODE = YES\nCLANG_WARN__DUPLICATE_METHOD_MATCH = YES\nCODE_SIGN_ENTITLEMENTS =\nCOMBINE_HIDPI_IMAGES = YES\nCONFIGURATION_BUILD_DIR = $(PROJECT_DIR)/Build Results/$(CONFIGURATION)\nCOPY_PHASE_STRIP = NO\nDEAD_CODE_STRIPPING = YES\nDEBUG_INFORMATION_FORMAT = dwarf-with-dsym\nDEFINES_MODULE = YES\nDEPLOYMENT_POSTPROCESSING = YES\nENABLE_HARDENED_RUNTIME = YES\nENABLE_NS_ASSERTIONS = YES\nENABLE_STRICT_OBJC_MSGSEND = NO\nFRAMEWORK_SEARCH_PATHS =\nGCC_C_LANGUAGE_STANDARD = gnu99\nGCC_DYNAMIC_NO_PIC = YES\nGCC_ENABLE_OBJC_EXCEPTIONS = YES\nGCC_GENERATE_DEBUGGING_SYMBOLS = YES\nGCC_NO_COMMON_BLOCKS = YES\nGCC_OPTIMIZATION_LEVEL = fast\nGCC_PREFIX_HEADER =\nGCC_UNROLL_LOOPS = YES\nGCC_WARN_64_TO_32_BIT_CONVERSION = YES\nGCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES\nGCC_WARN_ABOUT_MISSING_NEWLINE = YES\nGCC_WARN_ABOUT_RETURN_TYPE = YES\nGCC_WARN_TYPECHECK_CALLS_TO_PRINTF = NO\nGCC_WARN_UNDECLARED_SELECTOR = NO\nGCC_WARN_UNINITIALIZED_AUTOS = YES\nGCC_WARN_UNUSED_FUNCTION = YES\nGCC_WARN_UNUSED_LABEL = YES\nGCC_WARN_UNUSED_VARIABLE = YES\nHEADER_SEARCH_PATHS =\nINFOPLIST_OUTPUT_FORMAT = binary\nLD_NO_PIE = YES\nLD_NO_PIE[arch=arm64] = NO\nLD_RUNPATH_SEARCH_PATHS = @loader_path/../Frameworks @executable_path/../Frameworks\nLIBRARY_SEARCH_PATHS =\nMACOSX_DEPLOYMENT_TARGET = 11.0\nONLY_ACTIVE_ARCH = NO\nOTHER_CFLAGS = -Xclang -fobjc-runtime-has-weak\nPLIST_FILE_OUTPUT_FORMAT = binary\nPRODUCT_BUNDLE_IDENTIFIER =\nREMOVE_HEADERS_FROM_EMBEDDED_BUNDLES = YES\nRUN_CLANG_STATIC_ANALYZER = NO\nSTRINGS_FILE_OUTPUT_ENCODING = binary\nSWIFT_COMPILATION_MODE = wholemodule\nSWIFT_INSTALL_OBJC_HEADER = NO\nSWIFT_OPTIMIZATION_LEVEL = -O\nSWIFT_VERSION = 5.0\nVERSION_INFO_BUILDER = Codeux Software, LLC\nWARNING_CFLAGS = -Wobjc-circular-container -Winfinite-recursion\n\n#include \"../Code Signing Identity.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Common/Preserve Symbols.xcconfig",
    "content": "\n// It is important to preserve symbols and code that is\n// not directly used so that extensions can use them.\n\nDEAD_CODE_STRIPPING = NO\nGCC_SYMBOLS_PRIVATE_EXTERN = NO\nSTRIP_STYLE = non-global\n"
  },
  {
    "path": "Configurations/Build/Common/Textual App.xcconfig",
    "content": "\n// Main application\n\nTEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../..\n\nHEADER_SEARCH_PATHS = \"${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/\" \"${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**\"\nFRAMEWORK_SEARCH_PATHS = \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\nLIBRARY_SEARCH_PATHS = \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\n\nPRODUCT_BUNDLE_IDENTIFIER = ${TEXTUAL_BUNDLE_IDENTIFIER}\n\nPRODUCT_NAME = ${TEXTUAL_PRODUCT_NAME}\n\nWRAPPER_EXTENSION = app\n\nPRODUCT_MODULE_NAME = Textual\n\nCONFIGURATION_BUILD_DIR = $(TEXTUAL_WORKSPACE_DIR)/Build Results/$(CONFIGURATION)\n\nGCC_PREFIX_HEADER = ${PROJECT_DIR}/Classes/Headers/Private/TextualPrivate.h\n\nSWIFT_OBJC_BRIDGING_HEADER = ${PROJECT_DIR}/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h\n\nALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES\n\nREMOVE_HEADERS_FROM_EMBEDDED_BUNDLES = NO\n\nINFOPLIST_FILE = ${TEXTUAL_WORKSPACE_TEMP_DIR}/Info.plist\n\n#include \"Preserve Symbols.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Common/Textual Extensions.xcconfig",
    "content": "\n// Textual Extensions *.xcconfig file contains settings that\n// are specific to extensions for Textual (main application).\n\n// TEXTUAL_WORKSPACE_DIR is replaced by the build script\nTEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../../..\n\nCONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Extensions\n\nCODE_SIGN_ENTITLEMENTS = ${TEXTUAL_WORKSPACE_DIR}/Configurations/Sandbox/Inherited.entitlements\n\nHEADER_SEARCH_PATHS = ${inherited} \"${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/\" \"${TEXTUAL_WORKSPACE_DIR}/Sources/App/Classes/Headers/**\" \"${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**\"\nLIBRARY_SEARCH_PATHS = ${inherited} \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\nFRAMEWORK_SEARCH_PATHS = ${inherited} \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\n\nWRAPPER_EXTENSION = bundle\n\nPROVISIONING_PROFILE =\nPROVISIONING_PROFILE_SPECIFIER =\n\nBUNDLE_LOADER = ${TEXTUAL_PRODUCT_BINARY}\n"
  },
  {
    "path": "Configurations/Build/Common/Textual.xcconfig",
    "content": "\n// Main application, extensions, and XPC services\n\nTEXTUAL_PRODUCT_NAME = Textual\n\n// TEXTUAL_PRODUCT_LOCATION is replaced by the build script\nTEXTUAL_PRODUCT_LOCATION = /Applications/${TEXTUAL_PRODUCT_NAME}.app\n\n// TEXTUAL_PRODUCT_BINARY is replaced by the build script\nTEXTUAL_PRODUCT_BINARY = ${TEXTUAL_PRODUCT_LOCATION}/Contents/MacOS/${TEXTUAL_PRODUCT_NAME}\n\n// TEXTUAL_WORKSPACE_TEMP_DIR should be same for every\n// project so only override TEXTUAL_WORKSPACE_DIR, not this.\nTEXTUAL_WORKSPACE_TEMP_DIR = ${TEXTUAL_WORKSPACE_DIR}/.tmp\n\nSHARED_PRECOMPS_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedPCH\n\nDWARF_DSYM_FOLDER_PATH = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedSymbols\n\n// TEXTUAL_BUILT_AS_UNIVERSAL_BINARY acts an easy way to\n// modify code based on the type of binary being built.\n// As with other feature flags, changing this value only\n// adds or excludes certain chunks of code. It doesn't\n// change the underlying build process.\nTEXTUAL_BUILT_AS_UNIVERSAL_BINARY = 1\n"
  },
  {
    "path": "Configurations/Build/Common/XPC Service - ICL Extensions.xcconfig",
    "content": "\n// Inline Content Loader XPC service extensions\n\n// TEXTUAL_WORKSPACE_DIR is replaced by the build script\nTEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../../../..\n\n// ICL_WORKSPACE_DIR is NOT replaced by the build script\nICL_WORKSPACE_DIR = ${TEXTUAL_WORKSPACE_DIR}/XPC Services/Inline Content Loader\n\n// ICL_PRODUCT_LOCATION is replaced by the build script\nICL_PRODUCT_LOCATION = ${TEXTUAL_PRODUCT_LOCATION}/Contents/XPCServices/InlineContentLoader.xpc\n\n// ICL_PRODUCT_BINARY is replaced by the build script\nICL_PRODUCT_BINARY = ${ICL_PRODUCT_LOCATION}/Contents/MacOS/InlineContentLoader\n\nCONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-ICLExtension\n\nHEADER_SEARCH_PATHS = ${inherited} \"${ICL_WORKSPACE_DIR}/Classes/Headers/**\" \"${ICL_WORKSPACE_DIR}/Classes/Modules/**\" \"${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**\"\nLIBRARY_SEARCH_PATHS = ${inherited} \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\nFRAMEWORK_SEARCH_PATHS = ${inherited} \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\n\nWRAPPER_EXTENSION = bundle\n\nPROVISIONING_PROFILE =\nPROVISIONING_PROFILE_SPECIFIER =\n\nBUNDLE_LOADER = ${ICL_PRODUCT_BINARY}\n"
  },
  {
    "path": "Configurations/Build/Common/XPC Service - ICL.xcconfig",
    "content": "\n// Inline content loader XPC service\n\n#include \"Preserve Symbols.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Common/XPC Services.xcconfig",
    "content": "\n// XPC services\n\n// TEXTUAL_WORKSPACE_DIR is replaced by the build script\nTEXTUAL_WORKSPACE_DIR = ${PROJECT_DIR}/../..\n\nCONFIGURATION_BUILD_DIR = ${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-XPCServices\n\nCODE_SIGN_ENTITLEMENTS = ${TEXTUAL_WORKSPACE_DIR}/Configurations/Sandbox/Inherited.entitlements\n\nHEADER_SEARCH_PATHS = $(inherited) \"${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/\" \"${TEXTUAL_WORKSPACE_DIR}/Sources/Shared/Headers/**\"\nLIBRARY_SEARCH_PATHS = $(inherited) \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\nFRAMEWORK_SEARCH_PATHS = $(inherited) \"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks/**\" \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/**\"\n\nWRAPPER_EXTENSION = xpc\n\nGCC_PREPROCESSOR_DEFINITIONS = $(inherited) TEXTUAL_BUILDING_XPC_SERVICE=1\n\n// Link against frameworks in app itself rather than creating copies\n// ./(self) ../(Contents) ../(.xpc bundle) ../(XPCServices) ../(Contents)\nLD_RUNPATH_SEARCH_PATHS = $(inherited) @loader_path/../../../../Frameworks\n"
  },
  {
    "path": "Configurations/Build/Debug/Enabled Features.xcconfig",
    "content": "\n// The main project of Textual, its extensions, and its XPC services\n// all inherit one of these configuration files to allow them to\n// selectively disable code based on which features are enabled.\n\n// These macros that are used to disable and enable the inclusion\n// of certain segments of code. Toggling one of these flags does not\n// guarantee that the toggled feature will work. These only toggle the code.\n// Not add additional resource files that the code may be dependent on.\n// To add new feature flags, modify UpdateFeatureFlags.sh\n\nTEXTUAL_BUILT_INSIDE_SANDBOX=1\nTEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION=1\nTEXTUAL_BUILT_WITH_LICENSE_MANAGER=1\n"
  },
  {
    "path": "Configurations/Build/Debug/Textual App.xcconfig",
    "content": "\n#include \"../Common/Foundation Debug.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/Textual App.xcconfig\"\n\nCODE_SIGN_ENTITLEMENTS = ${PROJECT_DIR}/Configurations/Sandbox/Debug.entitlements\n"
  },
  {
    "path": "Configurations/Build/Debug/Textual Extensions.xcconfig",
    "content": "\n#include \"../Common/Foundation Debug.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/Textual Extensions.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Debug/Textual.xcconfig",
    "content": "\n#include \"../Common/Textual.xcconfig\"\n#include \"Enabled Features.xcconfig\"\n\nTEXTUAL_BUNDLE_IDENTIFIER = com.codeux.apps.textual\nTEXTUAL_GROUP_CONTAINER_IDENTIFIER = 8482Q6EPL6.com.codeux.apps.textual\nTEXTUAL_BUILD_SCHEME_TOKEN = debug\n\nTEXTUAL_EXTENSION_BUILD_SCHEME = Debug\nTEXTUAL_FRAMEWORK_BUILD_SCHEME = Release // Frameworks don't have a Debug scheme\nTEXTUAL_XPC_SERVICE_BUILD_SCHEME = Debug\n"
  },
  {
    "path": "Configurations/Build/Debug/XPC Service - ICL Extensions.xcconfig",
    "content": "\n#include \"../Common/Foundation Debug.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/XPC Service - ICL Extensions.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Debug/XPC Service - ICL.xcconfig",
    "content": "\n#include \"XPC Services.xcconfig\"\n#include \"../Common/XPC Service - ICL.xcconfig\"\n\nICL_EXTENSION_BUILD_SCHEME = Debug\n"
  },
  {
    "path": "Configurations/Build/Debug/XPC Services.xcconfig",
    "content": "\n#include \"../Common/Foundation Debug.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/XPC Services.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/README.md",
    "content": "\nTODO: Write a README\n"
  },
  {
    "path": "Configurations/Build/Standard Release/Enabled Features.xcconfig",
    "content": "\n// The main project of Textual, its extensions, and its XPC services\n// all inherit one of these configuration files to allow them to\n// selectively disable code based on which features are enabled.\n\n// These macros that are used to disable and enable the inclusion\n// of certain segments of code. Toggling one of these flags does not\n// guarantee that the toggled feature will work. These only toggle the code.\n// Not add additional resource files that the code may be dependent on.\n// To add new feature flags, modify UpdateFeatureFlags.sh\n\nTEXTUAL_BUILT_INSIDE_SANDBOX=1\nTEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION=1\nTEXTUAL_BUILT_WITH_LICENSE_MANAGER=1\nTEXTUAL_BUILT_WITH_SPARKLE_ENABLED=1\n"
  },
  {
    "path": "Configurations/Build/Standard Release/Textual App.xcconfig",
    "content": "\n#include \"../Common/Foundation.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/Textual App.xcconfig\"\n\nCODE_SIGN_ENTITLEMENTS = ${PROJECT_DIR}/Configurations/Sandbox/Standard Release.entitlements\n"
  },
  {
    "path": "Configurations/Build/Standard Release/Textual Extensions.xcconfig",
    "content": "\n#include \"../Common/Foundation.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/Textual Extensions.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Standard Release/Textual.xcconfig",
    "content": "\n#include \"../Common/Textual.xcconfig\"\n#include \"Enabled Features.xcconfig\"\n\nTEXTUAL_BUNDLE_IDENTIFIER = com.codeux.apps.textual\nTEXTUAL_GROUP_CONTAINER_IDENTIFIER = 8482Q6EPL6.com.codeux.apps.textual\nTEXTUAL_BUILD_SCHEME_TOKEN = devid\n\nTEXTUAL_EXTENSION_BUILD_SCHEME = Release\nTEXTUAL_FRAMEWORK_BUILD_SCHEME = Release\nTEXTUAL_XPC_SERVICE_BUILD_SCHEME = Release\n"
  },
  {
    "path": "Configurations/Build/Standard Release/XPC Service - ICL Extensions.xcconfig",
    "content": "\n#include \"../Common/Foundation.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/XPC Service - ICL Extensions.xcconfig\"\n"
  },
  {
    "path": "Configurations/Build/Standard Release/XPC Service - ICL.xcconfig",
    "content": "\n#include \"XPC Services.xcconfig\"\n#include \"../Common/XPC Service - ICL.xcconfig\"\n\nICL_EXTENSION_BUILD_SCHEME = Release\n"
  },
  {
    "path": "Configurations/Build/Standard Release/XPC Services.xcconfig",
    "content": "\n#include \"../Common/Foundation.xcconfig\"\n#include \"Textual.xcconfig\"\n#include \"../Common/XPC Services.xcconfig\"\n"
  },
  {
    "path": "Configurations/ExportArchiveConfiguration.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>teamID</key>\n\t<string>8482Q6EPL6</string>\n\t<key>method</key>\n\t<string>developer-id</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Configurations/Sandbox/Inherited.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.inherit</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "README.md",
    "content": "> [!IMPORTANT]\n> Textual is no longer being actively maintained. For the life of the project, it only ever had one full time maintainer whom has now moved on to different ventures in their life. To all that have contributed to Textual in some form in the past; be it a suggestion, bug report, pull request, financial support, or some other form of contribvution, you will forever be loved. Thank you so much. Words cannot properly express the gratitude we have for every single user. \n\n# Textual [![GitHub release](https://img.shields.io/github/tag/Codeux-Software/Textual.svg)](https://github.com/Codeux-Software/Textual/blob/master) [![Platform](https://img.shields.io/badge/platform-OS%20X-lightgrey.svg)](http://www.textualapp.com/mac-app-store)\n\nTextual is a highly customizable app for interacting with Internet Relay Chat (IRC) chatrooms on macOS.\n\nTextual can be customized with styles written in CSS, HTML, and JavaScript; [plugins](https://help.codeux.com/textual/Writing-Plugins.kb) written in Objective-C & Swift, and [scripts](https://help.codeux.com/textual/Writing-Scripts.kb) written in AppleScript (plus many other languages)\n\nPrecompiled versions of Textual can be purchased in the [directly from codeux.com](https://www.textualapp.com/).\n\n## Screenshots\n\n[![Light Screenshot](https://www.codeux.com/textual/private/images/v600media/YosemiteLightThumbnail.png)](https://www.codeux.com/textual/private/images/v600media/YosemiteLightFullscreen.png) \n[![Dark Screenshot](https://www.codeux.com/textual/private/images/v600media/YosemiteDarkThumbnail.png)](https://www.codeux.com/textual/private/images/v600media/YosemiteDarkFullscreen.png)\n\n## Resources\n\n- [Homepage](https://codeux.com/textual)\n- [Frequently Asked Questions](https://help.codeux.com/textual/Frequently-Asked-Questions.kb)\n- [Support](https://help.codeux.com/textual/Support.kb)\n- \\#textual on irc.libera.chat\n- Guides: [Writing Plugins](https://help.codeux.com/textual/Writing-Plugins.kb), [Writing Scripts](https://help.codeux.com/textual/Writing-Scripts.kb)\n\n## Note Regarding Downloading Source Code\n\nTextual is dependent on several other projects to build. This repository is automatically linked against these other projects using what are known as \"submodules\" — Clicking the \"Download ZIP\" button to build a copy of Textual will not download a copy of these projects. The source code must be cloned using [Github for Mac](https://mac.github.com/) or by using the following commands in Terminal:\n\n```\ngit clone https://github.com/Codeux-Software/Textual.git Textual\ncd Textual\ngit submodule update --init --recursive\n```\n\n## Note Regarding Code Signing\n\n**DO NOT change the Code Signing Identity setting through Xcode.** Textual uses a configuration file to specify the code signing identity. This allows it to be used across all projects associated with Textual without having to modify each.\n\n**DO** edit the file located at _[Configurations ➜ Build ➜ Code Signing Identity.xcconfig](https://github.com/Codeux-Software/Textual/blob/master/Configurations/Build/Code%20Signing%20Identity.xcconfig)_\n\n**It is HIGHLY DISCOURAGED to turn off code signing.** Certain features rely on the fact that Textual is properly signed and is within a sandboxed environment.\n\n**TEXTUAL DOES NOT REQUIRE A CERTIFICATE ISSUED BY APPLE TO BUILD** which means there is absolutely no reason to turn code signing off.\n\n## Note Regarding Trial Mode\n\nThe code which is responsible for licensing paid copies of Textual is in the source code that you download from here.\n\nIf you do not have a license key, then set the ``TEXTUAL_BUILT_WITH_LICENSE_MANAGER`` flag to `0` in the `Standard Release` configuration file to disable the inclusion of this code at build time.\n\n## Building Textual\n\nThe latest version of Textual requires two things to be built. One is a valid (does not need to be issued by Apple) code signing certificate. The second is an installation of Xcode 10.0 or newer on macOS High Sierra. **Building on anything earlier is not supported because of Swift 4.2 code.**\n\n**DO NOT change the Code Signing Identity setting through Xcode.** Modify the file located at _[Configurations ➜ Build ➜ Code Signing Identity.xcconfig](https://github.com/Codeux-Software/Textual/blob/master/Configurations/Build/Code%20Signing%20Identity.xcconfig)_ instead.\n\nBuild Textual using the \"Standard Release\" build scheme.\n\n## Original Limechat License\n\nTextual began as a fork of [LimeChat](https://github.com/psychs/limechat) in 2010\n\nLimeChat's original license is presented below.\n\n<pre>\nThe New BSD License\n\nCopyright (c) 2008 - 2010 Satoshi Nakagawa < psychs AT limechat DOT net >\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n</pre>\n\n## License for content originating from Textual\n\nUnless stated otherwise by Textual's [Acknowledgements.pdf](Acknowledgements.pdf) document, the license presented below shall govern the distribution of and modifications to; the work hosted by this repository.\n\n<pre>\nCopyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n      Please see Acknowledgements.pdf for additional information.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n\n   * Redistributions of source code must retain the above copyright\n     notice, this list of conditions and the following disclaimer.\n   * Redistributions in binary form must reproduce the above copyright\n     notice, this list of conditions and the following disclaimer in the\n     documentation and/or other materials provided with the distribution.\n   * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n     names of its contributors may be used to endorse or promote products\n     derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\nOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGE.\n</pre>\n"
  },
  {
    "path": "Sources/App/Build Scripts/BuildExtensions.sh",
    "content": "#!/bin/bash\n\nset -e\n\necho \"Building using architecture: ${ARCHS}\"\n\nTEXTUAL_PRODUCT_LOCATION=\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\"\nTEXTUAL_PRODUCT_BINARY=\"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\"\n\nplugins=(\n    'Caffeine'\n    'Chat Filter'\n    'Smiley Converter'\n    'System Profiler'\n    'User Insights'\n    'ZNC Additions'\n)\n\nfor plugin in \"${plugins[@]}\"; do\n    cd \"${TEXTUAL_WORKSPACE_DIR}/Sources/Plugins/${plugin}\"\n    xcodebuild -target \"$plugin Extension\" \\\n        -configuration \"${TEXTUAL_EXTENSION_BUILD_SCHEME}\" \\\n        ARCHS=\"${ARCHS}\" \\\n        CODE_SIGN_IDENTITY=\"${CODE_SIGN_IDENTITY}\" \\\n        DEVELOPMENT_TEAM=\"${DEVELOPMENT_TEAM}\" \\\n        PROVISIONING_PROFILE_SPECIFIER=\"\" \\\n        TEXTUAL_WORKSPACE_DIR=\"${TEXTUAL_WORKSPACE_DIR}\" \\\n        TEXTUAL_PRODUCT_LOCATION=\"${TEXTUAL_PRODUCT_LOCATION}\" \\\n        TEXTUAL_PRODUCT_BINARY=\"${TEXTUAL_PRODUCT_BINARY}\"\n\ndone\n\nexit 0\n"
  },
  {
    "path": "Sources/App/Build Scripts/BuildFrameworks.sh",
    "content": "#!/bin/bash\n\nset -e\n\necho \"Building using architecture: ${ARCHS}\"\n\nCONFIGURATION_BUILD_DIR=\"${TEXTUAL_WORKSPACE_TEMP_DIR}/SharedBuildProducts-Frameworks\"\n\nxcb() {\n    target=$1\n    xcodebuild -target \"$target\" \\\n        -configuration \"${TEXTUAL_FRAMEWORK_BUILD_SCHEME}\" \\\n        ARCHS=\"${ARCHS}\" \\\n        CODE_SIGN_IDENTITY=\"${CODE_SIGN_IDENTITY}\" \\\n        CONFIGURATION_BUILD_DIR=\"${CONFIGURATION_BUILD_DIR}\" \\\n        DEVELOPMENT_TEAM=\"${DEVELOPMENT_TEAM}\" \\\n        PROVISIONING_PROFILE_SPECIFIER=\"\" \\\n        DWARF_DSYM_FOLDER_PATH=\"${DWARF_DSYM_FOLDER_PATH}\"\n}\n\n# Assumes the name and filename of the framework is the same just without spaces.\nframeworks=(\n    'Auto Hyperlinks'\n    'Encryption Kit'\n    'Cocoa Extensions'\n)\n\nfor framework in \"${frameworks[@]}\"; do\n    cd \"${TEXTUAL_WORKSPACE_DIR}/Frameworks/${framework}/\"\n    xcb \"${framework// /}.framework\"\ndone\n\nexit 0\n"
  },
  {
    "path": "Sources/App/Build Scripts/BuildServices.sh",
    "content": "#!/bin/bash\n\nset -e\n\necho \"Building using architecture: ${ARCHS}\"\n\nTEXTUAL_PRODUCT_LOCATION=\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\"\nTEXTUAL_PRODUCT_BINARY=\"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\"\n\nservices=(\n    'Historic Log File Manager'\n    'Inline Content Loader'\n    'IRC Remote Connection Manager'\n)\n\nfor service in \"${services[@]}\"; do\n    cd \"${TEXTUAL_WORKSPACE_DIR}/XPC Services/${service}/\"\n\n    xcodebuild -target \"$service\" \\\n        -configuration \"${TEXTUAL_XPC_SERVICE_BUILD_SCHEME}\" \\\n        ARCHS=\"${ARCHS}\" \\\n        CODE_SIGN_IDENTITY=\"${CODE_SIGN_IDENTITY}\" \\\n        DEVELOPMENT_TEAM=\"${DEVELOPMENT_TEAM}\" \\\n        PROVISIONING_PROFILE_SPECIFIER=\"\" \\\n        TEXTUAL_WORKSPACE_DIR=\"${TEXTUAL_WORKSPACE_DIR}\" \\\n        TEXTUAL_PRODUCT_LOCATION=\"${TEXTUAL_PRODUCT_LOCATION}\" \\\n        TEXTUAL_PRODUCT_BINARY=\"${TEXTUAL_PRODUCT_BINARY}\"\ndone\n"
  },
  {
    "path": "Sources/App/Build Scripts/ExportArchive.sh",
    "content": "#!/bin/sh\n\nset -e\n\nWORKING_PATH=\"${TEXTUAL_WORKSPACE_TEMP_DIR}/ArchiveTan\"\n\nmkdir -p \"${WORKING_PATH}\"\n\ncd \"${WORKING_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nxcodebuild -exportArchive \\\n-exportOptionsPlist \"${TEXTUAL_WORKSPACE_DIR}/Configurations/ExportArchiveConfiguration.plist\" \\\n-archivePath \"${ARCHIVE_PATH}\" \\\n-exportPath \"${WORKING_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n# Zip product and send to notary\n#\n# Format to add notary to keychain:\n#\n# xcrun notarytool store-credentials \"Textual Notary\"\n#\t--apple-id \"<e-mail address>\"\n#\t--team-id <team id>\n#\t--password \"<password>\"\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWORKING_ZIP_PATH=\"./${FULL_PRODUCT_NAME}.zip\"\n\nzip -y -r -X \"${WORKING_ZIP_PATH}\" \"./${FULL_PRODUCT_NAME}/\"\n\nxcrun notarytool submit \"${WORKING_ZIP_PATH}\" \\\n                   --keychain-profile \"Textual Notary\" \\\n                   --wait \\\n                   --verbose \\\n                   --progress\n\n# Remove uploaded product\nrm \"${WORKING_ZIP_PATH}\"\n\n# Stable app\nxcrun stapler staple --verbose \"./${FULL_PRODUCT_NAME}/\" \n\n# Create new zip with stapled app\nzip -y -r -X \"${WORKING_ZIP_PATH}\" \"./${FULL_PRODUCT_NAME}/\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\n# Call `git` after `cd` into working path to make\n# sure we are in a directory of a git repository.\nGIT_COMMIT_HASH=`git rev-parse --short HEAD`\n\nEXPORT_PATH=\"${HOME}/Desktop/Textual-${GIT_COMMIT_HASH}\"\n\nmkdir -p \"${EXPORT_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\nif [ \"${TEXTUAL_BUILT_AS_UNIVERSAL_BINARY}\" == \"1\" ]; then\n\tARCHSPEC_PATH=\"${EXPORT_PATH}/universal\"\nelse\n\tARCHSPEC_PATH=\"${EXPORT_PATH}/intel\"\nfi\n\nmkdir -p \"${ARCHSPEC_PATH}\"\n\nZIP_EXPORT_PATH=\"${ARCHSPEC_PATH}/Textual.zip\"\n\nmv \"${WORKING_ZIP_PATH}\" \"${ZIP_EXPORT_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\nBUNDLE_VERSION_LONG=$(/usr/libexec/PlistBuddy -c \"Print \\\"CFBundleVersion\\\"\" \"./${FULL_PRODUCT_NAME}/Contents/Info.plist\")\nBUNDLE_VERSION_SHORT=$(/usr/libexec/PlistBuddy -c \"Print \\\"CFBundleShortVersionString\\\"\" \"./${FULL_PRODUCT_NAME}/Contents/Info.plist\")\nBUNDLE_MINIMUM_TARGET=$(/usr/libexec/PlistBuddy -c \"Print \\\"LSMinimumSystemVersion\\\"\" \"./${FULL_PRODUCT_NAME}/Contents/Info.plist\")\n\necho \"<?php\n\n\t/* Generated on: $(date) */\n\" > ./buildInfo.php\n\necho \"\t\\$current_release_version_short = \\\"${BUNDLE_VERSION_SHORT}\\\";\" >> ./buildInfo.php\necho \"\t\\$current_release_version_long = \\\"${BUNDLE_VERSION_LONG}\\\";\" >> ./buildInfo.php\necho \"\t\\$current_release_version_signature = \\\"${GIT_COMMIT_HASH}\\\";\" >> ./buildInfo.php\necho \"\t\\$current_release_minimum_system_version = \\\"${BUNDLE_MINIMUM_TARGET}\\\";\" >> buildInfo.php\n\nmv \"./buildInfo.php\" \"${EXPORT_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\necho \"<section class=\\\"main\\\">\n\t<section class=\\\"header\\\">Release Notes for ${BUNDLE_VERSION_LONG}</section>\n\n\t<section class=\\\"body\\\">\n\n\t\t<ul>\" > ./buildLog.txt\n\ngit log --since='48 hours ago' --pretty=format:'\t\t\t<li>%s</li>' >> ./buildLog.txt\n\necho \"\n\t\t</ul>\n\n\t</section>\n</section>\n\n<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->\" >> ./buildLog.txt\n\nmv \"./buildLog.txt\" \"${EXPORT_PATH}\"\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\ncd \"${DWARF_DSYM_FOLDER_PATH}\"\n\nDYSM_EXPORT_PATH=\"${ARCHSPEC_PATH}/Debug symbols.zip\"\n\nzip -y -r -X \"${DYSM_EXPORT_PATH}\" *\n\n# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #\n\nrm -rf \"${WORKING_PATH}\"\n\nexit 0;\n"
  },
  {
    "path": "Sources/App/Build Scripts/MergeSwift.sh",
    "content": "#!/bin/sh\n\nset -e\n\n#\n# Textual and Remote Connection Manager service both use Swift.\n# Textual embeds the library and the service will inherit that.\n# For some reason, during development, I found that the service\n# would not launch because \"libswiftSwiftOnoneSupport.dylib\"\n# was missing in Textual's copy of the library.\n#\n# Textual and the service both declare -Onone optimization level\n# at the same time, so I don't know why one will have it and\n# the other does not.\n#\n# To workaround this issue and any in the future, this script exists.\n# This script will find all libswift*.dylb files that aren't in the\n# main copy of the library and bring those files in.\n#\n# TODO: Revisit this when I've had sleep (June 28, 2018)\n#\n\ncd \"${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}\"\n\nfind . -type f -name \"libswift*\" \\\n -not -path \"./Frameworks/*\" \\\n -not -path \"./Resources/*\" \\\n -not -path \"*/Resources/libswiftRemoteMirror.dylib\" \\\n -exec cp '{}' ./Frameworks/ \\; \\\n -exec rm '{}' \\;\n\nexit 0;\n"
  },
  {
    "path": "Sources/App/Build Scripts/PostprocessSparkle.sh",
    "content": "#!/bin/bash\n\nset -e\n\necho \"Performing postprocessing on Sparkle framework\"\n\ncd \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\n\nrm -rf Sparkle.framework/Versions/B/XPCServices/Downloader.xpc\n\ncodesign -f -s \"$CODE_SIGN_IDENTITY\" -o runtime Sparkle.framework/Versions/B/XPCServices/Installer.xpc\n\ncodesign -f -s \"$CODE_SIGN_IDENTITY\" -o runtime Sparkle.framework/Versions/B/Autoupdate\ncodesign -f -s \"$CODE_SIGN_IDENTITY\" -o runtime Sparkle.framework/Versions/B/Updater.app\n\ncodesign -f -s \"$CODE_SIGN_IDENTITY\" -o runtime Sparkle.framework\n\nexit 0\n"
  },
  {
    "path": "Sources/App/Build Scripts/UpdateFeatureFlags.sh",
    "content": "#!/bin/bash\n\nset -e\n\ncd \"${TEXTUAL_WORKSPACE_TEMP_DIR}/Build Headers/\"\n\necho \"\n/* ANY CHANGES TO THIS FILE WILL NOT BE SAVED AND WILL NOT BE COMMITTED */\n\" > _FeatureFlags.h\n\nfeatureNames=(\"TEXTUAL_BUILT_INSIDE_SANDBOX\"\n\t\t\t\"TEXTUAL_BUILT_WITH_SPARKLE_ENABLED\"\n\t\t\t\"TEXTUAL_BUILT_WITH_LICENSE_MANAGER\"\n\t\t\t\"TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION\"\n\t\t\t\"TEXTUAL_BUILT_FOR_APP_STORE_DISTRIBUTION\"\n\t\t\t\"TEXTUAL_BUILT_AS_UNIVERSAL_BINARY\")\n\nfor feature in \"${featureNames[@]}\"; do\n\tfeatureValue=\"${!feature}\"\n\n\tif [ -n \"${featureValue}\" ]; then\n\t\techo \"#define ${feature} ${featureValue}\" >> _FeatureFlags.h\n\telse\n\t\techo \"#define ${feature} 0\" >> _FeatureFlags.h\n\tfi\ndone\n\nif cmp -s \"FeatureFlags.h\" \"_FeatureFlags.h\"; then\n\techo \"The feature flags file hasn't changed. Not deploying.\"\n\n\trm \"_FeatureFlags.h\"\nelse\n\t# Force flag is used on rm to avoid error for missing file\n\trm -f \"FeatureFlags.h\"\n\n\tmv \"_FeatureFlags.h\" \"FeatureFlags.h\"\nfi\n\n# ------ #\n\n# Exit with success\nexit 0;\n"
  },
  {
    "path": "Sources/App/Build Scripts/UpdateVersionInfo.sh",
    "content": "#!/bin/sh\n\nset -e\n\ncd \"${TEXTUAL_WORKSPACE_TEMP_DIR}/\"\n\n# Make a copy of the Info.plist file in the .tmp folder\n# This will be the Info.plist file manipulated with the version\n# information that is generated below.\n\ninfoPlistSource=\"${PROJECT_DIR}/Resources/Property Lists/Application Properties/Info.plist\"\n\ninfoPlistTarget=\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Info.plist\"\n\nif [ ! -f \"${infoPlistTarget}\" ] || [ \"${infoPlistTarget}\" -ot \"${infoPlistSource}\" ]; then\n\techo \"Step 1: Info.plist file doesn't exist and/or is oudated. Performing copy.\"\n\n\t# Copy with -p flag to preserve modification time\n\tcp -p \"${infoPlistSource}\" \"${infoPlistTarget}\"\nelse\n\techo \"Step 1: Info.plist file hasn't changed.\"\nfi\n\n# Write the version information to the Info.plist file.\n# The build version is the date of the last commit in git.\ngitBundle=`which git`\n\nif [ -z \"${gitBundle}\" ]; then\n\tbundleVersionNew=\"000000.00\"\nelse \n\tgitDateOfLastCommit=`\"${gitBundle}\" log -n1 --format=\"%at\"`\n\n\tbundleVersionNew=`/bin/date -u -r \"${gitDateOfLastCommit}\" \"+%y%m%d.%H\"`\nfi;\n\nbundleVersionOld=$(/usr/libexec/PlistBuddy -c \"Print \\\"CFBundleVersion\\\"\" Info.plist)\n\nif [ \"${bundleVersionOld}\" != \"${bundleVersionNew}\" ]; then\n\techo \"Step 2: Writing version: New ('${bundleVersionNew}'), Old ('${bundleVersionOld}')\"\n\n\t/usr/libexec/PlistBuddy -c \"Set \\\"CFBundleVersion\\\" \\\"${bundleVersionNew}\\\"\" Info.plist\nelse\n\techo \"Step 2: The version hasn't changed.\"\nfi\n\n# ------ #\n\n# Gather the information necessary for building Textual's BuildConfig.h\n# header. This header file gives various section of the code base version\n# information so it does not need to constantly access the Info.plist file.\nbundleVersionShort=$(/usr/libexec/PlistBuddy -c \"Print \\\"CFBundleShortVersionString\\\"\" Info.plist)\n\nmkdir -p \"./Build Headers\"\n\ncd \"./Build Headers\"\n\necho \"\n/* ANY CHANGES TO THIS FILE WILL NOT BE SAVED AND WILL NOT BE COMMITTED */\n\n#define TXBundleBuildProductName\t\t\t\t\t@\\\"${PRODUCT_NAME}\\\"\n#define TXBundleBuildProductIdentifier\t\t\t\t@\\\"${PRODUCT_BUNDLE_IDENTIFIER}\\\"\n#define TXBundleBuildProductIdentifierCString\t\t \\\"${PRODUCT_BUNDLE_IDENTIFIER}\\\"\n#define TXBundleBuildGroupContainerIdentifier\t\t@\\\"${TEXTUAL_GROUP_CONTAINER_IDENTIFIER}\\\"\n#define TXBundleBuildVersion\t\t\t\t\t\t@\\\"${bundleVersionNew}\\\"\n#define TXBundleBuildVersionShort\t\t\t\t\t@\\\"${bundleVersionShort}\\\"\n#define TXBundleBuildScheme\t\t\t\t\t\t\t@\\\"${TEXTUAL_BUILD_SCHEME_TOKEN}\\\"\n\" > _BuildConfig.h\n\nif [ -z \"$CODE_SIGN_IDENTITY\" ]; then\necho \"#define TXBundleBuiltWithoutCodeSigning\t\t1\" >> _BuildConfig.h\nfi\n\nif cmp -s \"BuildConfig.h\" \"_BuildConfig.h\"; then\n\techo \"Step 3: The build configuration file hasn't changed. Not deploying.\"\n\n\trm \"_BuildConfig.h\"\nelse\n\t# Force flag is used on rm to avoid error for missing file\n\trm -f \"BuildConfig.h\"\n\n\tmv \"_BuildConfig.h\" \"BuildConfig.h\"\nfi\n\n# ------ #\n\n# Compile list of enabled features\nexec \"${PROJECT_DIR}/Build Scripts/UpdateFeatureFlags.sh\" > \"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateFeatureFlags.txt\"\n\n# ------ #\n\n# Exit with success\nexit 0;\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TXAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TXApplicationAppearanceChangedNotification = @\"TXApplicationAppearanceChangedNotification\";\nNSString * const TXSystemAppearanceChangedNotification = @\"TXSystemAppearanceChangedNotification\";\n\n@interface TXAppearancePropertyCollection ()\n@property (nonatomic, copy, readwrite) NSString *appearanceName;\n@property (nonatomic, assign, readwrite) TXAppearanceType appearanceType;\n@property (nonatomic, assign, readwrite) BOOL isDarkAppearance;\n@property (nonatomic, assign, readwrite) TXAppKitAppearanceTarget appKitAppearanceTarget;\n@end\n\n@interface TXAppearance ()\n@property (nonatomic, strong, readwrite) TXAppearancePropertyCollection *properties;\n@end\n\n@implementation TXAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[self updateAppearance];\n\n\t[RZWorkspaceNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t\t\t\tselector:@selector(accessibilityDisplayOptionsDidChange:)\n\t\t\t\t\t\t\t\t\t\t\tname:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification\n\t\t\t\t\t\t\t\t\t\t  object:nil];\n\n\t[NSApp addObserver:self forKeyPath:@\"effectiveAppearance\" options:NSKeyValueObservingOptionNew context:NULL];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Removing appearance change observers\");\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\t[NSApp removeObserver:self forKeyPath:@\"effectiveAppearance\"];\n}\n\n#pragma mark -\n#pragma mark Properties\n\n+ (nullable NSString *)appearanceNameForType:(TXAppearanceType)type\n{\n\tswitch (type) {\n\t\tcase TXAppearanceTypeBigSurLight:\n\t\t{\n\t\t\treturn @\"BigSurLight\";\n\t\t}\n\t\tcase TXAppearanceTypeBigSurDark:\n\t\t{\n\t\t\treturn @\"BigSurDark\";\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn nil;\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"effectiveAppearance\"]) {\n\t\t[self applicationAppearanceChanged];\n\t}\n}\n\n- (void)applicationAppearanceChanged\n{\n\t/* Wait until next pass of the run loop to perform\n\t update because the effective appearance may not\n\t be propagated to all subviews when this is called. */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self updateAppearanceBySystemChange];\n\t});\n}\n\n- (void)systemColorsDidChange:(NSNotification *)aNote\n{\n\t[self updateAppearanceBySystemChange];\n}\n\n- (void)accessibilityDisplayOptionsDidChange:(NSNotification *)aNote\n{\n\t[self updateAppearanceBySystemChange];\n}\n\n- (void)updateAppearance\n{\n\t[self updateAppearanceBySystemChange:NO];\n}\n\n- (void)updateAppearanceBySystemChange\n{\n\t[self updateAppearanceBySystemChange:YES];\n}\n\n- (void)updateAppearanceBySystemChange:(BOOL)systemChanged\n{\n\tTXAppearanceType appearanceType = TXAppearanceTypeBigSurLight;\n\n\tTXPreferredAppearance preferredAppearance = [TPCPreferences appearance];\n\n\t/* Determine user's preference */\n\tswitch (preferredAppearance) {\n\t\tcase TXPreferredAppearanceInherited:\n\t\t{\n\t\t\tif ([TXAppearancePropertyCollection systemWideDarkModeEnabled]) {\n\t\t\t\tappearanceType = TXAppearanceTypeBigSurDark;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXPreferredAppearanceDark:\n\t\t{\n\t\t\tappearanceType = TXAppearanceTypeBigSurDark;\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tBOOL isAppearanceDark = (appearanceType == TXAppearanceTypeBigSurDark);\n\n\t/* Determine best appearance inheritance approach */\n\t/* Before Mojave, appearance needs to be applied to every view.\n\t After Mojave, views properly inherit the appearance of the parent\n\t window or the system. If the user selects a specific appearance,\n\t then we apply that to the parent window on Mojave and later to\n\t allow views to inherit that. If the user selects the system\n\t appearance, then we apply nothing and allow it to be inherited\n\t from the system. */\n\tTXAppKitAppearanceTarget appKitAppearanceTarget = TXAppKitAppearanceTargetNone;\n\n\tif (preferredAppearance != TXPreferredAppearanceInherited) {\n\t\tappKitAppearanceTarget = TXAppKitAppearanceTargetWindow;\n\t}\n\n\t/* Test for changes */\n\tTXAppearancePropertyCollection *oldProperties = self.properties;\n\n\tBOOL changeAppearance = (oldProperties == nil ||\n\t\t\t\t\t\t\t (oldProperties.appearanceType != appearanceType) ||\n\t\t\t\t\t\t\t (oldProperties.appKitAppearanceTarget != appKitAppearanceTarget));\n\n\tif (changeAppearance == NO)\n\t{\n\t\t/* Even if the desired appearance hasn't changed, we still\n\t\t signal views to perform selection update so that vibrant\n\t\t views can draw correctly when the system changes. */\n\n\t\tif (systemChanged == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\telse\n\t{\n\t\t/* When appearance changes as a result of a system change, then we\n\t\t treat it as an application change as that's more specialized. */\n\t\tsystemChanged = NO;\n\t}\n\n\t/* Assign new properties */\n\tTXAppearancePropertyCollection *newProperties = [TXAppearancePropertyCollection new];\n\n\tnewProperties.appearanceName = [self.class appearanceNameForType:appearanceType];\n\n\tnewProperties.appearanceType = appearanceType;\n\n\tnewProperties.isDarkAppearance = isAppearanceDark;\n\t\n\tnewProperties.appKitAppearanceTarget = appKitAppearanceTarget;\n\n\tself.properties = newProperties;\n\n\t/* Notify observers */\n\tif (systemChanged == NO) {\n\t\t[self notifyApplicationAppearanceChanged];\n\t} else {\n\t\t[self notifySystemAppearanceChanged];\n\t}\n}\n\n- (void)notifyApplicationAppearanceChanged\n{\n\t[RZNotificationCenter() postNotificationName:TXApplicationAppearanceChangedNotification object:self];\n}\n\n- (void)notifySystemAppearanceChanged\n{\n\t[RZNotificationCenter() postNotificationName:TXSystemAppearanceChangedNotification object:self];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Property Collection\n\n@implementation TXAppearancePropertyCollection\n\n- (nullable NSAppearance *)appKitAppearance\n{\n\tif (self.appKitAppearanceTarget == TXAppKitAppearanceTargetNone) {\n\t\treturn nil;\n\t}\n\n\tif (self.isDarkAppearance) {\n\t\treturn [self.class appKitDarkAppearance];\n\t} else {\n\t\treturn [self.class appKitLightAppearance];\n\t}\n}\n\n- (NSString *)shortAppearanceDescription\n{\n\tif (self.isDarkAppearance == NO) {\n\t\treturn @\"light\";\n\t} else {\n\t\treturn @\"dark\";\n\t}\n}\n\n+ (BOOL)systemWideDarkModeEnabled\n{\n\treturn ([[NSApp effectiveAppearance] bestMatchFromAppearancesWithNames:@[NSAppearanceNameDarkAqua]] != nil);\n}\n\n+ (nullable NSAppearance *)appKitDarkAppearance\n{\n\treturn [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];\n}\n\n+ (nullable NSAppearance *)appKitLightAppearance\n{\n\treturn [NSAppearance appearanceNamed:NSAppearanceNameAqua];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXApplication.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TXApplicationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TXApplication\n\n+ (BOOL)checkForOtherCopiesOfTextualRunning\n{\n\tpid_t ourProcessIdentifier = [[NSProcessInfo processInfo] processIdentifier];\n\n\tfor (NSRunningApplication *application in RZWorkspace().runningApplications) {\n\t\tif ([application.bundleIdentifier isEqualToString:@\"com.codeux.apps.textual\"] ||\n\t\t\t[application.bundleIdentifier isEqualToString:@\"com.codeux.apps.textual-mas\"] ||\n\t\t\t[application.bundleIdentifier isEqualToString:@\"com.codeux.irc.textual5\"])\n\t\t{\n\t\t\tif (application.processIdentifier == ourProcessIdentifier) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tBOOL continueLaunch = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[kx4-q8]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[hcb-3i]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\t\t\treturn continueLaunch;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)sendEvent:(NSEvent *)event\n{\n\tBOOL performedCustomEvent = [self performedCustomKeyboardEvent:event];\n\n\tif (performedCustomEvent) {\n\t\treturn;\n\t}\n\n\t[super sendEvent:event];\n}\n\n- (BOOL)performedCustomKeyboardEvent:(NSEvent *)event\n{\n\tif (event.type != NSEventTypeKeyDown) {\n\t\treturn NO;\n\t}\n\n\tNSWindow *keyWindow = self.keyWindow;\n\n\tif ([self sendCustomKeyboardEvent:event toObject:keyWindow]) {\n\t\treturn YES;\n\t}\n\n\tNSResponder *firstResponder = keyWindow.firstResponder;\n\n\tif ([self sendCustomKeyboardEvent:event toObject:firstResponder]) {\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (BOOL)sendCustomKeyboardEvent:(NSEvent *)event toObject:(nullable id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif ([object respondsToSelector:@selector(performedCustomKeyboardEvent:)]) {\n\t\tif ([(id)object performedCustomKeyboardEvent:event]) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXGlobalModels.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <time.h>\n\n#import \"TLOLocalization.h\"\n#import \"TXGlobalModels.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Time\n\nNSString * _Nullable TXFormattedTimestamp(NSDate *date, NSString *format)\n{\n\tNSCParameterAssert(date != nil);\n\tNSCParameterAssert(format != nil);\n\n\ttime_t global = (time_t)date.timeIntervalSince1970;\n\n\tconst size_t outputBufferSize = 256;\n\n\tchar outputBuffer[(outputBufferSize + 1)];\n\n\tstruct tm *localTime = localtime(&global);\n\n\tif (strftime(outputBuffer, outputBufferSize, format.UTF8String, localTime) == 0) {\n\t\treturn nil;\n\t}\n\n\treturn @(outputBuffer);\n}\n\nNSString * _Nullable TXHumanReadableTimeInterval(NSTimeInterval dateInterval, BOOL shortValue, NSCalendarUnit orderMatrix)\n{\n\t/* Default what we will return */\n\tif (orderMatrix == 0) {\n\t\torderMatrix = (NSCalendarUnitYear\t\t\t|\n\t\t\t\t\t   NSCalendarUnitMonth\t\t\t|\n\t\t\t\t\t   NSCalendarUnitDay\t\t\t|\n\t\t\t\t\t   NSCalendarUnitHour\t\t\t|\n\t\t\t\t\t   NSCalendarUnitMinute\t\t\t|\n\t\t\t\t\t   NSCalendarUnitSecond);\n\t}\n\n\t/* Convert calendar units to a text rep */\n\tNSMutableArray<NSNumber *> *units = [NSMutableArray arrayWithCapacity:6];\n\n\tif (orderMatrix & NSCalendarUnitYear) {\n\t\t[units addObject:@(NSCalendarUnitYear)];\n\t}\n\n\tif (orderMatrix & NSCalendarUnitMonth) {\n\t\t[units addObject:@(NSCalendarUnitMonth)];\n\t}\n\n\tif (orderMatrix & NSCalendarUnitDay) {\n\t\t[units addObject:@(NSCalendarUnitDay)];\n\t}\n\n\tif (orderMatrix & NSCalendarUnitHour) {\n\t\t[units addObject:@(NSCalendarUnitHour)];\n\t}\n\n\tif (orderMatrix & NSCalendarUnitMinute) {\n\t\t[units addObject:@(NSCalendarUnitMinute)];\n\t}\n\n\tif (orderMatrix & NSCalendarUnitSecond) {\n\t\t[units addObject:@(NSCalendarUnitSecond)];\n\t}\n\n\t/* Build compare information */\n\tNSCalendar *systemCalendar = [NSCalendar currentCalendar];\n\n\tNSDate *date1 = [NSDate date];\n\n\tNSDate *date2 = [NSDate dateWithTimeIntervalSinceNow:dateInterval];\n\n\t/* Perform comparison */\n\tNSDateComponents *breakdownInfo = [systemCalendar components:orderMatrix fromDate:date1 toDate:date2 options:0];\n\n\tif (breakdownInfo == nil) {\n\t\treturn nil;\n\t}\n\n\tNSMutableString *returnResult = nil;\n\n\tfor (NSNumber *unit in units) {\n\t\tNSInteger unitValue = [breakdownInfo valueForComponent:unit.unsignedIntegerValue];\n\n\t\t/* If results isn't zero, we show it */\n\t\tif (unitValue == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (unitValue < 0) {\n\t\t\tunitValue *= (-1);\n\t\t}\n\n\t\tNSString *languageKey = nil;\n\n\t\tif (unitValue == 1) { // plurals\n\t\t\tlanguageKey = [NSString stringWithFormat:@\"fko-64-%@\", unit];\n\t\t} else {\n\t\t\tlanguageKey = [NSString stringWithFormat:@\"eoq-pr-%@\", unit];\n\t\t}\n\n\t\t/* shortValue returns only the first time component */\n\t\tif (shortValue) {\n\t\t\treturn [NSString stringWithFormat:@\"%ld %@\", unitValue, TXTLS(languageKey)];\n\t\t}\n\n\t\tif (returnResult == nil) {\n\t\t\treturnResult = [NSMutableString string];\n\t\t}\n\n\t\tif (unit == units.lastObject) {\n\t\t\t[returnResult appendFormat:@\"%ld %@\", unitValue, TXTLS(languageKey)];\n\t\t} else {\n\t\t\t[returnResult appendFormat:@\"%ld %@, \", unitValue, TXTLS(languageKey)];\n\t\t}\n\t}\n\n\tif (returnResult.length > 0) {\n\t\treturn [returnResult copy];\n\t}\n\n\t/* Return \"0 seconds\" when there are no results. */\n\treturn [NSString stringWithFormat:@\"0 %@\", TXTLS(@\"BasicLanguage[eoq-pr-128]\")];\n}\n\nNSString * _Nullable TXFormatDateLongStyle(id dateObject, BOOL relativeOutput)\n{\n\treturn TXFormatDate(dateObject, NSDateFormatterLongStyle, NSDateFormatterLongStyle, relativeOutput);\n}\n\nNSString * _Nullable TXFormatDate(id dateObject, NSDateFormatterStyle dateStyle, NSDateFormatterStyle timeStyle, BOOL relativeOutput)\n{\n\tNSCParameterAssert(dateObject != nil);\n\n\tNSDateFormatter *dateFormatter = [NSDateFormatter new];\n\n\tdateFormatter.doesRelativeDateFormatting = relativeOutput;\n\n\tdateFormatter.lenient = YES;\n\n\tdateFormatter.dateStyle = dateStyle;\n\tdateFormatter.timeStyle = timeStyle;\n\n\tNSString *resultString = nil;\n\n\tif ([dateObject isKindOfClass:[NSString class]]) {\n\t\tresultString = [dateFormatter stringForObjectValue:dateObject];\n\t} else if ([dateObject isKindOfClass:[NSDate class]]) {\n\t\tresultString = [dateFormatter stringFromDate:dateObject];\n\t}\n\n\treturn resultString;\n}\n\nNSDateFormatter *TXSharedISOStandardDateFormatter(void)\n{\n\tstatic NSDateFormatter *_isoStandardDateFormatter = nil;\n\n\tif (_isoStandardDateFormatter == nil) {\n\t\tNSDateFormatter *dateFormatter = [NSDateFormatter new];\n\n\t\tdateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@\"en_US_POSIX\"];\n\n\t\tdateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@\"UTC\"];\n\n\t\tdateFormatter.dateFormat = @\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"; //2011-10-19T16:40:51.620Z\n\n\t\t_isoStandardDateFormatter = dateFormatter;\n\t}\n\n\treturn _isoStandardDateFormatter;\n}\n\n#pragma mark -\n#pragma mark Misc\n\nNSUInteger TXRandomNumber(u_int32_t maximum)\n{\n\treturn arc4random_uniform(maximum);\n}\n\nNSString *TXFormattedNumber(NSInteger number)\n{\n\treturn [NSNumberFormatter localizedStringFromNumber:@(number) numberStyle:NSNumberFormatterDecimalStyle];\n}\n\nNSComparator NSDefaultComparator = ^(id object1, id object2)\n{\n\treturn [object1 compare:object2];\n};\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXMasterController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BuildConfig.h\"\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"OELReachability.h\"\n#import \"TDCAlert.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOSpeechSynthesizerPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TVCLogControllerHistoricLogFilePrivate.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.h\"\n#import \"TVCLogControllerOperationQueuePrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCChannelMemberListPrivate.h\"\n#import \"IRCCommandIndexPrivate.h\"\n#import \"IRCExtrasPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"TPCApplicationInfoPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCResourceManagerPrivate.h\"\n#import \"TPCSandboxMigrationPrivate.h\"\n#import \"TPCThemeControllerPrivate.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TXWindowControllerPrivate.h\"\n#import \"TXMasterControllerPrivate.h\"\n#import \"IRCClient.h\"\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n#import <Sparkle/Sparkle.h>\n#endif\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXMasterController ()\n@property (nonatomic, strong, readwrite) IRCWorld *world;\n@property (nonatomic, assign, readwrite) BOOL debugModeIsOn;\n@property (nonatomic, assign, readwrite) BOOL ghostModeIsOn;\n@property (nonatomic, assign, readwrite) BOOL applicationIsActive;\n@property (nonatomic, assign, readwrite) BOOL applicationIsLaunched;\n@property (nonatomic, assign, readwrite) BOOL applicationIsTerminating;\n@property (nonatomic, assign, readwrite) BOOL applicationIsChangingActiveState;\n@property (readonly) BOOL isSafeToPerformApplicationTermination;\n@property (nonatomic, assign, readwrite) BOOL terminateHistoricLogSaveFinished;\n@property (nonatomic, strong, readwrite) IBOutlet TVCMainWindow *mainWindow;\n@property (nonatomic, weak, readwrite) IBOutlet TXMenuController *menuController;\n@property (nonatomic, assign) NSUInteger applicationLaunchRemainder;\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n@property (nonatomic, strong, readwrite) SPUStandardUpdaterController *updateController;\n#endif\n@end\n\n@implementation TXMasterController\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[NSObject setGlobalMasterControllerClassReference:self];\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tLogToConsoleSetDefaultSubsystemToMainBundle(@\"General\");\n\n\tNSUInteger keyboardKeys = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\tif ((keyboardKeys & NSEventModifierFlagControl) == NSEventModifierFlagControl) {\n\t\tself.debugModeIsOn = YES;\n\n\t\tLogToConsoleInfo(\"Launching in debug mode\");\n\t}\n\n#if defined(DEBUG)\n\tself.ghostModeIsOn = YES; // Do not use auto connect during debug\n#else\n\tif ((keyboardKeys & NSEventModifierFlagShift) == NSEventModifierFlagShift) {\n\t\tself.ghostModeIsOn = YES;\n\n\t\tLogToConsoleInfo(\"Launching without auto connecting to the configured servers\");\n\t}\n#endif\n}\n\n- (void)awakeFromNib\n{\n\tstatic BOOL _awakeFromNibCalled = NO;\n\n\tif (_awakeFromNibCalled == NO) {\n\t\t_awakeFromNibCalled = YES;\n\n\t\t[self _awakeFromNib];\n\t}\n}\n\n- (void)_awakeFromNib\n{\n\t/* Migrate files and preferences */\n\t[TPCSandboxMigration migrateResources];\n\n\t/* Initialize preferences */\n\t[TPCPreferences initPreferences];\n\n\t/* Call shared instance to warm it */\n\t[TXSharedApplication sharedAppearance];\n\n\t/* We wait until -awakeFromNib to wake the window so that the menu\n\t controller created by the main nib has time to load. */\n\t[RZMainBundle() loadNibNamed:@\"TVCMainWindow\" owner:self topLevelObjects:nil];\n}\n\n- (void)applicationWakeStepOne\n{\n\tself.world = [IRCWorld new];\n}\n\n- (void)applicationWakeStepTwo\n{\n\t[IRCCommandIndex populateCommandIndex];\n\n\t[self prepareNetworkReachabilityNotifier];\n\n\t[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerDidWakeUp:) name:NSWorkspaceDidWakeNotification object:nil];\n\t[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerWillSleep:) name:NSWorkspaceWillSleepNotification object:nil];\n\t[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerWillPowerOff:) name:NSWorkspaceWillPowerOffNotification object:nil];\n\t[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerScreenDidWake:) name:NSWorkspaceScreensDidWakeNotification object:nil];\n\t[RZWorkspaceNotificationCenter() addObserver:self selector:@selector(computerScreenWillSleep:) name:NSWorkspaceScreensDidSleepNotification object:nil];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(pluginsFinishedLoading:) name:THOPluginManagerFinishedLoadingPluginsNotification object:nil];\n\n\t[RZAppleEventManager() setEventHandler:self andSelector:@selector(handleURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];\n\n\t[NSColorPanel setPickerMask:(NSColorPanelRGBModeMask | NSColorPanelGrayModeMask | NSColorPanelColorListModeMask | NSColorPanelWheelModeMask | NSColorPanelCrayonModeMask)];\n\n\t[[NSColorPanel sharedColorPanel] setShowsAlpha:YES];\n\n\tXRPerformBlockAsynchronouslyOnGlobalQueueWithPriority(^{\n\t\t[TPCResourceManager copyResourcesToApplicationSupportFolder];\n\t}, DISPATCH_QUEUE_PRIORITY_BACKGROUND);\n\n\t/* We want to guarantee some specific things happen before the\n\t app is considered \"launched\" and ready to use. This property\n\t counts down once each task completes and once it reaches 0,\n\t then the app is considered launched. */\n\t/* 1 is default value because we want plugins to be loaded\n\t before we are finished launching. */\n\t[self addObserver:self forKeyPath:@\"applicationLaunchRemainder\" options:NSKeyValueObservingOptionNew context:NULL];\n\n\tself.applicationLaunchRemainder = 1;\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\t[self prepareLicenseManager];\n#endif\n\n\t[self prepareThirdPartyServices];\n\n\t/* Load plugins last so that -applicationDidFinishLaunching is posted\n\t only once they have loaded and everything else has been setup. */\n\t[sharedPluginManager() loadPlugins];\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"applicationLaunchRemainder\"]) {\n\t\tif (self.applicationLaunchRemainder == 0) {\n\t\t\t[self applicationDidFinishLaunching];\n\t\t}\n\t}\n}\n\n- (void)pluginsFinishedLoading:(NSNotification *)notification\n{\n\tself.applicationLaunchRemainder -= 1;\n}\n\n#pragma mark -\n#pragma mark Services\n\n- (void)prepareThirdPartyServiceSparkleFramework\n{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\t  SPUStandardUpdaterController *controller =\n\t[[SPUStandardUpdaterController alloc] initWithStartingUpdater:NO\n\t\t\t\t\t\t\t\t\t\t\t\t  updaterDelegate:(id <SPUUpdaterDelegate>)self\n\t\t\t\t\t\t\t\t\t\t\t   userDriverDelegate:nil];\n\n\tself.updateController = controller;\n\n\tSPUUpdater *updater = controller.updater;\n\n\tif ([updater respondsToSelector:@selector(clearFeedURLFromUserDefaults)]) {\n\t\t[updater performSelector:@selector(clearFeedURLFromUserDefaults)];\n\t} else {\n\t\t[RZUserDefaults() removeObjectForKey:@\"SUFeedURL\"];\n\t}\n\n\tNSError *error;\n\n\t(void)[updater startUpdater:&error];\n\n\tif (error) {\n\t\tLogToConsoleError(\"Sparkle failed to start updater: %{public}@\", error.description);\n\t}\n#endif\n}\n\n- (void)prepareThirdPartyServices\n{\n\t[self prepareThirdPartyServiceSparkleFramework];\n}\n\n- (void)prepareNetworkReachabilityNotifier\n{\n\tOELReachability *notifier = [TXSharedApplication sharedNetworkReachabilityNotifier];\n\n\tnotifier.reachableBlock = ^(OELReachability *reachability) {\n\t\t[self.world noteReachabilityChanged:YES];\n\t};\n\n\tnotifier.unreachableBlock = ^(OELReachability *reachability) {\n\t\t[self.world noteReachabilityChanged:NO];\n\t};\n\n\t[notifier startNotifier];\n}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)prepareLicenseManager\n{\n\tTLOLicenseManagerSetup();\n\n\t[[TXSharedApplication sharedLicenseManagerDialog] applicationDidFinishLaunching];\n}\n#endif\n\n#pragma mark -\n#pragma mark NSApplication Delegate\n\n- (void)applicationWillFinishLaunching:(NSNotification *)notification\n{\n\t/* UserNotifications.framework wants delegation set before app has\n\t finished launching. A simple access to the singleton will set this\n\t for us which we can just do here. */\n\tLogToConsoleDebug(\"Preparing notification controller singeton: %@\",\n\t\t\tsharedNotificationController().description);\n}\n\n- (void)applicationDidFinishLaunching\n{\n\t[self removeObserver:self forKeyPath:@\"applicationLaunchRemainder\"];\n\n\tself.applicationIsLaunched = YES;\n\n\tif ([self.mainWindow reloadLoadingScreen]) {\n\t\t[self.world autoConnectAfterWakeup:NO];\n\t}\n\n\t[self.mainWindow maybeToggleFullscreenAfterLaunch];\n}\n\n- (void)applicationWillResignActive:(NSNotification *)notification\n{\n\tself.applicationIsChangingActiveState = YES;\n}\n\n- (void)applicationWillBecomeActive:(NSNotification *)notification\n{\n\tself.applicationIsChangingActiveState = YES;\n}\n\n- (void)applicationDidResignActive:(NSNotification *)notification\n{\n\tself.applicationIsActive = NO;\n\tself.applicationIsChangingActiveState = NO;\n}\n\n- (void)applicationDidBecomeActive:(NSNotification *)notification\n{\n\tself.applicationIsActive = YES;\n\tself.applicationIsChangingActiveState = NO;\n}\n\n- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag\n{\n\tif (self.applicationIsTerminating) {\n\t\treturn NO;\n\t}\n\n\t[self.mainWindow makeKeyAndOrderFront:nil];\n\n\treturn YES;\n}\n\n- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender\n{\n\tif (self.applicationIsTerminating) {\n\t\treturn NO;\n\t}\n\n\t[self.mainWindow makeKeyAndOrderFront:nil];\n\n\treturn YES;\n}\n\n- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)sender\n{\n\t/* This will have no effect on our app. Implement to suppress warning in console. */\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark NSApplication Terminate Procedure\n\n- (NSMenu *)applicationDockMenu:(NSApplication *)sender\n{\n\treturn self.menuController.dockMenu;\n}\n\n- (BOOL)queryTerminate\n{\n\tif (self.applicationIsTerminating) {\n\t\tLogToConsoleTerminationProgress(\"Termination is already in progress\");\n\n\t\treturn YES;\n\t}\n\n\tif ([TPCPreferences confirmQuit] == NO) {\n\t\treturn YES;\n\t}\n\n\tBOOL stillConnected = NO;\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tif (u.isConnecting || u.isConnected) {\n\t\t\tstillConnected = YES;\n\t\t}\n\t}\n\n\tif (stillConnected) {\n\t\tBOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[77u-vp]\")\n\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[6vj-2p]\")\n\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[1bf-k0]\")\n\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[qso-2g]\")];\n\n\t\tLogToConsoleTerminationProgress(\"Perform termination: %{BOOL}d\", result);\n\n\t\treturn result;\n\t}\n\n\treturn YES;\n}\n\n- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender\n{\n\tif ([self queryTerminate] == NO) {\n\t\treturn NSTerminateCancel;\n\t}\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self performApplicationTerminationStepOne];\n\t});\n\n\treturn NSTerminateLater;\n}\n\n- (BOOL)isSafeToPerformApplicationTermination\n{\n\t/* Clients are still disconnecting */\n\tBOOL condition1 = (self.terminatingClientCount == 0);\n\n\t/* Core Data is saving */\n\tBOOL condition2 = (TVCLogControllerHistoricLogSharedInstance().isSaving == NO &&\n\t\t\t\t\t\t\tself.terminateHistoricLogSaveFinished);\n\n\n\tLogToConsoleTerminationProgress(\"Conditions: %{BOOL}d %{BOOL}d\", condition1, condition2);\n\n\treturn (condition1 && condition2);\n}\n\n- (void)performApplicationTerminationStepOne\n{\n\tLogToConsoleTerminationProgress(\"Step one entry\");\n\n\tself.applicationIsTerminating = YES;\n\n\t[[TXSharedApplication sharedAppearance] prepareForApplicationTermination];\n\n\t[self.mainWindow prepareForApplicationTermination];\n\n\tLogToConsoleTerminationProgress(\"Giving up shared application delegation\");\n\n\t[[NSApplication sharedApplication] setDelegate:nil];\n\n\tLogToConsoleTerminationProgress(\"Removing workspace notification center observer\");\n\n\t[RZWorkspaceNotificationCenter() removeObserver:self];\n\n\tLogToConsoleTerminationProgress(\"Removing shared notification center observer\");\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\tLogToConsoleTerminationProgress(\"Removing AppleScript event observer\");\n\n\t[RZAppleEventManager() removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];\n\n\tLogToConsoleTerminationProgress(\"Stopping reachability notifier\");\n\n\t[[TXSharedApplication sharedNetworkReachabilityNotifier] stopNotifier];\n\n\tLogToConsoleTerminationProgress(\"Stopping speech synthesizer\");\n\n\t[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:YES];\n\n\t[TVCLogControllerInlineMediaSharedInstance() prepareForApplicationTermination];\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t[sharedEncryptionManager() prepareForApplicationTermination];\n#endif\n\n\t[self.menuController prepareForApplicationTermination];\n\n\t[self performApplicationTerminationStepTwo];\n}\n\n- (void)performApplicationTerminationStepTwo\n{\n\tif (self.applicationIsTerminating == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleTerminationProgress(\"Step two entry\");\n\n\tself.terminatingClientCount = worldController().clientCount;\n\n\t[self.world prepareForApplicationTermination];\n\n\tif (self.isSafeToPerformApplicationTermination) {\n\t\t[self performApplicationTerminationStepThree];\n\n\t\treturn;\n\t}\n\n\t/* We want certain things to 100% happen before the app completely closes.\n\t This block that is performed below loops until all these actions are completed.\n\t Notable actions: gracefully leaving IRC, saving historic logs, etc. */\n\tXRPerformBlockAsynchronouslyOnGlobalQueueWithPriority(^{\n\t\tdo {\n\t\t\t/* We wait until this value reaches zero so that\n\t\t\t view controllers had the chance to perform any\n\t\t\t changes they want to historic log. */\n\t\t\tif (self.terminatingClientCount == 0) {\n\t\t\t\t[TVCLogControllerHistoricLogSharedInstance() prepareForApplicationTermination];\n\n\t\t\t\tself.terminateHistoricLogSaveFinished = YES;\n\t\t\t}\n\n\t\t\t/* Sleep a little bit so we aren't looping a lot. */\n\t\t\t[NSThread sleepForTimeInterval:0.5];\n\t\t} while (self.isSafeToPerformApplicationTermination == NO);\n\n\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t[self performApplicationTerminationStepThree];\n\t\t});\n\t}, DISPATCH_QUEUE_PRIORITY_HIGH);\n}\n\n- (void)performApplicationTerminationStepThree\n{\n\tif (self.applicationIsTerminating == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleTerminationProgress(\"Step three entry\");\n\n\tif (self.skipTerminateSave == NO) {\n\t\tLogToConsoleTerminationProgress(\"Saving IRC world\");\n\n\t\t[self.world save];\n\t}\n\n\tLogToConsoleTerminationProgress(\"Suspending member list dispatch queue\");\n\n\t[IRCChannelMemberList suspendMemberListSerialQueues];\n\n\tLogToConsoleTerminationProgress(\"Unloading plugins\");\n\n\t[sharedPluginManager() unloadPlugins];\n\n\t[windowController() prepareForApplicationTermination];\n\n\t[themeController() prepareForApplicationTermination];\n\n\tLogToConsoleTerminationProgress(\"Saving running internal\");\n\n\t[TPCApplicationInfo saveTimeIntervalSinceApplicationInstall];\n\n\tLogToConsoleTerminationProgress(\"Terminate\");\n\n\t[NSApp replyToApplicationShouldTerminate:YES];\n}\n\n- (void)terminateGracefully\n{\n\tself.applicationIsTerminating = YES;\n\n\t[RZSharedApplication() terminate:nil];\n}\n\n#pragma mark -\n#pragma mark NSWorkspace Notifications\n\n- (void)handleURLEvent:(NSAppleEventDescriptor *)event\n\t\twithReplyEvent:(NSAppleEventDescriptor *)replyEvent\n{\n\tNSAppleEventDescriptor *description = [event descriptorAtIndex:1];\n\n\tNSString *stringValue = description.stringValue;\n\n\t[IRCExtras parseIRCProtocolURI:stringValue withDescriptor:event];\n}\n\n- (void)computerScreenWillSleep:(NSNotification *)note\n{\n\tLogToConsole(\"Preparing for screen sleep\");\n\n\t[self.world prepareForScreenSleep];\n}\n\n- (void)computerScreenDidWake:(NSNotification *)note\n{\n\tLogToConsole(\"Waking from screen sleep\");\n\n\t[self.world wakeFromScreenSleep];\n}\n\n- (void)computerWillSleep:(NSNotification *)note\n{\n\tLogToConsole(\"Preparing for sleep\");\n\n\t[self.world prepareForSleep];\n\n\t[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:YES];\n\t[[TXSharedApplication sharedSpeechSynthesizer] clearQueue];\n\n\t[[TXSharedApplication sharedNetworkReachabilityNotifier] stopNotifier];\n}\n\n- (void)computerDidWakeUp:(NSNotification *)note\n{\n\tLogToConsole(\"Waking from sleep\");\n\n\t[[TXSharedApplication sharedSpeechSynthesizer] setIsStopped:NO];\n\n\t[[TXSharedApplication sharedNetworkReachabilityNotifier] startNotifier];\n\n\t[self.world autoConnectAfterWakeup:YES];\n}\n\n- (void)computerWillPowerOff:(NSNotification *)note\n{\n\t[self terminateGracefully];\n}\n\n#pragma mark -\n#pragma mark Sparkle Delegate\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n- (void)updaterWillRelaunchApplication:(SPUUpdater *)updater\n{\n\tself.applicationIsTerminating = YES;\n}\n\n- (NSSet<NSString *> *)allowedChannelsForUpdater:(SPUUpdater *)updater\n{\n\tBOOL receiveBetaUpdates = [TPCPreferences receiveBetaUpdates];\n\n\tif (receiveBetaUpdates) {\n\t\treturn [NSSet setWithObject:@\"beta\"];\n\t}\n\n\treturn [NSSet set];\n}\n#endif\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXMenuController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCChannelMode.h\"\n#import \"IRCChannelUser.h\"\n#import \"IRCExtrasPrivate.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCUser.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogViewInternalWK2.h\"\n#import \"TVCMemberList.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowSplitView.h\"\n#import \"TVCMainWindowTextView.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TDCAboutDialogPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelInviteSheetPrivate.h\"\n#import \"TDCChannelModifyModesSheetPrivate.h\"\n#import \"TDCChannelModifyTopicSheetPrivate.h\"\n#import \"TDCChannelPropertiesSheetPrivate.h\"\n#import \"TDCChannelSpotlightControllerPrivate.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n#import \"TDCInputPrompt.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TDCNicknameColorSheetPrivate.h\"\n#import \"TDCPreferencesControllerPrivate.h\"\n#import \"TDCServerChangeNicknameSheetPrivate.h\"\n#import \"TDCServerHighlightListSheetPrivate.h\"\n#import \"TDCServerPropertiesSheetPrivate.h\"\n#import \"TDCWelcomeSheetPrivate.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesImportExport.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesReload.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TXMasterControllerPrivate.h\"\n#import \"TXWindowControllerPrivate.h\"\n#import \"TXMenuControllerPrivate.h\"\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n#import <Sparkle/Sparkle.h>\n#endif\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define\t_popWindowViewIfExists(c)\tif ([windowController() maybeBringWindowForward:(c)]) {\t\t\\\n\t\t\t\t\t\t\t\t\t\treturn;\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t}\n\n@interface TXMenuController () <NSMenuItemValidation>\n@property (nonatomic, assign) BOOL menuIsOpen;\n@property (nonatomic, assign) BOOL menuPerformedActionLastOpen;\n@property (nonatomic, weak) IRCClient *pointedClient;\n@property (nonatomic, weak) IRCChannel *pointedChannel;\n@property (nonatomic, copy) NSString *currentSearchPhrase;\n@property (readonly, nullable) TVCLogController *selectedViewController;\n@property (readonly, nullable) TVCLogView *selectedViewControllerBackingView;\n@property (readonly) TDCFileTransferDialog *fileTransferController;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewChannelNameMenu;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewGeneralMenu;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *channelViewURLMenu;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *dockMenu;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *encryptionManagerStatusMenu;\n#endif\n\n@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuNavigationChannelListMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuChannelMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenu *mainMenuQueryMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuChannelMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuQueryMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuServerMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *mainMenuWindowMenuItem;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *mainWindowSegmentedControllerCellMenu;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *serverListNoSelectionMenu;\n@property (nonatomic, strong, readwrite) IBOutlet NSMenu *userControlMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsDockMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsFileMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsSoundsDockMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *muteNotificationsSoundsFileMenuItem;\n@end\n\n@implementation TXMenuController\n\n- (void)prepareInitialState\n{\n\tself.currentSearchPhrase = @\"\";\n\n\tif ([TPCPreferences soundIsMuted]) {\n\t\tself.muteNotificationsSoundsDockMenuItem.state = NSControlStateValueOn;\n\t\tself.muteNotificationsSoundsFileMenuItem.state = NSControlStateValueOn;\n\t}\n\n\t[self.channelViewGeneralMenu itemWithTag:MTWKGeneralChannelMenu].submenu = [self.mainMenuChannelMenu copy];\n\n\t[self setupOtherServices];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(menuItemWillPerformedAction:) name:NSMenuWillSendActionNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(menuItemPerformedAction:) name:NSMenuDidSendActionNotification object:nil];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(mainWindowSelectionChanged:) name:TVCMainWindowSelectionChangedNotification object:nil];\n}\n\n- (void)setupOtherServices\n{\n\t[self.fileTransferController startUsingDownloadDestinationURL];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing menu controller\");\n\n\t[self.fileTransferController prepareForApplicationTermination];\n}\n\n- (void)preferencesChanged\n{\n\t[self.fileTransferController clearIPAddress];\n}\n\n- (void)mainWindowSelectionChanged:(NSNotification *)notification\n{\n\tif (self.menuIsOpen == NO) {\n\t\t[self resetSelectedItems];\n\t}\n\n\t/* When the selection changes, menus that may be dynamic are force\n\t revalidated so that Command I (or other shortcuts) work with channel\n\t selected, but not for the server console. */\n\tNSMenuItem *channelMenu = self.mainMenuChannelMenuItem;\n\n\t[self _forceMenuItemValidation:channelMenu];\n\n\tNSMenuItem *queryMenu = self.mainMenuQueryMenuItem;\n\n\t[self _forceMenuItemValidation:queryMenu];\n}\n\n- (void)_forceMenuValidation:(NSMenu *)menu\n{\n\tNSParameterAssert(menu != nil);\n\n\tfor (NSMenuItem *menuItem in menu.itemArray) {\n\t\t[self _forceMenuItemValidation:menuItem];\n\t}\n}\n\n- (void)_forceMenuItemValidation:(NSMenuItem *)menuItem\n{\n\tNSParameterAssert(menuItem != nil);\n\n\tid target = menuItem.target;\n\n\tif (target == nil) {\n\t\treturn;\n\t}\n\n\tif ([target respondsToSelector:@selector(validateMenuItem:)]) {\n\t\t[target performSelector:@selector(validateMenuItem:) withObject:menuItem];\n\t}\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem\n{\n\tNSParameterAssert(menuItem != nil);\n\n\tif (masterController().applicationIsTerminating) {\n\t\treturn NO;\n\t}\n\n\t/* Menu validation works in two passes:\n\t\t 1. First -_validateMenuItem: is called which performs validation for\n\t\t    the individual menu item including hiding it and related items.\n\t\t 2. The result is then passed to the logic below which performs more\n\t\t    specialized work such as disabling large group of menu items when\n\t\t    the trial has expired.\n\t */\n\tBOOL validationResult = [self _validateMenuItem:menuItem];\n\n\tif (validationResult == NO) {\n\t\treturn NO;\n\t}\n\n\tNSUInteger tag = menuItem.tag;\n\n\t/* The submenus of the main menu are all targets of the menu\n\t controller so that we can chose to hide or show some depending\n\t on context. For the top most submenus, we have nothing further\n\t to do after performing initial validation. */\n\tswitch (tag) {\n\t\tcase MTMainMenuApp:\n\t\tcase MTMainMenuFile:\n\t\tcase MTMainMenuEdit:\n\t\tcase MTMainMenuView:\n\t\tcase MTMainMenuServer:\n\t\tcase MTMainMenuChannel:\n\t\tcase MTMainMenuQuery:\n\t\tcase MTMainMenuNavigate:\n\t\tcase MTMainMenuWindow:\n\t\tcase MTMainMenuHelp:\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t} // switch\n\n\t/* When the main window is not the focused window or when we are\n\t in a sheet, most items can be disabled which means at this point\n\t we will default to disabled and allow the bottom logic to enable\n\t only the bare essentials. */\n\tBOOL defaultToNoForSheet = ( mainWindow().attachedSheet != nil ||\n\t\t\t\t\t\t\t\t(mainWindow().mainWindow == NO &&\n\t\t\t\t\t\t\t\t mainWindow().isBeneathMouse == NO));\n\n\tif (defaultToNoForSheet) {\n\t\tvalidationResult = NO;\n\t}\n\n\t/* If the app has not finished launching,\n\t then default everything to disabled. */\n\tif (masterController().applicationIsLaunched == NO) {\n\t\tvalidationResult = NO;\n\t}\n\n\t/* If trial is expired, then default everything to disabled. */\n\tBOOL isTrialExpired = NO;\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\tif (TLOLicenseManagerTextualIsRegistered() == NO && TLOLicenseManagerIsTrialExpired()) {\n\t\t/* Set flag letting logic know trial expired */\n\t\tisTrialExpired = YES;\n\n\t\t/* Disable everything by default except \"Manage license…\" */\n\t\tvalidationResult = (tag == MTMMAppManageLicense);\n\t} // if\n#endif\n\n\t/* If certain items are hidden because of sheet but not because\n\t of the trial being expired, then enable additional items. */\n\tif (validationResult == NO && defaultToNoForSheet && isTrialExpired == NO) {\n\t\tswitch (tag) {\n\t\t\tcase MTMMAppAboutApp: // \"About Textual\"\n\t\t\tcase MTMMAppPreferences: // \"Preferences…\"\n\t\t\tcase MTMMAppManageLicense: // \"Manage license…\"\n\t\t\tcase MTMMAppCheckForUpdates: // \"Check for updates…\"\n\t\t\tcase MTMMHelpAdvancedMenuEnableDeveloperMode: // \"Enable Developer Mode\"\n\t\t\tcase MTMMHelpAdvancedMenuHiddenPreferences: // \"Hidden Preferences…\"\n\t\t\tcase MTMMFileDisableAllNotifications: // \"Disable All Notifications\"\n\t\t\tcase MTMMFileDisableAllNotificationSounds: // \"Disable All Notification Sounds\"\n\t\t\tcase MTDockMenuDisableAllNotifications: // \"Disable All Notifications\"\n\t\t\tcase MTDockMenuDisableAllNotificationSounds: // \"Disable All Notification Sounds\"\n\t\t\t{\n\t\t\t\tvalidationResult = YES;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // switch\n\t} // if\n\n\t/* These are the bare minimum of menu items that must be enabled\n\t at all times because they are essential to the entire application. */\n\t/* This list may look incomplete but it isn't. Many menu items,\n\t such as Undo, Cut, Copy, Quit, etc. are not a target of the menu\n\t controller which means they never pass through this logic. */\n\tif (validationResult == NO) {\n\t\tswitch (tag) {\n\t\t\tcase MTMMAppAboutApp: // \"About Textual\"\n\t\t\tcase MTMMAppQuitApp: // \"Quit Textual & IRC\"\n\t\t\tcase MTMMFilePrint: // \"Print\"\n\t\t\tcase MTMMFileCloseWindow: // \"Close Window\"\n\t\t\tcase MTMMEditPaste: // \"Paste\"\n\t\t\tcase MTMMViewToggleFullscreen: // \"Toggle Fullscreen\"\n\t\t\tcase MTMMWindowMainWindow: // \"Main Window\"\n\t\t\tcase MTMMHelpAcknowledgements: // \"Acknowledgements\"\n\t\t\tcase MTMMHelpLicenseAgreement: // \"License Agreement\"\n\t\t\tcase MTMMHelpPrivacyPolicy: // \"Privacy Policy\"\n\t\t\tcase MTMMHelpFrequentlyAskedQuestions: // \"Frequently Asked Questions\"\n\t\t\tcase MTMMHelpKnowledgeBaseMenu: // \"Knowledge Base\"\n\t\t\tcase MTMMHelpAdvancedMenu: // \"Advanced\"\n\t\t\tcase MTMMHelpAdvancedMenuExportPreferences: // \"Export Preferences\"\n\t\t\t{\n\t\t\t\tvalidationResult = YES;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tif (menuItem.parentItem.tag == MTMMHelpKnowledgeBaseMenu) {\n\t\t\t\t\tvalidationResult = YES;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // switch\n\t} // if\n\n\treturn validationResult;\n}\n\n- (BOOL)_validateMenuItem:(NSMenuItem *)menuItem\n{\n\tNSParameterAssert(menuItem != nil);\n\n\tNSUInteger tag = menuItem.tag;\n\n\tIRCClient *u = mainWindow().selectedClient;\n\tIRCChannel *c = mainWindow().selectedChannel;\n\n\tswitch (tag) {\n\t\tcase MTMainMenuChannel: // \"Channel\"\n\t\t{\n\t\t\tBOOL isChannel = c.isChannel;\n\n\t\t\tmenuItem.hidden = (isChannel == NO);\n\n\t\t\tif (isChannel) {\n\t\t\t\tmenuItem.submenu = self.mainMenuChannelMenu;\n\t\t\t} else {\n\t\t\t\tmenuItem.submenu = nil;\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMainMenuQuery: // \"Query\"\n\t\t{\n\t\t\tBOOL isQuery = (c.isPrivateMessage || c.isUtility);\n\n\t\t\tmenuItem.hidden = (isQuery == NO);\n\n\t\t\tif (isQuery) {\n\t\t\t\tmenuItem.submenu = self.mainMenuQueryMenu;\n\t\t\t} else {\n\t\t\t\tmenuItem.submenu = nil;\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\n\t\tcase MTMMAppManageLicense: // \"Manage license…\"\n\t\t{\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 0\n\t\t\tmenuItem.hidden = YES;\n#endif\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMMAppCheckForUpdates: // \"Check for Updates\"\n\t\t{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 0\n\t\t\tmenuItem.hidden = YES;\n#endif\n\n\t\t\treturn YES;\n\t\t}\n\n\t\tcase MTMMFileCloseWindow: // \"Close Window\"\n\t\t{\n\t\t\tTXCommandWKeyAction keyAction = [TPCPreferences commandWKeyAction];\n\n\t\t\tif (keyAction == TXCommandWKeyActionCloseWindow || mainWindow().keyWindow == NO) {\n\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[1f6-bg]\");\n\n\t\t\t\treturn YES;\n\t\t\t}\n\n\t\t\tif (u == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tswitch (keyAction) {\n\t\t\t\tcase TXCommandWKeyActionPartChannel:\n\t\t\t\t{\n\t\t\t\t\tif (c == nil) {\n\t\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[1f6-bg]\");\n\n\t\t\t\t\t\treturn NO;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (c.isChannel) {\n\t\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[5td-3f]\");\n\n\t\t\t\t\t\tif (c.isActive == NO) {\n\t\t\t\t\t\t\treturn NO;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (c.isPrivateMessage) {\n\t\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[hri-l0]\");\n\t\t\t\t\t} else if (c.isUtility) {\n\t\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[hri-l0]\");\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase TXCommandWKeyActionDisconnect:\n\t\t\t\t{\n\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[w3a-je]\", u.networkNameAlt);\n\n\t\t\t\t\tif (u.isConnecting == NO && u.isConnected == NO) {\n\t\t\t\t\t\treturn NO;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase TXCommandWKeyActionTerminate:\n\t\t\t\t{\n\t\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[x97-ro]\");\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\n\t\tcase MTMMEditPaste: // \"Paste\"\n\t\tcase MTWKGeneralPaste: // \"Paste\" (WebView)\n\t\t{\n\t\t\tNSString *currentPasteboard = RZPasteboard().stringContent;\n\n\t\t\tif (currentPasteboard.length == 0) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tif (mainWindow().keyWindow) {\n\t\t\t\treturn mainWindowTextField().editable;\n\t\t\t}\n\n\t\t\tid firstResponder = [NSApp keyWindow].firstResponder;\n\n\t\t\tif ([firstResponder respondsToSelector:@selector(isEditable)]) {\n\t\t\t\treturn [firstResponder isEditable];\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\n\t\tcase MTMMViewMarkScrollback: // \"Mark Scrollback\"\n\t\tcase MTMMViewScrollbackMarker: // \"Scrollback Marker\"\n\t\tcase MTMMViewMarkAllAsRead: // \"Mark All as Read\"\n\t\tcase MTMMViewClearScrollback: // \"Clear Scrollback\"\n\t\tcase MTMMViewIncreaseFontSize: // \"Increase Font Size\"\n\t\tcase MTMMViewDecreaseFontSize: // \"Decrease Font Size\"\n\t\tcase MTMMNavigationJumpToCurrentSession: // \"Jump to Current Session\"\n\t\tcase MTMMNavigationJumpToPresent: // \"Jump to Present\"\n\t\t{\n\t\t\treturn (self.selectedViewController != nil);\n\t\t}\n\t\tcase MTMMViewToggleFullscreen:\n\t\t{\n\t\t\tNSWindowCollectionBehavior collectionBehavior = [NSApp keyWindow].collectionBehavior;\n\n\t\t\treturn ((collectionBehavior & NSWindowCollectionBehaviorFullScreenAuxiliary) == NSWindowCollectionBehaviorFullScreenAuxiliary ||\n\t\t\t\t\t(collectionBehavior & NSWindowCollectionBehaviorFullScreenPrimary) == NSWindowCollectionBehaviorFullScreenPrimary);\n\t\t}\n\n\t\tcase MTMMServerConnect: // \"Connect\"\n\t\t{\n\t\t\tif (u == nil) {\n\t\t\t\tmenuItem.hidden = NO;\n\t\t\t\t\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tBOOL connected = (u.isConnected || u.isConnecting);\n\t\t\t\n\t\t\tmenuItem.hidden = connected;\n\n\t\t\treturn (connected == NO && u.isQuitting == NO);\n\t\t}\n\t\tcase MTMMServerConnectWithoutProxy: // \"Connect Without Proxy\"\n\t\t{\n\t\t\tNSUInteger flags = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\t\t\tif (flags != NSEventModifierFlagShift) {\n\t\t\t\tmenuItem.hidden = YES;\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tif (u == nil) {\n\t\t\t\tmenuItem.hidden = YES;\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tBOOL condition = (u.isConnected || u.isConnecting ||\n\t\t\t\t\tu.config.proxyType == IRCConnectionProxyTypeNone);\n\n\t\t\tmenuItem.hidden = condition;\n\n\t\t\treturn (condition == NO && u.isQuitting == NO);\n\t\t}\n\t\tcase MTMMServerDisconnect: // \"Disconnect\"\n\t\t{\n\t\t\tBOOL connected = (u.isConnected || u.isConnecting);\n\t\t\t\n\t\t\tmenuItem.hidden = (connected == NO);\n\t\t\t\n\t\t\treturn connected;\n\t\t}\n\t\tcase MTMMServerCancelReconnect: // \"Cancel Reconnect\"\n\t\t{\n\t\t\tBOOL reconnecting = u.isReconnecting;\n\t\t\t\n\t\t\tmenuItem.hidden = (reconnecting == NO);\n\t\t\t\n\t\t\treturn reconnecting;\n\t\t}\n\t\tcase MTMMServerChannelList: // \"Channel List…\"\n\t\t{\n\t\t\treturn u.isLoggedIn;\n\t\t}\n\t\tcase MTMMServerChangeNickname: // \"Change Nickname…\"\n\t\tcase MTWKGeneralChangeNickname: // \"Change Nickname…\"\n\t\t{\n\t\t\treturn u.isConnected;\n\t\t}\n\t\tcase MTMMServerDuplicateServer: // \"Duplicate Server\"\n\t\tcase MTMMServerAddChannel: // \"Add Channel…\"\n\t\tcase MTMMServerServerProperties: // \"Server Properties…\"\n\t\t{\n\t\t\treturn (u != nil);\n\t\t}\n\t\tcase MTMMServerDeleteServer: // \"Delete Server…\"\n\t\t{\n\t\t\treturn (u && u.isConnecting == NO && u.isConnected == NO);\n\t\t}\n\n\t\tcase MTMMNavigationNextHighlight: // \"Next Highlight\"\n\t\tcase MTMMNavigationPreviousHighlight: // \"Previous Highlight\"\n\t\t{\n\t\t\tTVCLogController *viewController = self.selectedViewController;\n\n\t\t\tif (viewController == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\treturn [viewController highlightAvailable:(tag == MTMMNavigationPreviousHighlight)];\n\t\t}\n\n\t\tcase MTMMChannelJoinChannel: // \"Join Channel\"\n\t\t{\n\t\t\tmenuItem.hidden = (u.isLoggedIn == NO || c.isActive);\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMMChannelLeaveChannel: // \"Leave Channel\"\n\t\t{\n\t\t\tmenuItem.hidden = (u.isLoggedIn == NO || c.isActive == NO);\n\n\t\t\tNSMenuItem *joinChannel = [menuItem.menu itemWithTag:MTMMChannelJoinChannel];\n\n\t\t\t[menuItem.menu itemWithTag:MTMMChannelLeaveChannelSeparator].hidden = (menuItem.hidden && joinChannel.hidden);\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMMChannelAddChannel: // \"Add Channel…\"\n\t\t{\n\t\t\treturn (u != nil);\n\t\t}\n\t\tcase MTMMChannelViewLogs: // \"View Logs\"\n\t\t{\n\t\t\treturn [TPCPreferences logToDiskIsEnabled];\n\t\t}\n\t\tcase MTMMChannelModifyTopic: // \"Modify Topic\"\n\t\tcase MTMMChannelModesMenu: // \"Modes\"\n\t\tcase MTMMChannelListOfBans: // \"List of Bans\"\n\t\t{\n\t\t\treturn (u.isLoggedIn && c.isActive);\n\t\t}\n\t\tcase MTMMChannelListOfBanExceptions: // \"List of Ban Exceptions\"\n\t\t{\n\t\t\tmenuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeBanException] == NO);\n\n\t\t\treturn (u.isLoggedIn && c.isActive);\n\t\t}\n\t\tcase MTMMChannelListOfInviteExceptions: // \"List of Invite Exceptions\"\n\t\t{\n\t\t\tmenuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeInviteException] == NO);\n\n\t\t\treturn (u.isLoggedIn && c.isActive);\n\t\t}\n\t\tcase MTMMChannelListOfQuiets: // \"List of Quiets\"\n\t\t{\n\t\t\tmenuItem.hidden = ([u.supportInfo isListSupported:IRCISupportInfoListTypeQuiet] == NO);\n\n\t\t\treturn (u.isLoggedIn && c.isActive);\n\t\t}\n\n\t\tcase MTMMQueryQueryLogs: // \"Query Logs\"\n\t\t{\n\t\t\t/* Query menu is used for utility windows too so we\n\t\t\t hide \"Query Logs\" for anything except private messages. */\n\t\t\tBOOL isQuery = c.isPrivateMessage;\n\n\t\t\tmenuItem.hidden = (isQuery == NO);\n\n\t\t\t[menuItem.menu itemWithTag:MTMMQueryCloseQuerySeparator].hidden = (isQuery == NO);\n\n\t\t\treturn [TPCPreferences logToDiskIsEnabled];\n\t\t}\n\n\t\tcase MTMMWindowToggleVisibilityOfServerList: // \"Toggle Visibility of Server List\"\n\t\tcase MTMMWindowSortChannelList: // \"Sort Channel List\"\n\t\tcase MTMMWindowCenterWindow: // \"Center Window\"\n\t\tcase MTMMWindowResetWindowToDefaultSize: // \"Reset Window to Default Size\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\n\t\t\tmenuItem.hidden = (isMainWindowMain == NO);\n\n\t\t\tif (tag == MTMMWindowSortChannelList) {\n\t\t\t\t[menuItem.menu itemWithTag:MTMMWindowSortChannelListSeparator].hidden = (isMainWindowMain == NO);\n\t\t\t} else if (tag == MTMMWindowResetWindowToDefaultSize) {\n\t\t\t\t[menuItem.menu itemWithTag:MTMMWindowResetWindowToDefaultSizeSeparator].hidden = (isMainWindowMain == NO);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMMWindowMainWindow: // \"Main Window\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\t\t\tBOOL isMainWindowDisabled = mainWindow().disabled;\n\n\t\t\tmenuItem.hidden = isMainWindowMain;\n\n\t\t\treturn (isMainWindowDisabled == NO);\n\t\t}\n\t\tcase MTMMWindowToggleVisibilityOfMemberList: // \"Toggle Visibility of Member List\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\n\t\t\tmenuItem.hidden = (isMainWindowMain == NO);\n\n\t\t\treturn c.isChannel;\n\t\t}\n\t\tcase MTMMWindowToggleWindowAppearance: // \"Toggle Window Appearance\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\n\t\t\tmenuItem.hidden = (isMainWindowMain == NO);\n\n\t\t\t[menuItem.menu itemWithTag:MTMMWindowToggleWindowAppearanceSeparator].hidden = (isMainWindowMain == NO);\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTMMWindowAddressBook: // \"Address Book\"\n\t\tcase MTMMWindowIgnoreList: // \"Ignore List\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\n\t\t\tmenuItem.hidden = (isMainWindowMain == NO);\n\n\t\t\treturn (u != nil);\n\t\t}\n\t\tcase MTMMWindowViewLogs: // \"View Logs\"\n\t\t{\n\t\t\treturn [TPCPreferences logToDiskIsEnabled];\n\t\t}\n\t\tcase MTMMWindowHighlightList: // \"Highlight List\"\n\t\t{\n\t\t\tBOOL isMainWindowMain = mainWindow().mainWindow;\n\n\t\t\tmenuItem.hidden = (isMainWindowMain == NO);\n\n\t\t\tif (u == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\treturn [TPCPreferences logHighlights];\n\t\t}\n\n\t\tcase MTUserControlsAddIgnore: // \"Add Ignore\"\n\t\t{\n\t\t\t/* To make it as efficient as possible, we only check for ignore\n\t\t\t for the \"Add Ignore\" menu item. When that menu item is validated,\n\t\t\t we validate \"Modify Ignore\" and \"Remove Ignore\" at the same time. */\n\t\t\tNSMenuItem *modifyIgnoreMenuItem = [menuItem.menu itemWithTag:MTUserControlsModifyIgnore];\n\t\t\tNSMenuItem *removeIgnoreMenuItem = [menuItem.menu itemWithTag:MTUserControlsRemoveIgnore];\n\n\t\t\tif (c.isUtility) {\n\t\t\t\tmodifyIgnoreMenuItem.hidden = YES;\n\n\t\t\t\tremoveIgnoreMenuItem.hidden = YES;\n\n\t\t\t\tmenuItem.hidden = NO;\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\t/* If less than or more than one user is selected, then hide all\n\t\t\t menu items except \"Add Ignore\" and disable the \"Add Ignore\" item. */\n\t\t\tNSArray<IRCChannelUser *> *nicknames = [self selectedMembers:menuItem];\n\n\t\t\tNSString *hostmask = nicknames.firstObject.user.hostmask;\n\n\t\t\tif (nicknames.count != 1 || hostmask == nil) {\n\t\t\t\tmodifyIgnoreMenuItem.hidden = YES;\n\n\t\t\t\tremoveIgnoreMenuItem.hidden = YES;\n\n\t\t\t\tmenuItem.hidden = NO;\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\t/* Update visibility depending on whether ignore is available */\n\t\t\t/* When this logic was first introduced, we kept a reference to\n\t\t\t the ignores in the represented object of the menu item.\n\t\t\t This was stopped because information about the ignore can\n\t\t\t change while the menu item is still open, making the object\n\t\t\t we will reference when action is performed garbage. */\n\t\t\tNSArray *userIgnores = [u findIgnoresForHostmask:hostmask];\n\n\t\t\tBOOL condition = (userIgnores.count == 0);\n\n\t\t\tmodifyIgnoreMenuItem.hidden = condition;\n\n\t\t\tremoveIgnoreMenuItem.hidden = condition;\n\n\t\t\tmenuItem.hidden = (condition == NO);\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTUserControlsModifyIgnore: // \"Modify Ignore\"\n\t\tcase MTUserControlsRemoveIgnore: // \"Remove Ignore\"\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTUserControlsInviteTo: // \"Invite To…\"\n\t\t{\n\t\t\tif (u.isLoggedIn == NO || c.isUtility) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tNSUInteger channelCount = 0;\n\n\t\t\tfor (IRCChannel *e in u.channelList) {\n\t\t\t\tif (c != e && e.isChannel) {\n\t\t\t\t\tchannelCount++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn (channelCount > 0);\n\t\t}\n\t\tcase MTUserControlsGetInfo: // \"Get Info (Whois)\"\n\t\tcase MTUserControlsClientToClientMenu: // \"Client-to-Client\"\n\t\t{\n\t\t\treturn (u.isLoggedIn && c.isUtility == NO);\n\t\t}\n\t\tcase MTUserControlsPrivateMessage: // \"Private Message (Query)\"\n\t\t{\n\t\t\tmenuItem.hidden = (c.isChannel == NO);\n\n\t\t\treturn (u.isLoggedIn && c.isUtility == NO);\n\t\t}\n\t\tcase MTUserControlsGiveOp: // \"Give Op (+o)\"\n\t\tcase MTUserControlsGiveHalfop: // \"Give Halfop (+h)\"\n\t\tcase MTUserControlsGiveVoice: // \"Give Voice (+v)\"\n\t\tcase MTUserControlsTakeOp: // \"Take Op (-o)\"\n\t\tcase MTUserControlsTakeHalfop: // \"Take Halfop (-h)\"\n\t\tcase MTUserControlsTakeVoice: // \"Take Voice (-v)\"\n\t\t{\n\t\t\treturn (u.isLoggedIn && c.isActive);\n\t\t}\n\t\tcase MTUserControlsAllModesGiven: // \"All Modes Given\"\n\t\t{\n\t\t\treturn NO;\n\t\t}\n\t\tcase MTUserControlsAllModesTaken: // \"All Modes Taken\"\n\t\t{\n#define _setHidden(tag, value)\t\t[menuItem.menu itemWithTag:(tag)].hidden = (value)\n\n\t\t\tif (c.isChannel == NO) {\n\t\t\t\t_setHidden(MTUserControlsGiveOp, YES);\n\t\t\t\t_setHidden(MTUserControlsGiveHalfop, YES);\n\t\t\t\t_setHidden(MTUserControlsGiveVoice, YES);\n\t\t\t\t_setHidden(MTUserControlsTakeOp, YES);\n\t\t\t\t_setHidden(MTUserControlsTakeHalfop, YES);\n\t\t\t\t_setHidden(MTUserControlsTakeVoice, YES);\n\n\t\t\t\t_setHidden(MTUserControlsAllModesGiven, YES);\n\t\t\t\t_setHidden(MTUserControlsAllModesGivenSeparator, YES);\n\t\t\t\t_setHidden(MTUserControlsAllModesTaken, YES);\n\t\t\t\t_setHidden(MTUserControlsAllModesTakenSeparator, YES);\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\t_setHidden(MTUserControlsAllModesGivenSeparator, NO);\n\t\t\t_setHidden(MTUserControlsAllModesTakenSeparator, NO);\n\n\t\t\tNSArray *nicknames = [self selectedMembers:menuItem];\n\n\t\t\tif (nicknames.count == 1)\n\t\t\t{\n\t\t\t\tIRCChannelUser *user = nicknames[0];\n\n\t\t\t\tIRCUserRank userRanks = user.ranks;\n\n\t\t\t\tBOOL UserHasModeO = ((userRanks & IRCUserRankNormalOperator) == IRCUserRankNormalOperator);\n\t\t\t\tBOOL UserHasModeH = NO;\n\t\t\t\tBOOL UserHasModeV = ((userRanks & IRCUserRankVoiced) == IRCUserRankVoiced);\n\n\t\t\t\t_setHidden(MTUserControlsGiveOp, UserHasModeO);\n\t\t\t\t_setHidden(MTUserControlsGiveVoice, UserHasModeV);\n\t\t\t\t_setHidden(MTUserControlsTakeOp, (UserHasModeO == NO));\n\t\t\t\t_setHidden(MTUserControlsTakeVoice, (UserHasModeV == NO));\n\n\t\t\t\tBOOL halfOpModeSupported = [u.supportInfo modeSymbolIsUserPrefix:@\"h\"];\n\n\t\t\t\tif (halfOpModeSupported == NO) {\n\t\t\t\t\t_setHidden(MTUserControlsGiveHalfop, YES);\n\t\t\t\t\t_setHidden(MTUserControlsTakeHalfop, YES);\n\t\t\t\t} else {\n\t\t\t\t\tUserHasModeH = ((userRanks & IRCUserRankHalfOperator) == IRCUserRankHalfOperator);\n\n\t\t\t\t\t_setHidden(MTUserControlsGiveHalfop, UserHasModeH);\n\t\t\t\t\t_setHidden(MTUserControlsTakeHalfop, (UserHasModeH == NO));\n\t\t\t\t}\n\n\t\t\t\tBOOL hideGiveSepItem = ((UserHasModeO == NO || UserHasModeV == NO) || (UserHasModeH == NO && halfOpModeSupported));\n\n\t\t\t\t_setHidden(MTUserControlsAllModesGiven, hideGiveSepItem);\n\n\t\t\t\tBOOL hideTakenSepItem = (UserHasModeO || UserHasModeH || UserHasModeV);\n\n\t\t\t\t_setHidden(MTUserControlsAllModesTaken, hideTakenSepItem);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t_setHidden(MTUserControlsGiveOp, NO);\n\t\t\t\t_setHidden(MTUserControlsGiveHalfop, NO);\n\t\t\t\t_setHidden(MTUserControlsGiveVoice, NO);\n\t\t\t\t_setHidden(MTUserControlsTakeOp, NO);\n\t\t\t\t_setHidden(MTUserControlsTakeHalfop, NO);\n\t\t\t\t_setHidden(MTUserControlsTakeVoice, NO);\n\n\t\t\t\t_setHidden(MTUserControlsAllModesGiven, YES);\n\t\t\t\t_setHidden(MTUserControlsAllModesTaken, YES);\n\t\t\t}\n\n\t\t\treturn NO;\n\n#undef _setHidden\n\t\t}\n\t\tcase MTUserControlsBan: // \"Ban\"\n\t\tcase MTUserControlsKick: // \"Kick\"\n\t\tcase MTUserControlsBanAndKick: // \"Ban and Kick\"\n\t\t{\n\t\t\tBOOL isChannel = c.isChannel;\n\n\t\t\tmenuItem.hidden = (isChannel == NO);\n\n\t\t\t[menuItem.menu itemWithTag:MTUserControlsBanAndKickSeparator].hidden = (isChannel == NO);\n\n\t\t\treturn (u.isLoggedIn && isChannel && c.isActive);\n\t\t}\n\t\tcase MTUserControlsIRCOperatorMenu: // \"IRC Operator\"\n\t\t{\n\t\t\tmenuItem.hidden = (u.userIsIRCop == NO);\n\n\t\t\treturn (u.isLoggedIn && c.isUtility == NO);\n\t\t}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t\tcase MTOTRStatusButtonStartPrivateConversation:\n\t\tcase MTOTRStatusButtonRefreshPrivateConversation:\n\t\tcase MTOTRStatusButtonEndPrivateConversation:\n\t\tcase MTOTRStatusButtonAuthenticateChatPartner:\n\t\tcase MTOTRStatusButtonViewListOfFingerprints:\n\t\t{\n\t\t\t/* Even if we are not logged in, we still ask the encryption manager\n\t\t\t to validate the menu item first so that it can hide specific menu items.\n\t\t\t After it has done that, then we can disable if not logged in. */\n\t\t\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tif (u.isLoggedIn == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tBOOL valid = [sharedEncryptionManager()\n\t\t\t\t\t\t  validateMenuItem:menuItem\n\t\t\t\t\t\t  withStateOf:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t  from:[u encryptionAccountNameForLocalUser]];\n\n\t\t\treturn valid;\n\t\t}\n#endif\n\n\t\tcase MTWKGeneralSearchWithGoogle: // \"Search With Google\"\n\t\t{\n\t\t\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\t\t\tif (webView == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tNSString *searchProviderName = [self searchProviderName];\n\n\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[1ll-h9]\", searchProviderName);\n\n\t\t\treturn webView.hasSelection;\n\t\t}\n\t\tcase MTWKGeneralLookUpInDictionary: // \"Look Up in Dictionary\"\n\t\t{\n\t\t\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\t\t\tif (webView == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tNSString *selection = webView.selection;\n\n\t\t\tNSUInteger selectionLength = selection.length;\n\n\t\t\tif (selectionLength == 0 || selectionLength > 40) {\n\t\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[o5l-4s]\");\n\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tif (selectionLength > 25) {\n\t\t\t\tselection = [selection substringToIndex:24];\n\n\t\t\t\tselection = [NSString stringWithFormat:@\"%@…\", selection.trim];\n\t\t\t}\n\n\t\t\tmenuItem.title = TXTLS(@\"BasicLanguage[zxs-yy]\", selection);\n\n\t\t\treturn (selectionLength > 0);\n\t\t}\n\t\tcase MTWKGeneralCopy: // \"Copy\" (WebView)\n\t\t{\n\t\t\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\t\t\tif (webView == nil) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\treturn webView.hasSelection;\n\t\t}\n\t\tcase MTWKGeneralQueryLogs: // \"Query Logs\" (WebKit)\n\t\t{\n\t\t\tmenuItem.hidden = (c.isPrivateMessage == NO);\n\n\t\t\treturn [TPCPreferences logToDiskIsEnabled];\n\t\t}\n\t\tcase MTWKGeneralChannelMenu: // \"Channel\" (WebKit)\n\t\t{\n\t\t\tmenuItem.hidden = (c.isChannel == NO);\n\n\t\t\t/* \"Query Logs\" will appear above this menu item,\n\t\t\t but if this is neither channel or query, then we\n\t\t\t have to hide the separator above that so it's not\n\t\t\t just sitting there with nothing beneath it. */\n\t\t\tNSMenuItem *queryLogs = [menuItem.menu itemWithTag:MTWKGeneralQueryLogs];\n\n\t\t\t[menuItem.menu itemWithTag:MTWKGeneralPasteSeparator].hidden = (menuItem.hidden && queryLogs.hidden);\n\n\t\t\treturn YES;\n\t\t}\n\n\t\tcase MTMMHelpAdvancedMenuEnableDeveloperMode: // Developer Mode\n\t\t{\n\t\t\tif ([TPCPreferences developerModeEnabled]) {\n\t\t\t\tmenuItem.state = NSControlStateValueOn;\n\t\t\t} else {\n\t\t\t\tmenuItem.state = NSControlStateValueOff;\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\n\t\tcase MTMainWindowSegmentedControllerAddChannel: // \"Add Channel…\"\n\t\t{\n\t\t\treturn (u != nil);\n\t\t}\n\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)menuWillOpen:(NSMenu *)menu\n{\n\tself.menuIsOpen = YES;\n\n\tself.pointedClient = mainWindow().selectedClient;\n\tself.pointedChannel = mainWindow().selectedChannel;\n\n\tself.menuPerformedActionLastOpen = NO;\n}\n\n- (void)menuDidClose:(NSMenu *)menu\n{\n\tself.menuIsOpen = NO;\n\n\t/* This delegate callback is received before -menuItemPerformedAction:\n\t is called. So that our selected items can be reset if the user did \n\t not perform an action, we call -menuClosedTimer the next time the \n\t main queue comes around. The action is performed on the current pass\n\t which means this prevents a race. */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _menuClosedTimer];\n\t});\n}\n\n- (void)_menuClosedTimer\n{\n\tif (self.menuPerformedActionLastOpen) {\n\t\treturn;\n\t}\n\n\t[self resetSelectedItems];\n}\n\n- (void)menuItemWillPerformedAction:(NSNotification *)aNote\n{\n\tNSMenuItem *menuItem = aNote.userInfo[@\"MenuItem\"];\n\n\tif (menuItem.target != self) {\n\t\treturn;\n\t}\n\n\tself.menuPerformedActionLastOpen = YES;\n}\n\n- (void)menuItemPerformedAction:(NSNotification *)aNote\n{\n\tNSMenuItem *menuItem = aNote.userInfo[@\"MenuItem\"];\n\n\tif (menuItem.target != self) {\n\t\treturn;\n\t}\n\n\t[self resetSelectedItems];\n}\n\n#pragma mark -\n#pragma mark Selection\n\n- (void)resetSelectedItems\n{\n\tself.pointedClient = nil;\n\tself.pointedChannel = nil;\n}\n\n- (nullable IRCClient *)selectedClient\n{\n\tIRCClient *pointedClient = self.pointedClient;\n\n\tif (pointedClient) {\n\t\treturn pointedClient;\n\t}\n\n\treturn mainWindow().selectedClient;\n}\n\n- (nullable IRCChannel *)selectedChannel\n{\n\tIRCChannel *pointedChannel = self.pointedChannel;\n\n\tif (pointedChannel) {\n\t\treturn pointedChannel;\n\t}\n\n\treturn mainWindow().selectedChannel;\n}\n\n- (nullable TVCLogController *)selectedViewController\n{\n\tIRCChannel *selectedChannel = self.selectedChannel;\n\n\tif (selectedChannel) {\n\t\treturn selectedChannel.viewController;\n\t}\n\n\treturn self.selectedClient.viewController;\n}\n\n- (nullable TVCLogView *)selectedViewControllerBackingView\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\treturn viewController.backingView;\n}\n\n#pragma mark -\n#pragma mark Selected User(s)\n\n- (BOOL)checkSelectedMembers:(id)sender\n{\n\treturn ([self selectedMembers:sender].count > 0);\n}\n\n- (NSArray<IRCChannelUser *> *)selectedMembers:(id)sender\n{\n\treturn [self selectedMembers:sender returnStrings:NO];\n}\n\n- (NSArray<NSString *> *)selectedMembersNicknames:(id)sender\n{\n\treturn [self selectedMembers:sender returnStrings:YES];\n}\n\n- (NSArray *)selectedMembers:(id)sender returnStrings:(BOOL)returnStrings\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isActive == NO) {\n\t\treturn @[];\n\t}\n\n\t/* Return a specific nickname for WebView events */\n\tNSString *pointedNickname = nil;\n\n\tif ([sender isKindOfClass:[NSMenuItem class]]) {\n\t\tpointedNickname = ((NSMenuItem *)sender).userInfo;\n\t} else {\n\t\tpointedNickname = self.pointedNickname;\n\t}\n\n\tif (pointedNickname) {\n\t\tif (returnStrings) {\n\t\t\treturn @[pointedNickname];\n\t\t}\n\n\t\tIRCChannelUser *user = [c findMember:pointedNickname];\n\n\t\tif (user) {\n\t\t\treturn @[user];\n\t\t}\n\n\t\treturn @[];\n\t}\n\n\t/* If we did not have a specific nickname, then query\n\t the user list for selected rows. */\n\tNSMutableArray *userArray = [NSMutableArray array];\n\n\tNSIndexSet *selectedRows = mainWindowMemberList().selectedRowIndexes;\n\n\t[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\tIRCChannelUser *user = [mainWindowMemberList() itemAtRow:index];\n\n\t\tif (returnStrings) {\n\t\t\t[userArray addObject:user.user.nickname];\n\t\t} else {\n\t\t\t[userArray addObject:user];\n\t\t}\n\t}];\n\n\treturn [userArray copy];\n}\n\n- (void)deselectMembers:(id)sender\n{\n\tif ([sender isKindOfClass:[NSMenuItem class]]) {\n\t\tif (((NSMenuItem *)sender).userInfo.length > 0) {\n\t\t\treturn; // Nothing to deselect when our sender used userInfo\n\t\t}\n\t}\n\n\tif (self.pointedNickname) {\n\t\tself.pointedNickname = nil;\n\n\t\treturn;\n\t}\n\n\t[mainWindowMemberList() deselectAll:sender];\n}\n\n#pragma mark -\n#pragma mark Find Panel\n\n- (void)_showFindPromptOpenDialog:(id)sender\n{\n\tvoid (^promptCompletionBlock)(NSString *) = ^(NSString *resultString)\n\t{\n\t\tif ([self.currentSearchPhrase isEqualToString:resultString]) {\n\t\t\treturn;\n\t\t}\n\n\t\tself.currentSearchPhrase = resultString;\n\n\t\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\t\t[webView findString:resultString movingForward:YES];\n\t};\n\n\tNSString *resultString = nil;\n\n\tTVCAlertResponseButton response =\n\t[TDCInputPrompt promptWithMessage:TXTLS(@\"Prompts[d2w-4o]\")\n\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[akr-eh]\")\n\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[q5h-xx]\")\n\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t\tprefillString:self.currentSearchPhrase\n\t\t\t\t\t\t resultString:&resultString];\n\n\tif (response == TVCAlertResponseButtonFirst) {\n\t\tpromptCompletionBlock(resultString);\n\t}\n}\n\n- (void)showFindPrompt:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tif (mainWindow().keyWindow == NO) {\n\t\treturn;\n\t}\n\n\tif ([sender tag] == MTMMEditFindMenuFind || self.currentSearchPhrase.length == 0) {\n\t\t[self _showFindPromptOpenDialog:sender];\n\n\t\treturn;\n\t}\n\n\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\tif ([sender tag] == MTMMEditFindMenuFindNext) {\n\t\t[webView findString:self.currentSearchPhrase movingForward:YES];\n\t} else {\n\t\t[webView findString:self.currentSearchPhrase movingForward:NO];\n\t}\n}\n\n\n#pragma mark -\n#pragma mark Edit\n\n- (void)copy:(id)sender\n{\n\tid firstResponder = [NSApp keyWindow].firstResponder;\n\n\tif ([firstResponder respondsToSelector:@selector(copy:)]) {\n\t\t[firstResponder performSelector:@selector(copy:) withObject:sender];\n\t}\n}\n\n- (void)paste:(id)sender\n{\n\tif (mainWindow().keyWindow) {\n\t\t[mainWindowTextField() focus];\n\n\t\t[mainWindowTextField() paste:sender];\n\n\t\treturn;\n\t}\n\n\tid firstResponder = [NSApp keyWindow].firstResponder;\n\n\tif ([firstResponder respondsToSelector:@selector(paste:)]) {\n\t\t[firstResponder performSelector:@selector(paste:) withObject:sender];\n\t}\n}\n\n- (void)print:(id)sender\n{\n\tif (mainWindow().keyWindow) {\n\t\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\t\tif (webView == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[webView print];\n\n\t\treturn;\n\t}\n\n\tid firstResponder = [NSApp keyWindow].firstResponder;\n\n\tif ([firstResponder respondsToSelector:@selector(print:)]) {\n\t\t[firstResponder performSelector:@selector(print:) withObject:sender];\n\t}\n}\n\n#pragma mark -\n#pragma mark Backing View\n\n- (void)copyLogAsHtml:(id)sender\n{\n\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\tif (webView == nil) {\n\t\treturn;\n\t}\n\n\t[webView copyContentString];\n}\n\n- (void)openWebInspector:(id)sender\n{\n\t/*\n\t When WebKit2 first announced, there was no way for an\n\t app to take an NSMenu, modify it, and return the result\n\t when a context menu is presented.\n\n\t WebKit1 had a delegate method for that named:\n\t -webView:contextMenuItemsForElement:defaultMenuItems:\n\n\t WebKit2 added this delegate method, in private, but it\n\t was not available until the next update of macOS.\n\n\t 'Til then, we had to fake \"Inspect Element\" because we\n\t did not have access to the default implementation that\n\t is available through the delegate method.\n\n\t Apple now flags the function names that were used to do that.\n\n\t This will break \"Inspect Element\" on one version of macOS.\n\t Which one I don't even recall.\n\t But it is worth it to make the review process smoother.\n\n\t Sorry.\n*/\n\n\t(void)\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[kig-m1]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[ujw-64]\")\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t   alternateButton:nil];\n}\n\n- (void)markScrollback:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController mark];\n}\n\n- (void)gotoScrollbackMarker:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController goToMark];\n}\n\n- (void)clearScrollback:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tif (c) {\n\t\t[mainWindow() clearContentsOfChannel:c];\n\t} else {\n\t\t[mainWindow() clearContentsOfClient:u];\n\t}\n}\n\n- (void)increaseLogFontSize:(id)sender\n{\n\t[mainWindow() changeTextSize:YES];\n}\n\n- (void)decreaseLogFontSize:(id)sender\n{\n\t[mainWindow() changeTextSize:NO];\n}\n\n- (NSString *)searchProviderName\n{\n\tNSDictionary *preferredWebServices =\n\t[[NSUserDefaults standardUserDefaults] dictionaryForKey:@\"NSPreferredWebServices\"];\n\n\tNSDictionary *defaultSearchProvider = [preferredWebServices dictionaryForKey:@\"NSWebServicesProviderWebSearch\"];\n\n\tNSString *searchProviderName = [defaultSearchProvider stringForKey:@\"NSDefaultDisplayName\"];\n\n\tif (searchProviderName == nil) {\n\t\treturn @\"Google\";\n\t}\n\n\treturn searchProviderName;\n}\n\n- (void)searchGoogle:(id)sender\n{\n\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\tif (webView == nil) {\n\t\treturn;\n\t}\n\n\tNSString *selection = webView.selection;\n\n\tif (selection.length == 0) {\n\t\treturn;\n\t}\n\n\tNSPasteboard *searchPasteboard = [NSPasteboard pasteboardWithUniqueName];\n\n\tsearchPasteboard.stringContent = selection;\n\n\tNSPerformService(@\"Search With %WebSearchProvider@\", searchPasteboard);\n}\n\n- (void)lookUpInDictionary:(id)sender\n{\n\tTVCLogView *webView = self.selectedViewControllerBackingView;\n\n\tif (webView == nil) {\n\t\treturn;\n\t}\n\n\tNSString *selection = webView.selection;\n\n\tif (selection.length == 0) {\n\t\treturn;\n\t}\n\n\tNSString *urlString = [NSString stringWithFormat:@\"dict://%@\", selection.percentEncodedString];\n\n\t[TLOpenLink openWithString:urlString];\n}\n\n#pragma mark -\n#pragma mark Server\n\n- (void)connect:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isConnecting || u.isConnected || u.isQuitting) {\n\t\treturn;\n\t}\n\n\t[u connect];\n\n\t[mainWindow() expandClient:u];\n}\n\n- (void)connectBypassingProxy:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isConnecting || u.isConnected || u.isQuitting) {\n\t\treturn;\n\t}\n\n\t[u connect:IRCClientConnectModeNormal bypassProxy:YES];\n\n\t[mainWindow() expandClient:u];\n}\n\n- (void)disconnect:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || (u.isConnecting == NO && u.isConnected == NO) || u.isQuitting) {\n\t\treturn;\n\t}\n\n\t[u quit];\n}\n\n- (void)cancelReconnection:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\t[u cancelReconnect];\n}\n\n- (void)showServerChannelList:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\t[u createChannelListDialog];\n\n\t[u requestChannelList];\n}\n\n- (void)addServer:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tTDCServerPropertiesSheet *sheet =\n\t[[TDCServerPropertiesSheet alloc] initWithClient:nil];\n\n\tsheet.delegate = self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet startWithSelection:TDCServerPropertiesSheetSelectionDefault context:nil];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)duplicateServer:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tIRCClientConfigMutable *config = [u.config uniqueCopyMutable];\n\n\tconfig.connectionName = [config.connectionName stringByAppendingString:@\"_\"];\n\n\tIRCClient *newClient = [worldController() createClientWithConfig:config reload:YES];\n\n\tif (newClient.config.sidebarItemExpanded) { // Only expand new client if old was expanded already.\n\t\t[mainWindow() expandClient:newClient];\n\t}\n\n\t[worldController() save];\n}\n\n- (void)deleteServer:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isConnecting || u.isConnected) {\n\t\treturn;\n\t}\n\n\tBOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[etl-ss]\")\n\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[0kz-wd]\")\n\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\tif (result == NO) {\n\t\treturn;\n\t}\n\n\t[worldController() destroyClient:u];\n\n\t[worldController() save];\n}\n\n#pragma mark -\n#pragma mark Channel\n\n- (void)joinChannel:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO || c.isActive) {\n\t\treturn;\n\t}\n\n\t[u joinChannel:c];\n\n\t[mainWindow() select:c];\n}\n\n- (void)leaveChannel:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\t/* Second boxed in condition is because this is used for queries too */\n\tif (u == nil || c == nil || (c.isChannel && (u.isLoggedIn == NO || c.isActive == NO))) {\n\t\treturn;\n\t}\n\n\tif (c.isChannel) {\n\t\t[u partChannel:c];\n\n\t\treturn;\n\t}\n\n\t[worldController() destroyChannel:c];\n}\n\n- (void)addChannel:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tTDCChannelPropertiesSheet *sheet =\n\t[[TDCChannelPropertiesSheet alloc] initWithClient:u];\n\n\tsheet.delegate = self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)deleteChannel:(id)sender\n{\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (c == nil) {\n\t\treturn;\n\t}\n\n\tif (c.isChannel) {\n\t\tBOOL result = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[516-ms]\")\n\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[i8o-7z]\")\n\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")\n\t\t\t\t\t\t\t\t\t   suppressionKey:@\"delete_channel\"\n\t\t\t\t\t\t\t\t\t  suppressionText:nil];\n\n\t\tif (result == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t[worldController() destroyChannel:c];\n\n\t[worldController() save];\n}\n\n- (void)copyUniqueIdentifier:(id)sender\n{\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (c == nil) {\n\t\treturn;\n\t}\n\n\t[RZPasteboard() setStringContent:c.uniqueIdentifier];\n}\n\n#pragma mark -\n#pragma mark Other Actions\n\n- (void)copyUrl:(id)sender\n{\n\tNSString *pointedUrl = ((NSMenuItem *)sender).userInfo;\n\n\tif (pointedUrl.length == 0) {\n\t\treturn;\n\t}\n\n\tRZPasteboard().stringContent = pointedUrl;\n}\n\n- (void)joinChannelClicked:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tNSString *pointedChannelName = nil;\n\n\tif ([sender isKindOfClass:[NSMenuItem class]]) {\n\t\tpointedChannelName = ((NSMenuItem *)sender).userInfo;\n\t} else if ([sender isKindOfClass:[NSString class]]) {\n\t\tpointedChannelName = sender;\n\t} else {\n\t\treturn;\n\t}\n\n\tif ([u stringIsChannelName:pointedChannelName] == NO) {\n\t\treturn;\n\t}\n\n\tIRCChannel *c = [u findChannelOrCreate:pointedChannelName];\n\n\t[u joinChannel:c];\n\n\t[mainWindow() select:c];\n}\n\n- (void)emptyAction:(id)sender\n{\n\t/* Empty action used to validate submenus */\n}\n\n#pragma mark -\n#pragma mark Ignores\n\n- (void)memberAddIgnore:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tNSString *command = [NSString stringWithFormat:@\"ignore %@\", nicknames[0]];\n\n\t[u sendCommand:command completeTarget:YES target:c.name];\n}\n\n- (void)memberRemoveIgnore:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tNSString *command = [NSString stringWithFormat:@\"unignore %@\", nicknames[0]];\n\n\t[u sendCommand:command completeTarget:YES target:c.name];\n}\n\n- (void)memberModifyIgnore:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tNSArray<IRCChannelUser *> *nicknames = [self selectedMembers:sender];\n\n\t[self deselectMembers:sender];\n\n\t/* User's hostmask and other information can change between the point\n\t the menu item is opened and the point the action is performed.\n\t We therefore perform a new query for ignores when performing action. */\n\tNSString *hostmask = nicknames.firstObject.user.hostmask;\n\n\tif (nicknames.count != 1 || hostmask == nil) {\n\t\treturn;\n\t}\n\n\tNSArray *userIgnores = [u findIgnoresForHostmask:hostmask];\n\n\t/* If we have more than one user ignore, then open\n\t the address book instead of a specific ignore. */\n\tif (userIgnores.count == 1) {\n\t\t[self showServerPropertiesSheetForClient:u\n\t\t\t\t\t\t\t\t   withSelection:TDCServerPropertiesSheetSelectionNewIgnoreEntry\n\t\t\t\t\t\t\t\t\t\t context:userIgnores[0]];\n\t} else {\n\t\t[self showServerPropertiesSheetForClient:u\n\t\t\t\t\t\t\t\t   withSelection:TDCServerPropertiesSheetSelectionAddressBook\n\t\t\t\t\t\t\t\t\t\t context:nil];\n\t}\n}\n\n#pragma mark -\n#pragma mark Members\n\n- (void)memberInMemberListDoubleClicked:(id)sender\n{\n\tNSInteger rowBeneathMouse = mainWindowMemberList().rowBeneathMouse;\n\n\tif (rowBeneathMouse < 0) {\n\t\treturn;\n\t}\n\n\tTXUserDoubleClickAction action = [TPCPreferences userDoubleClickOption];\n\n\tif (action == TXUserDoubleClickActionWhois) {\n\t\t[self whoisSelectedMembers:sender];\n\t} else if (action == TXUserDoubleClickActionPrivateMessage) {\n\t\t[self memberStartPrivateMessage:sender];\n\t} else if (action == TXUserDoubleClickActionInsertTextField) {\n\t\t[self memberInsertNameIntoTextField:sender];\n\t}\n}\n\n- (void)memberInChannelViewDoubleClicked:(id)sender\n{\n\tTXUserDoubleClickAction action = [TPCPreferences userDoubleClickOption];\n\n\tif (action == TXUserDoubleClickActionWhois) {\n\t\t[self whoisSelectedMembers:sender];\n\t} else if (action == TXUserDoubleClickActionPrivateMessage) {\n\t\t[self memberStartPrivateMessage:sender];\n\t} else if (action == TXUserDoubleClickActionInsertTextField) {\n\t\t[self memberInsertNameIntoTextField:sender];\n\t}\n}\n\n- (void)memberInsertNameIntoTextField:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tTVCMainWindowTextView *textView = mainWindowTextField();\n\n\tNSRange selectedRange = textView.selectedRange;\n\n\tNSMutableString *stringToInsert = [NSMutableString string];\n\n\tif (selectedRange.location > 0) {\n\t\tUniChar previousCharacter = [textView.stringValue characterAtIndex:(selectedRange.location - 1)];\n\n\t\tif ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:previousCharacter] == NO) {\n\t\t\t[stringToInsert appendString:@\" \"];\n\t\t}\n\t}\n\n\tNSString *nicknamesString = [nicknames componentsJoinedByString:@\", \"];\n\n\t[stringToInsert appendString:nicknamesString];\n\n\tNSString *completionSuffix = [TPCPreferences tabCompletionSuffix];\n\n\tif (completionSuffix != nil) {\n\t\t[stringToInsert appendString:completionSuffix];\n\t}\n\n\t[textView replaceCharactersInRange:selectedRange withString:stringToInsert];\n\n\t[textView resetFontColorInRange:selectedRange];\n\n\t[textView focus];\n}\n\n- (void)memberSendWhois:(id)sender\n{\n\t[self whoisSelectedMembers:sender];\n}\n\n- (void)whoisSelectedMembers:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendWhois:nickname];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberStartPrivateMessage:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tIRCChannel *query = [u findChannelOrCreate:nickname isPrivateMessage:YES];\n\n\t\t[mainWindow() select:query];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPPing:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPPing:nickname];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPFinger:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPQuery:nickname command:@\"FINGER\" text:nil];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPTime:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPQuery:nickname command:@\"TIME\" text:nil];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPVersion:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPQuery:nickname command:@\"VERSION\" text:nil];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPUserinfo:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPQuery:nickname command:@\"USERINFO\" text:nil];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberSendCTCPClientInfo:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u sendCTCPQuery:nickname command:@\"CLIENTINFO\" text:nil];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)_processModeChange:(id)sender usingCommand:(NSString *)modeCommand\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\t[self deselectMembers:sender];\n\n\tNSString *nicknamesString = [nicknames componentsJoinedByString:@\" \"];\n\n\tNSString *command = [NSString stringWithFormat:@\"%@ %@\", modeCommand, nicknamesString];\n\n\t[u sendCommand:command completeTarget:YES target:c.name];\n}\n\n- (void)memberModeGiveOp:(id)sender\n{\n\t[self _processModeChange:sender usingCommand:@\"OP\"];\n}\n\n- (void)memberModeTakeOp:(id)sender\n{ \n\t[self _processModeChange:sender usingCommand:@\"DEOP\"];\n}\n\n- (void)memberModeGiveHalfop:(id)sender\n{ \n\t[self _processModeChange:sender usingCommand:@\"HALFOP\"];\n}\n\n- (void)memberModeTakeHalfop:(id)sender\n{ \n\t[self _processModeChange:sender usingCommand:@\"DEHALFOP\"];\n}\n\n- (void)memberModeGiveVoice:(id)sender\n{ \n\t[self _processModeChange:sender usingCommand:@\"VOICE\"];\n}\n\n- (void)memberModeTakeVoice:(id)sender\n{ \n\t[self _processModeChange:sender usingCommand:@\"DEVOICE\"];\n}\n\n- (void)memberKickFromChannel:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\t[u kick:nickname inChannel:c];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberBanFromChannel:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tNSString *command = [NSString stringWithFormat:@\"BAN %@\", nickname];\n\n\t\t[u sendCommand:command completeTarget:YES target:c.name];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberKickbanFromChannel:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tNSString *command = [NSString stringWithFormat:@\"KICKBAN %@ %@\", nickname, [TPCPreferences defaultKickMessage]];\n\n\t\t[u sendCommand:command completeTarget:YES target:c.name];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberKillFromServer:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tNSString *command = [NSString stringWithFormat:@\"KILL %@ %@\", nickname, [TPCPreferences IRCopDefaultKillMessage]];\n\n\t\t[u sendCommand:command];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberBanFromServer:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tif ([u nicknameIsMyself:nickname]) {\n\t\t\t[u printDebugInformation:TXTLS(@\"IRC[0r1-5l]\", u.serverAddress) inChannel:c];\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *command = [NSString stringWithFormat:@\"GLINE %@ %@\", nickname, [TPCPreferences IRCopDefaultGlineMessage]];\n\n\t\t[u sendCommand:command];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)memberShunOnServer:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in [self selectedMembersNicknames:sender]) {\n\t\tNSString *command = [NSString stringWithFormat:@\"SHUN %@ %@\", nickname, [TPCPreferences IRCopDefaultShunMessage]];\n\n\t\t[u sendCommand:command];\n\t}\n\n\t[self deselectMembers:sender];\n}\n\n- (void)_showSetVhostPromptOpenDialog:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tvoid (^promptCompletionBlock)(NSString *) = ^(NSString *resultString)\n\t{\n\t\tNSString *vhost = resultString.trimAndGetFirstToken;\n\n\t\tif (vhost.length == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (NSString *nickname in nicknames) {\n\t\t\tNSString *command = [NSString stringWithFormat:@\"hs setall %@ %@\", nickname, vhost];\n\n\t\t\t[u sendCommand:command completeTarget:NO target:nil];\n\t\t}\n\t};\n\n\tNSString *vhost = nil;\n\n\tTVCAlertResponseButton response =\n\t[TDCInputPrompt promptWithMessage:TXTLS(@\"Prompts[2mx-jf]\")\n\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[7gr-e4]\")\n\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t\tprefillString:nil\n\t\t\t\t\t\t resultString:&vhost];\n\n\tif (response == TVCAlertResponseButtonFirst) {\n\t\tpromptCompletionBlock(vhost);\n\t}\n}\n\n- (void)showSetVhostPrompt:(id)sender\n{\n\t[self _showSetVhostPromptOpenDialog:sender];\n}\n\n#pragma mark -\n#pragma mark File Transfers\n\n- (TDCFileTransferDialog *)fileTransferController\n{\n\treturn [TXSharedApplication sharedFileTransferDialog];\n}\n\n- (void)showFileTransfersWindow:(id)sender\n{\n\t[self.fileTransferController show:YES restorePosition:YES];\n}\n\n- (void)memberSendFileRequest:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tNSOpenPanel *openPanel = [NSOpenPanel openPanel];\n\n\topenPanel.allowsMultipleSelection = YES;\n\topenPanel.canChooseDirectories = NO;\n\topenPanel.canChooseFiles = YES;\n\topenPanel.canCreateDirectories = NO;\n\topenPanel.resolvesAliases = YES;\n\n\t[openPanel beginSheetModalForWindow:mainWindow() completionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode != NSModalResponseOK) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.fileTransferController.fileTransferTable beginUpdates];\n\n\t\tfor (NSString *nickname in nicknames) {\n\t\t\tfor (NSURL *path in openPanel.URLs) {\n\t\t\t\t[self.fileTransferController addSenderForClient:u nickname:nickname path:path.path autoOpen:YES];\n\t\t\t}\n\t\t}\n\n\t\t[self.fileTransferController.fileTransferTable endUpdates];\n\t}];\n}\n\n- (void)memberSendDroppedFilesToSelectedChannel:(NSArray<NSString *> *)files\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\t[self memberSendDroppedFiles:files to:c.name];\n}\n\n- (void)memberSendDroppedFiles:(NSArray<NSString *> *)files row:(NSUInteger)row\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\tIRCChannelUser *member = [mainWindowMemberList() itemAtRow:row];\n\n\t[self memberSendDroppedFiles:files to:member.user.nickname];\n}\n\n- (void)memberSendDroppedFiles:(NSArray<NSString *> *)files to:(NSString *)nickname\n{\n\tNSParameterAssert(files != nil);\n\tNSParameterAssert(nickname != nil);\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\t[self.fileTransferController.fileTransferTable beginUpdates];\n\n\tfor (NSString *file in files) {\n\t\tBOOL isDirectory = NO;\n\n\t\tif ([RZFileManager() fileExistsAtPath:file isDirectory:&isDirectory] == NO) {\n\t\t\tcontinue;\n\t\t} else if (isDirectory) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[self.fileTransferController addSenderForClient:u nickname:nickname path:file autoOpen:YES];\n\t}\n\n\t[self.fileTransferController.fileTransferTable endUpdates];\n}\n\n#pragma mark -\n#pragma mark Logging\n\n- (void)openLogLocation:(id)sender\n{\t\n\tNSURL *path = [TPCPathInfo transcriptFolderURL];\n\n\tif (path == nil) {\n\t\treturn;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:path]) {\n\t\t[RZWorkspace() openURL:path];\n\n\t\treturn;\n\t}\n\n\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[f05-hu]\")\n\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[k55-19]\")\n\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\talternateButton:nil];\n}\n\n- (void)openChannelLogs:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil) {\n\t\treturn;\n\t}\n\n\tNSURL *path = c.logFilePath;\n\n\tif (path == nil) {\n\t\treturn;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:path]) {\n\t\t[RZWorkspace() openURL:path];\n\n\t\treturn;\n\t}\n\n\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[f05-hu]\")\n\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[k55-19]\")\n\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\talternateButton:nil];\n}\n\n#pragma mark -\n#pragma mark Help\n\n- (void)openAcknowledgements:(id)sender\n{\n\tNSURL *Acknowledgements = [RZMainBundle() URLForResource:@\"Acknowledgements\" withExtension:@\"pdf\" subdirectory:@\"Documentation\"];\n\n\t[RZWorkspace() openURL:Acknowledgements];\n}\n\n- (void)openHelpMenuItem:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tNSDictionary *_helpMenuLinks = @{\n\t   @(MTMMHelpLicenseAgreement) \t\t\t\t\t: @\"https://help.codeux.com/textual/End-User-License-Agreement.kb\",\n\t   @(MTMMHelpPrivacyPolicy) \t\t\t\t\t: @\"https://help.codeux.com/textual/Privacy-Policy.kb\",\n\t   @(MTMMHelpFrequentlyAskedQuestions) \t\t\t: @\"https://help.codeux.com/textual/Frequently-Asked-Questions.kb\",\n\t   @(MTMMHelpKBMenuKnowledgeBaseHome) \t\t\t: @\"https://help.codeux.com/textual/home.kb\",\n\t   @(MTMMHelpKBMenuChatEncryption) \t\t\t\t: @\"https://help.codeux.com/textual/Off-the-Record-Messaging.kb\",\n\t   @(MTMMHelpKBMenuCommandReference) \t\t\t: @\"https://help.codeux.com/textual/Command-Reference.kb\",\n\t   @(MTMMHelpKBMenuFeatureRequests) \t\t\t: @\"https://help.codeux.com/textual/Support.kb\",\n\t   @(MTMMHelpKBMenuKeyboardShortcuts) \t\t\t: @\"https://help.codeux.com/textual/Keyboard-Shortcuts.kb\",\n\t   @(MTMMHelpKBMenuMemoryManagement) \t\t\t: @\"https://help.codeux.com/textual/Memory-Management.kb\",\n\t   @(MTMMHelpKBMenuNetworkTimeouts)\t\t\t\t: @\"https://help.codeux.com/textual/Network-Timeouts.kb\",\n\t   @(MTMMHelpKBMenuTextFormatting) \t\t\t\t: @\"https://help.codeux.com/textual/Text-Formatting.kb\",\n\t   @(MTMMHelpKBMenuStylingInformation) \t\t\t: @\"https://help.codeux.com/textual/Styles.kb\",\n\t   @(MTMMHelpKBMenuConnectingWithCertificate) \t: @\"https://help.codeux.com/textual/Using-CertFP.kb\",\n\t   @(MTMMHelpKBMenuConnectingToBouncer)\t\t\t: @\"https://help.codeux.com/textual/Connecting-to-ZNC-Bouncer.kb\",\n\t   @(MTMMHelpKBMenuDCCFileTransferInformation) \t: @\"https://help.codeux.com/textual/DCC-File-Transfer-Information.kb\"\n\t};\n\n\tNSString *link = _helpMenuLinks[@([sender tag])];\n\n\t[TLOpenLink openWithString:link inBackground:NO];\n}\n\n- (void)openStandaloneStoreWebpage:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://www.textualapp.com/standalone-store\" inBackground:NO];\n}\n\n- (void)contactSupport:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://contact.codeux.com/\" inBackground:NO];\n}\n\n- (void)connectToTextualHelpChannel:(id)sender\n{\n\t[IRCExtras createConnectionToServer:@\"irc.libera.chat +6697\" channelList:@\"#textual\" connectWhenCreated:YES mergeConnectionIfPossible:YES selectFirstChannelAdded:YES];\n}\n\n- (void)connectToTextualTestingChannel:(id)sender\n{\n\t[IRCExtras createConnectionToServer:@\"irc.libera.chat +6697\" channelList:@\"#textual-testing\" connectWhenCreated:YES mergeConnectionIfPossible:YES selectFirstChannelAdded:YES];\n}\n\n#pragma mark -\n#pragma mark IRC\n\n- (void)showChannelBanList:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[u createChannelBanListSheet];\n\n\t[u sendModes:@\"+b\" withParameters:nil inChannel:c];\n}\n\n- (void)showChannelBanExceptionList:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[u createChannelBanExceptionListSheet];\n\n\t[u sendModes:@\"+e\" withParameters:nil inChannel:c];\n}\n\n- (void)showChannelInviteExceptionList:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[u createChannelInviteExceptionListSheet];\n\n\t[u sendModes:@\"+I\" withParameters:nil inChannel:c];\n}\n\n- (void)showChannelQuietList:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[u createChannelQuietListSheet];\n\n\t[u sendModes:@\"+q\" withParameters:nil inChannel:c];\n}\n\n- (void)toggleChannelModerationMode:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSString *modeSymbol = nil;\n\n\tif ([sender tag] == MTMMChannelModesMenuRemoveModerated) {\n\t\tmodeSymbol = @\"-m\";\n\t} else {\n\t\tmodeSymbol = @\"+m\";\n\t}\n\n\t[u sendModes:modeSymbol withParameters:nil inChannel:c];\n}\n\n- (void)toggleChannelInviteMode:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSString *modeSymbol = nil;\n\n\tif ([sender tag] == MTMMChannelModesMenuRemoveInviteOnly) {\n\t\tmodeSymbol = @\"-i\";\n\t} else {\n\t\tmodeSymbol = @\"+i\";\n\t}\n\n\t[u sendModes:modeSymbol withParameters:nil inChannel:c];\n}\n\n#pragma mark -\n#pragma mark Window\n\n- (void)closeWindow:(id)sender\n{\n\tTXCommandWKeyAction keyAction = [TPCPreferences commandWKeyAction];\n\n\tif (keyAction == TXCommandWKeyActionCloseWindow || mainWindow().keyWindow == NO) {\n\t\tNSWindow *windowToClose = [NSApp keyWindow];\n\n\t\tif (windowToClose == nil) {\n\t\t\twindowToClose = [NSApp mainWindow];\n\t\t}\n\n\t\tif (windowToClose) {\n\t\t\t[windowToClose performClose:sender];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tswitch (keyAction) {\n\t\tcase TXCommandWKeyActionPartChannel:\n\t\t{\n\t\t\tif (c == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (c.isChannel) {\n\t\t\t\tif (c.isActive == NO) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t[u partChannel:c];\n\t\t\t} else {\n\t\t\t\t[worldController() destroyChannel:c];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXCommandWKeyActionDisconnect:\n\t\t{\n\t\t\tif (u.isConnecting == NO && u.isConnected == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[u quit];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXCommandWKeyActionTerminate:\n\t\t{\n\t\t\t[NSApp terminate:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n- (void)showMainWindow:(id)sender\n{\n\t[mainWindow() makeKeyAndOrderFront:sender];\n}\n\n- (void)centerMainWindow:(id)sender\n{\n\t[mainWindow() exactlyCenterWindow];\n}\n\n- (void)toggleFullscreen:(id)sender\n{\n\t[[NSApp keyWindow] toggleFullScreen:sender];\n}\n\n- (void)resetMainWindowFrame:(id)sender\n{\n\tif (mainWindow().inFullscreenMode) {\n\t\t[mainWindow() toggleFullScreen:sender];\n\t}\n\n\t[mainWindow() setFrame:[mainWindow() defaultWindowFrame] display:YES animate:YES];\n\n\t[mainWindow() exactlyCenterWindow];\n}\n\n- (void)sortChannelListNames:(id)sender\n{\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tNSMutableArray *channelList = [u.channelList mutableCopy];\n\n\t\t[channelList sortUsingComparator:^NSComparisonResult(IRCChannel *channel1, IRCChannel *channel2) {\n\t\t\tif (channel1.isChannel && channel2.isChannel == NO) {\n\t\t\t\treturn NSOrderedAscending;\n\t\t\t}\n\n\t\t\tNSString *name1 = channel1.name.lowercaseString;\n\t\t\tNSString *name2 = channel2.name.lowercaseString;\n\n\t\t\treturn [name1 compare:name2];\n\t\t}];\n\n\t\tif ([channelList isEqualToArray:u.channelList]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tu.channelList = channelList;\n\n\t\t[u reloadServerListItems];\n\t}\n\n\t[worldController() save];\n}\n\n- (void)markAllAsRead:(id)sender\n{\n\t[mainWindow() markAllAsRead];\n}\n\n#pragma mark -\n#pragma mark Preferences\n\n- (void)importPreferences:(id)sender\n{\n\t[TPCPreferencesImportExport importInWindow:mainWindow()];\n}\n\n- (void)exportPreferences:(id)sender\n{\n\t[TPCPreferencesImportExport exportInWindow:mainWindow()];\n}\n\n#pragma mark -\n#pragma mark Off-the-Record Messaging\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n#define _encryptionNotEnabled\t\t([TPCPreferences textEncryptionIsEnabled] == NO)\n\n- (void)encryptionStartPrivateConversation:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\t[sharedEncryptionManager() beginConversationWith:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t\t\t\t\t\t\tfrom:[u encryptionAccountNameForLocalUser]];\n}\n\n- (void)encryptionRefreshPrivateConversation:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\t[sharedEncryptionManager() refreshConversationWith:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t\t\t\t\t\t\t  from:[u encryptionAccountNameForLocalUser]];\n}\n\n- (void)encryptionEndPrivateConversation:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\t[sharedEncryptionManager() endConversationWith:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t\t\t\t\t\t  from:[u encryptionAccountNameForLocalUser]];\n}\n\n- (void)encryptionAuthenticateChatPartner:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (_encryptionNotEnabled || u == nil || c == nil || u.isLoggedIn == NO || c.isPrivateMessage == NO) {\n\t\treturn;\n\t}\n\n\t[sharedEncryptionManager() authenticateUser:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t\t\t\t\t   from:[u encryptionAccountNameForLocalUser]];\n}\n\n- (void)encryptionListFingerprints:(id)sender\n{\n\t[sharedEncryptionManager() presentListOfFingerprints];\n}\n\n- (void)encryptionWhatIsThisInformation:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Off-the-Record-Messaging.kb\" inBackground:NO];\n}\n\n#undef _encryptionNotEnabled\n#endif\n\n#pragma mark -\n#pragma mark Notifications\n\n- (void)toggleMuteOnNotificationsShortcutOn:(BOOL)toggleOn\n{\n\tsharedNotificationController().areNotificationsDisabled = toggleOn;\n\n\tNSControlStateValue state = ((toggleOn) ? NSControlStateValueOn : NSControlStateValueOff);\n\n\tself.muteNotificationsFileMenuItem.state = state;\n\n\tself.muteNotificationsDockMenuItem.state = state;\n}\n\n- (void)toggleMuteOnNotificationSoundsShortcutOn:(BOOL)toggleOn\n{\n\t[TPCPreferences setSoundIsMuted:toggleOn];\n\n\tNSControlStateValue state = ((toggleOn) ? NSControlStateValueOn : NSControlStateValueOff);\n\n\tself.muteNotificationsSoundsDockMenuItem.state = state;\n\n\tself.muteNotificationsSoundsFileMenuItem.state = state;\n}\n\n- (void)toggleMuteOnNotificationSounds:(id)sender\n{\n\tif ([TPCPreferences soundIsMuted]) {\n\t\t[self toggleMuteOnNotificationSoundsShortcutOn:NO];\n\t} else {\n\t\t[self toggleMuteOnNotificationSoundsShortcutOn:YES];\n\t}\n}\n\n- (void)toggleMuteOnNotifications:(id)sender\n{\n\tif (sharedNotificationController().areNotificationsDisabled) {\n\t\t[self toggleMuteOnNotificationsShortcutOn:NO];\n\t} else {\n\t\t[self toggleMuteOnNotificationsShortcutOn:YES];\n\t}\n}\n\n#pragma mark -\n#pragma mark Appearance\n\n- (void)resetMainWindowAppearance:(id)sender\n{\n\t[TPCPreferences setAppearance:TXPreferredAppearanceInherited];\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];\n}\n\n- (void)toggleMainWindowAppearance:(id)sender\n{\n\tTXPreferredAppearance appearance = [TPCPreferences appearance];\n\n\tswitch (appearance) {\n\t\tcase TXPreferredAppearanceInherited:\n\t\t{\n\t\t\tTXAppearance *appAppearance = [TXSharedApplication sharedAppearance];\n\n\t\t\tif (appAppearance.properties.isDarkAppearance == NO) {\n\t\t\t\tappearance = TXPreferredAppearanceDark;\n\t\t\t} else {\n\t\t\t\tappearance = TXPreferredAppearanceLight;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXPreferredAppearanceLight:\n\t\t{\n\t\t\tappearance = TXPreferredAppearanceDark;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXPreferredAppearanceDark:\n\t\t{\n\t\t\tappearance = TXPreferredAppearanceLight;\n\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n\n\t[TPCPreferences setAppearance:appearance];\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];\n}\n\n- (void)toggleServerListVisibility:(id)sender\n{\n\t[mainWindow().contentSplitView toggleServerListVisibility];\n}\n\n- (void)toggleMemberListVisibility:(id)sender\n{\n\tmainWindowMemberList().isHiddenByUser = (mainWindowMemberList().isHiddenByUser == NO);\n\n\t[mainWindow().contentSplitView toggleMemberListVisibility];\n}\n\n- (void)forceReloadTheme:(id)sender\n{\n\t[mainWindow() reloadTheme];\n}\n\n#pragma mark -\n#pragma mark License Manager\n\n- (void)manageLicense:(id)sender\n{\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\t[self manageLicense:sender activateLicenseKey:nil licenseKeyPassedByArgument:NO];\n#endif\n}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey\n{\n\t[self manageLicense:sender activateLicenseKey:licenseKey licenseKeyPassedByArgument:NO];\n}\n\n- (void)manageLicense:(id)sender activateLicenseKeyWithURL:(NSURL *)licenseKeyURL\n{\n\tNSParameterAssert(licenseKeyURL != nil);\n\n\tNSString *path = licenseKeyURL.path;\n\n\tif (path == nil) {\n\t\treturn;\n\t}\n\n\tNSCharacterSet *slashCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@\"/\"];\n\n\tNSString *licenseKey = [path stringByTrimmingCharactersInSet:slashCharacterSet];\n\n\tif (licenseKey.length == 0) {\n\t\treturn;\n\t}\n\n\t[self manageLicense:sender activateLicenseKey:licenseKey licenseKeyPassedByArgument:NO];\n}\n\n- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey licenseKeyPassedByArgument:(BOOL)licenseKeyPassedByArgument\n{\n\tTDCLicenseManagerDialog *licenseDialog = [TXSharedApplication sharedLicenseManagerDialog];\n\n\t[licenseDialog show];\n\n\tif (licenseKey) {\n\t\t[licenseDialog activateLicenseKey:licenseKey silently:licenseKeyPassedByArgument];\n\t}\n}\n#endif\n\n#pragma mark -\n#pragma mark Developer\n\n- (void)toggleDeveloperMode:(id)sender\n{\n\t[TPCPreferences setDeveloperModeEnabled:([TPCPreferences developerModeEnabled] == NO)];\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionIRCCommandCache];\n}\n\n- (void)resetDoNotAskMePopupWarnings:(id)sender\n{\n\tNSDictionary *settings = [RZUserDefaults() dictionaryRepresentation];\n\n\tfor (NSString *key in settings) {\n\t\tif ([key hasPrefix:TDCAlertSuppressionPrefix] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[RZUserDefaults() setBool:NO forKey:key];\n\t}\n}\n\n#pragma mark -\n#pragma mark Sparkle Framework\n\n- (void)checkForUpdates:(id)sender\n{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tSPUStandardUpdaterController *controller = masterController().updateController;\n\n\t[controller checkForUpdates:sender];\n#endif\n}\n\n#pragma mark -\n#pragma mark Navigation\n\n- (void)navigateToTreeItemAtURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *path = url.path;\n\t\n\tif (path == nil) {\n\t\treturn;\n\t}\n\t\n\tNSCharacterSet *slashCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@\"/\"];\n\t\n\tNSString *identifier = [path stringByTrimmingCharactersInSet:slashCharacterSet];\n\t\n\tif (identifier.length == 0) {\n\t\treturn;\n\t}\n\t\n\t[self navigateToTreeItemWithIdentifier:identifier];\n}\n\n- (void)navigateToTreeItemWithIdentifier:(NSString *)identifier\n{\n\tNSParameterAssert(identifier != nil);\n\t\n\t/* Do not use assert for this condition so we\n\t don't crash user when we open a malformed URL. */\n\tif (identifier.length != 36) {\n\t\treturn;\n\t}\n\t\n\tIRCTreeItem *item = [worldController() findItemWithId:identifier];\n\t\n\tif (item == nil) {\n\t\treturn;\n\t}\n\t\n\t[self navigateToTreeItem:item];\n}\n\n- (void)navigateToTreeItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\t\n\t[mainWindow() select:item];\n}\n\n- (void)populateNavigationChannelList\n{\n\t[self.mainMenuNavigationChannelListMenu removeAllItems];\n\n\tNSUInteger channelCount = 0;\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tNSMenu *channelSubmenu = [NSMenu new];\n\n\t\tNSMenuItem *clientMenuItem = [NSMenuItem new];\n\n\t\tclientMenuItem.title = u.name;\n\n\t\tclientMenuItem.submenu = channelSubmenu;\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tNSMenuItem *channelMenuItem = nil;\n\n\t\t\tif (channelCount >= 10) {\n\t\t\t\tchannelMenuItem = [NSMenuItem menuItemWithTitle:c.name\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t target:self\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t action:@selector(_navigateToChannelInNavigationList:)];\n\t\t\t} else {\n\t\t\t\tNSUInteger keyboardIndex = (channelCount + 1);\n\n\t\t\t\tif (keyboardIndex == 10) {\n\t\t\t\t\tkeyboardIndex = 0; // Have 0 as the last item.\n\t\t\t\t}\n\n\t\t\t\tchannelMenuItem = [NSMenuItem menuItemWithTitle:c.name\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t target:self\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t action:@selector(_navigateToChannelInNavigationList:)\n\t\t\t\t\t\t\t\t\t\t\t\t  keyEquivalent:[NSString stringWithUniChar:('0' + keyboardIndex)]\n\t\t\t\t\t\t\t\t\t\t\t  keyEquivalentMask:NSEventModifierFlagCommand];\n\t\t\t}\n\n\t\t\tchannelMenuItem.userInfo = [worldController() pasteboardStringForItem:c];\n\n\t\t\t[channelSubmenu addItem:channelMenuItem];\n\n\t\t\tchannelCount += 1;\n\t\t}\n\n\t\t[self.mainMenuNavigationChannelListMenu addItem:clientMenuItem];\n\t}\n}\n\n- (void)_navigateToChannelInNavigationList:(NSMenuItem *)sender\n{\n\tIRCTreeItem *treeItem = [worldController() findItemWithPasteboardString:sender.userInfo];\n\n\tif (treeItem == nil) {\n\t\treturn;\n\t}\n\n\t[mainWindow() select:treeItem];\n}\n\n- (void)performNavigationAction:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tswitch ([sender tag]) {\n\t\tcase MTMMNavigationServersMenuNextServer:\n\t\t{\n\t\t\t[mainWindow() selectNextServer:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationServersMenuPreviousServer:\n\t\t{\n\t\t\t[mainWindow() selectPreviousServer:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationServersMenuNextActiveServer:\n\t\t{\n\t\t\t[mainWindow() selectNextActiveServer:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationServersMenuPreviousActiveServer:\n\t\t{\n\t\t\t[mainWindow() selectPreviousActiveServer:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuNextChannel:\n\t\t{\n\t\t\t[mainWindow() selectNextChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuPreviousChannel:\n\t\t{\n\t\t\t[mainWindow() selectPreviousChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuNextActiveChannel:\n\t\t{\n\t\t\t[mainWindow() selectNextActiveChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuPreviousActiveChannel:\n\t\t{\n\t\t\t[mainWindow() selectPreviousActiveChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuNextUnreadChannel:\n\t\t{\n\t\t\t[mainWindow() selectNextUnreadChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationChannelsMenuPreviousUnreadChannel:\n\t\t{\n\t\t\t[mainWindow() selectPreviousUnreadChannel:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationMoveBackward:\n\t\t{\n\t\t\t[mainWindow() selectPreviousWindow:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationMoveForward:\n\t\t{\n\t\t\t[mainWindow() selectNextWindow:sender];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase MTMMNavigationPreviousSelection:\n\t\t{\n\t\t\t[mainWindow() selectPreviousSelection:sender];\n\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n}\n\n- (void)onNextHighlight:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController nextHighlight];\n}\n\n- (void)onPreviousHighlight:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController previousHighlight];\n}\n\n- (void)jumpToCurrentSession:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController jumpToCurrentSession];\n}\n\n- (void)jumpToPresent:(id)sender\n{\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\t[viewController jumpToPresent];\n}\n\n#pragma mark -\n#pragma mark Channel Properties Sheet\n\n- (void)showChannelPropertiesSheet:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tTDCChannelPropertiesSheet *sheet =\n\t[[TDCChannelPropertiesSheet alloc] initWithChannel:c];\n\n\tsheet.delegate = self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config\n{\n\tIRCClient *u = sender.client;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tIRCChannel *c = sender.channel;\n\n\tif (c == nil) {\n\t\t[worldController() createChannelWithConfig:config onClient:u];\n\n\t\t[mainWindow() expandClient:u];\n\n\t\treturn;\n\t}\n\n\t[c updateConfig:config];\n\n\t[worldController() save];\n}\n\n- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Channel Invite Sheet\n\n- (void)memberSendInvite:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO || c.isActive == NO) {\n\t\treturn;\n\t}\n\n\tNSArray *nicknames = [self selectedMembersNicknames:sender];\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\t[self deselectMembers:sender];\n\n\tNSMutableArray<NSString *> *channels = [NSMutableArray array];\n\n\tfor (IRCChannel *e in u.channelList) {\n\t\tif (c != e && e.isChannel) {\n\t\t\t[channels addObject:e.name];\n\t\t}\n\t}\n\n\tif (channels.count == 0) {\n\t\treturn;\n\t}\n\n\tTDCChannelInviteSheet *sheet =\n\t[[TDCChannelInviteSheet alloc] initWithNicknames:nicknames onClient:u];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet startWithChannels:channels];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)channelInviteSheet:(TDCChannelInviteSheet *)sender onSelectChannel:(NSString *)channelName\n{\n\tIRCClient *u = sender.client;\n\n\tif (u == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *nickname in sender.nicknames) {\n\t\t[u sendInviteTo:nickname toJoinChannelNamed:channelName];\n\t}\n}\n\n- (void)channelInviteSheetWillClose:(TDCChannelInviteSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Address Book Sheet\n\n- (void)showAddressBook:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\t[self showServerPropertiesSheetForClient:u\n\t\t\t\t\t\t\t   withSelection:TDCServerPropertiesSheetSelectionAddressBook\n\t\t\t\t\t\t\t\t\t context:nil];\n}\n\n- (void)showIgnoreList:(id)sender\n{\n\t[self showAddressBook:sender];\n}\n\n#pragma mark -\n#pragma mark Welcome Sheet\n\n- (void)showWelcomeSheet:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tTDCWelcomeSheet *sheet =\n\t[[TDCWelcomeSheet alloc] initWithWindow:mainWindow()];\n\n\tsheet.delegate = (id)self;\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)welcomeSheet:(TDCWelcomeSheet *)sender onOk:(IRCClientConfig *)config\n{\n\tIRCClient *u = [worldController() createClientWithConfig:config reload:YES];\n\n\t[mainWindow() expandClient:u];\n\n\t[worldController() save];\n\n\t[u connect];\n\n\t[u selectFirstChannelInChannelList];\n}\n\n- (void)welcomeSheetWillClose:(TDCWelcomeSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark About Window\n\n- (void)showAboutWindow:(id)sender\n{\n\t_popWindowViewIfExists(@\"TDCAboutDialog\");\n\n\tTDCAboutDialog *dialog = [TDCAboutDialog new];\n\n\tdialog.delegate = (id)self;\n\n\t[dialog show];\n\n\t[windowController() addWindowToWindowList:dialog];\n}\n\n- (void)aboutDialogWillClose:(TDCAboutDialog *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Server Properties Sheet\n\n- (void)showServerPropertiesSheetForClient:(IRCClient *)client withSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context\n{\n\tNSParameterAssert(client != nil);\n\n\t[windowController() popMainWindowSheetIfExists];\n\n\tTDCServerPropertiesSheet *sheet = [[TDCServerPropertiesSheet alloc] initWithClient:client];\n\n\tsheet.delegate = self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet startWithSelection:selection context:context];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)showServerPropertiesSheet:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\t[self showServerPropertiesSheetForClient:u\n\t\t\t\t\t\t\t   withSelection:TDCServerPropertiesSheetSelectionDefault\n\t\t\t\t\t\t\t\t\t context:nil];\n}\n\n- (void)serverPropertiesSheet:(TDCServerPropertiesSheet *)sender onOk:(IRCClientConfig *)config\n{\n\tIRCClient *u = sender.client;\n\n\tif (u == nil) {\n\t\tu = [worldController() createClientWithConfig:config reload:YES];\n\n\t\t[mainWindow() expandClient:u];\n\n\t\t[worldController() save];\n\n\t\treturn;\n\t}\n\n\tBOOL sameEncoding = (config.primaryEncoding == u.config.primaryEncoding);\n\n\t[u updateConfig:config];\n\n\tif (sameEncoding == NO) {\n\t\t[mainWindow() reloadTheme];\n\t}\n\n\t[mainWindow() reloadTreeGroup:u];\n\n\t[worldController() save];\n}\n\n- (void)serverPropertiesSheetWillClose:(TDCServerPropertiesSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Highlight List Sheet\n\n- (void)showServerHighlightList:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tTDCServerHighlightListSheet *sheet =\n\t[[TDCServerHighlightListSheet alloc] initWithClient:u];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)serverHighlightListSheetWillClose:(TDCServerHighlightListSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Nickname Color Sheet\n\n- (void)memberChangeColor:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil) {\n\t\treturn;\n\t}\n\n\tTDCNicknameColorSheet *sheet =\n\t[[TDCNicknameColorSheet alloc] initWithNickname:nickname];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)nicknameColorSheetOnOk:(TDCNicknameColorSheet *)sender\n{\n\t[mainWindow() reloadTheme];\n}\n\n- (void)nicknameColorSheetWillClose:(TDCNicknameColorSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Channel Topic Sheet\n\n- (void)showChannelModifyTopicSheet:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tTDCChannelModifyTopicSheet *sheet =\n\t[[TDCChannelModifyTopicSheet alloc] initWithChannel:c];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)channelModifyTopicSheet:(TDCChannelModifyTopicSheet *)sender onOk:(NSString *)topic\n{\n\tIRCClient *u = sender.client;\n\tIRCChannel *c = sender.channel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[u sendTopicTo:topic inChannel:c];\n}\n\n- (void)channelModifyTopicSheetWillClose:(TDCChannelModifyTopicSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Channel Mode Sheet\n\n- (void)showChannelModifyModesSheet:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil || c == nil || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tTDCChannelModifyModesSheet *sheet =\n\t[[TDCChannelModifyModesSheet alloc] initWithChannel:c];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)channelModifyModesSheet:(TDCChannelModifyModesSheet *)sender onOk:(IRCChannelModeContainer *)modes\n{\n\tIRCClient *u = sender.client;\n\tIRCChannel *c = sender.channel;\n\n\tif (u == nil || c == nil || u.isLoggedIn == NO || c.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSString *changeString = [c.modeInfo getChangeCommand:modes];\n\n\tif (changeString.length == 0) {\n\t\treturn;\n\t}\n\n\t[u sendModes:changeString withParameters:nil inChannel:c];\n}\n\n- (void)channelModifyModesSheetWillClose:(TDCChannelModifyModesSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Channel Spotlight Window\n\n- (void)showChannelSpotlightWindow:(id)sender\n{\n\t_popWindowViewIfExists(@\"TDCChannelSpotlightController\");\n\n\tTDCChannelSpotlightController *dialog = [TDCChannelSpotlightController new];\n\n\tdialog.delegate = (id)self;\n\n\t[dialog show];\n\n\t[windowController() addWindowToWindowList:dialog];\n}\n\n- (void)channelSpotlightController:(TDCChannelSpotlightController *)sender selectChannel:(IRCChannel *)channel\n{\n\t[mainWindow() select:channel];\n}\n\n- (void)channelSpotlightControllerWillClose:(TDCChannelSpotlightController *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Change Nickname Sheet\n\n- (void)showServerChangeNicknameSheet:(id)sender\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCClient *u = self.selectedClient;\n\n\tif (u == nil || u.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tTDCServerChangeNicknameSheet *sheet =\n\t[[TDCServerChangeNicknameSheet alloc] initWithClient:u];\n\n\tsheet.delegate = (id)self;\n\n\tsheet.window = mainWindow();\n\n\t[sheet start];\n\n\t[windowController() addWindowToWindowList:sheet];\n}\n\n- (void)serverChangeNicknameSheet:(TDCServerChangeNicknameSheet *)sender didInputNickname:(NSString *)nickname\n{\n\tIRCClient *u = sender.client;\n\n\tif (u == nil || u.isConnected == NO) {\n\t\treturn;\n\t}\n\n\t[u changeNickname:nickname];\n}\n\n- (void)serverChangeNicknameSheetWillClose:(TDCServerChangeNicknameSheet *)sender\n{\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Preferences Dialog\n\n- (void)showPreferencesWindow:(id)sender\n{\n\t[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionDefault];\n}\n\n- (void)showNotificationPreferences:(id)sender\n{\n\t[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionNotifications];\n}\n\n- (void)showStylePreferences:(id)sender\n{\n\t[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionStyle];\n}\n\n- (void)showHiddenPreferences:(id)sender\n{\n\t[self showPreferencesWindowWithSelection:TDCPreferencesControllerSelectionHiddenPreferences];\n}\n\n- (void)showPreferencesWindowWithSelection:(TDCPreferencesControllerSelection)selection\n{\n\tTDCPreferencesController *openWindow = [windowController() windowFromWindowList:@\"TDCPreferencesController\"];\n\n\tif (openWindow) {\n\t\t[openWindow show:selection];\n\n\t\treturn;\n\t}\n\n\tTDCPreferencesController *controller =\n\t[TDCPreferencesController new];\n\n\tcontroller.delegate = (id)self;\n\n\t[controller show:selection];\n\n\t[windowController() addWindowToWindowList:controller];\n}\n\n- (void)preferencesDialogWillClose:(TDCPreferencesController *)sender\n{\n\t[TPCPreferences performReloadAction:(TPCPreferencesReloadActionHighlightKeywords |\n\t\t\t\t\t\t\t\t\t\t TPCPreferencesReloadActionPreferencesChanged)];\n\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Main Window Proxy\n\n@implementation TXMenuControllerMainWindowProxy\n\n- (void)openStandaloneStoreWebpage:(id)sender\n{\n\t[menuController() openStandaloneStoreWebpage:sender];\n}\n\n- (void)manageLicense:(id)sender\n{\n\t[menuController() manageLicense:sender];\n}\n\n- (void)showWelcomeSheet:(id)sender\n{\n\t[menuController() showWelcomeSheet:sender];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXSharedApplication.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BuildConfig.h\"\n\n#import \"OELReachability.h\"\n#import \"TXAppearance.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TXWindowControllerPrivate.h\"\n#import \"TPCThemeController.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"IRCWorld.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLONotificationController.h\"\n#import \"TLOSpeechSynthesizerPrivate.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TVCLogControllerOperationQueuePrivate.h\"\n#import \"TXSharedApplicationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TXErrorDomain = @\"TextualErrorDomain\";\n\n#define _defineSharedInstance(si_name, si_class, si_init_method)\t\\\n\t\t\t+ (si_class *)si_name\t\t\t\t\t\t\t\t\t\\\n\t\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tstatic id sharedSelf = nil;\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tstatic dispatch_once_t onceToken;\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\tdispatch_once(&onceToken, ^{\t\t\t\t\t\t\\\n\t\t\t\t\tsharedSelf = [si_class si_init_method];\t\t\t\\\n\t\t\t\t});\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\treturn sharedSelf;\t\t\t\t\t\t\t\t\t\\\n\t\t\t}\n\n@implementation TXSharedApplication\n\n_defineSharedInstance(sharedAppearance, TXAppearance, new)\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n_defineSharedInstance(sharedEncryptionManager, TLOEncryptionManager, new)\n#endif\n\n_defineSharedInstance(sharedNetworkReachabilityNotifier, OELReachability, reachabilityForInternetConnection)\n_defineSharedInstance(sharedNotificationController, TLONotificationController, new)\n_defineSharedInstance(sharedPluginManager, THOPluginManager, new)\n_defineSharedInstance(sharedPrintingQueue, TVCLogControllerPrintingOperationQueue, new)\n_defineSharedInstance(sharedSpeechSynthesizer, TLOSpeechSynthesizer, new)\n_defineSharedInstance(sharedThemeController, TPCThemeController, new)\n_defineSharedInstance(sharedWindowController, TXWindowController, new)\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n_defineSharedInstance(sharedLicenseManagerDialog, TDCLicenseManagerDialog, new)\n#endif\n\n_defineSharedInstance(sharedFileTransferDialog, TDCFileTransferDialog, new)\n\nos_log_t ApplicationTerminationLogSubsystem(void)\n{\n\tstatic os_log_t cachedValue = NULL;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue = os_log_create(TXBundleBuildProductIdentifierCString, \"Termination\");\n\t});\n\n\treturn cachedValue;\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSObject (TXSharedApplicationObjectExtension)\n\n__weak static TXMasterController *TXGlobalMasterControllerClassReference;\n\n+ (void)setGlobalMasterControllerClassReference:(id)masterController\n{\n\tTXGlobalMasterControllerClassReference = masterController;\n}\n\n- (TXMasterController *)masterController\n{\n\treturn TXGlobalMasterControllerClassReference;\n}\n\n+ (TXMasterController *)masterController\n{\n\treturn TXGlobalMasterControllerClassReference;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Controllers/TXWindowController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TVCMainWindow.h\"\n#import \"TXWindowControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXWindowController ()\n@property (nonatomic, strong) NSMutableDictionary *windowObjects;\n@end\n\n@implementation TXWindowController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.windowObjects = [NSMutableDictionary dictionary];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing window controller\");\n\n\t@synchronized(self.windowObjects) {\n\t\t[self.windowObjects removeAllObjects];\n\t\t self.windowObjects = nil;\n\t}\n}\n\n+ (NSString *)windowDescriptionForWindow:(id)window\n{\n\treturn [self windowDescriptionForWindow:window inRelationTo:nil];\n}\n\n+ (NSString *)windowDescriptionForWindow:(id)window inRelationTo:(nullable id)relatedObject\n{\n\tNSParameterAssert(window != nil);\n\n\tNSString *windowClass = NSStringFromClass([window class]);\n\n\tif (relatedObject == nil) {\n\t\treturn windowClass;\n\t}\n\n\treturn [NSString stringWithFormat:@\"%@ -> %@\", windowClass, [relatedObject description]];\n}\n\n- (void)addWindowToWindowList:(id)window\n{\n\t[self addWindowToWindowList:window inRelationTo:nil];\n}\n\n- (void)addWindowToWindowList:(id)window inRelationTo:(nullable id)relatedObject\n{\n\tNSString *windowDescription = [self.class windowDescriptionForWindow:window inRelationTo:relatedObject];\n\n\t[self addWindowToWindowList:window withDescription:windowDescription];\n}\n\n- (void)addWindowToWindowList:(id)window withDescription:(NSString *)windowDescription\n{\n\tNSParameterAssert(window != nil);\n\n\tNSAssert([window respondsToSelector:@selector(window)],\n\t\t@\"'window' does not respond to -window\");\n\n\t@synchronized(self.windowObjects) {\n\t\tself.windowObjects[windowDescription] = window;\n\t}\n}\n\n- (void)removeWindowFromWindowList:(id)window\n{\n\t[self removeWindowFromWindowList:window inRelationTo:nil];\n}\n\n- (void)removeWindowFromWindowList:(id)window inRelationTo:(nullable id)relatedObject\n{\n\tNSParameterAssert(window != nil);\n\n\tif ([window isKindOfClass:[NSArray class]]) {\n\t\tfor (id object in window) {\n\t\t\t[self removeWindowFromWindowList:object inRelationTo:relatedObject];\n\t\t}\n\n\t\treturn; // Do not continue...\n\t}\n\n\tBOOL windowWasString = NO;\n\n\tNSString *windowDescription = nil;\n\n\tif ([window isKindOfClass:[NSString class]]) {\n\t\twindowWasString = YES;\n\n\t\twindowDescription = window;\n\t} else {\n\t\twindowDescription = [self.class windowDescriptionForWindow:window inRelationTo:relatedObject];\n\t}\n\n\tif (windowDescription == nil) {\n\t\treturn; // Cannot continue...\n\t}\n\n\t@synchronized(self.windowObjects) {\n\t\tif (self.windowObjects[windowDescription] == nil && windowWasString == NO) {\n\t\t\twindowDescription = [self.windowObjects firstKeyForObject:window];\n\t\t}\n\n\t\tif (windowDescription) {\n\t\t\t[self.windowObjects removeObjectForKey:windowDescription];\n\t\t}\n\t}\n}\n\n- (nullable id)windowFromWindowList:(NSString *)windowDescription\n{\n\tNSParameterAssert(windowDescription != nil);\n\n\t@synchronized(self.windowObjects) {\n\t\treturn self.windowObjects[windowDescription];\n\t}\n}\n\n- (NSArray *)windowsFromWindowList:(NSArray<NSString *> *)windowDescriptions\n{\n\tNSParameterAssert(windowDescriptions != nil);\n\n\t@synchronized(self.windowObjects) {\n\t\tNSMutableArray *returnedValues = [NSMutableArray array];\n\n\t\tfor (id windowDescription in windowDescriptions) {\n\t\t\tif ([windowDescription isKindOfClass:[NSString class]] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tid windowObject = self.windowObjects[windowDescription];\n\n\t\t\tif (windowObject) {\n\t\t\t\t[returnedValues addObject:windowObject];\n\t\t\t}\n\t\t}\n\n\t\treturn [returnedValues copy];\n\t}\n}\n\n- (BOOL)maybeBringWindowForward:(NSString *)windowDescription\n{\n\tNSParameterAssert(windowDescription != nil);\n\n\tid windowObject = [self windowFromWindowList:windowDescription];\n\n\tif (windowObject) {\n\t\tNSWindow *window = [windowObject window];\n\n\t\t[window makeKeyAndOrderFront:nil];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)popMainWindowSheetIfExists\n{\n\tNSWindow *attachedSheet = mainWindow().attachedSheet;\n\n\tif (attachedSheet == nil) {\n\t\treturn;\n\t}\n\n\t[attachedSheet close];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCAppearancePrivate.h\"\n#import \"TDCChannelSpotlightControlsPrivate.h\"\n#import \"TDCChannelSpotlightAppearanceInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightAppearance ()\n#pragma mark -\n#pragma mark Search Field\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldCompletionTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchFieldNoResultsTextColor;\n\n#pragma mark -\n#pragma mark Search Result\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultRowSelectionColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultRowSelectionColorInactiveWindow;\n@property (nonatomic, assign, readwrite) BOOL searchResultRowEmphasized;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultChannelNameTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultChannelDescriptionTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultKeyboardShortcutTextColor;\n@property (nonatomic, assign, readwrite) CGFloat searchResultKeyboardShortcutDeselectedOffset;\n@property (nonatomic, assign, readwrite) CGFloat searchResultKeyboardShortcutSelectedOffset;\n@property (nonatomic, copy, nullable, readwrite) NSColor *searchResultSelectedTextColor;\n@end\n\n@implementation TDCChannelSpotlightAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (nullable instancetype)initWithWindow:(TDCChannelSpotlightPanel *)window\n{\n\tNSParameterAssert(window != nil);\n\n\tNSURL *appearanceLocation = [self.class appearanceLocation];\n\n\tBOOL forRetinaDisplay = window.runningInHighResolutionMode;\n\n\tif ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (NSURL *)appearanceLocation\n{\n\treturn [RZMainBundle() URLForResource:@\"TDCChannelSpotlightAppearance\" withExtension:@\"plist\"];\n}\n\n- (void)prepareInitialState\n{\n\tNSDictionary *properties = self.appearanceProperties;\n\n\tNSDictionary *searchField = properties[@\"Search Field\"];\n\n\tself.searchFieldTextColor = [self colorInGroup:searchField withKey:@\"controlTextColor\"];\n\tself.searchFieldCompletionTextColor = [self colorInGroup:searchField withKey:@\"completionTextColor\"];\n\tself.searchFieldNoResultsTextColor = [self colorInGroup:searchField withKey:@\"noResultsTextColor\"];\n\n\tNSDictionary *searchResult = properties[@\"Search Result\"];\n\n\tself.searchResultRowSelectionColorActiveWindow = [self colorInGroup:searchResult withKey:@\"selectionColor\" forActiveWindow:YES];\n\tself.searchResultRowSelectionColorInactiveWindow = [self colorInGroup:searchResult withKey:@\"selectionColor\" forActiveWindow:NO];\n\tself.searchResultRowEmphasized = [searchResult boolForKey:@\"rowEmphasized\"];\n\tself.searchResultChannelNameTextColor = [self colorInGroup:searchResult withKey:@\"channelNameTextColor\"];\n\tself.searchResultChannelDescriptionTextColor = [self colorInGroup:searchResult withKey:@\"channelDescriptionTextColor\"];\n\tself.searchResultKeyboardShortcutTextColor = [self colorInGroup:searchResult withKey:@\"keyboardShortcutTextColor\"];\n\tself.searchResultKeyboardShortcutDeselectedOffset = [self measurementInGroup:searchResult withKey:@\"keyboardShortcutDeselectedOffset\"];\n\tself.searchResultKeyboardShortcutSelectedOffset = [self measurementInGroup:searchResult withKey:@\"keyboardShortcutSelectedOffset\"];\n\tself.searchResultSelectedTextColor = [self colorInGroup:searchResult withKey:@\"selectedTextColor\"];\n\n\t[self flushAppearanceProperties];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"IRCAddressBookUserTracking.h\"\n#import \"IRCClient.h\"\n#import \"IRCWorld.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TDCChannelSpotlightAppearanceInternal.h\"\n#import \"TDCChannelSpotlightSearchResultPrivate.h\"\n#import \"TDCChannelSpotlightSearchResultsTablePrivate.h\"\n#import \"TDCChannelSpotlightControlsPrivate.h\"\n#import \"TDCChannelSpotlightControllerInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightController () <NSTableViewDataSource, NSTableViewDelegate>\n@property (nonatomic, strong, readwrite) TDCChannelSpotlightAppearance *userInterfaceObjects;\n@property (nonatomic, weak) IBOutlet NSVisualEffectView *visualEffectView;\n@property (nonatomic, weak) IBOutlet NSTextField *noResultsLabel;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *noResultsLabelLeadingConstraint;\n@property (nonatomic, weak) IBOutlet NSView *searchResultsView;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *searchResultsViewHeightConstraint;\n@property (nonatomic, weak) IBOutlet NSTextField *searchField;\n@property (nonatomic, weak) IBOutlet NSTableView *searchResultsTable;\n@property (nonatomic, strong) IBOutlet NSArrayController *searchResultsController;\n@property (nonatomic, strong) id mouseEventMonitor;\n@end\n\n@implementation TDCChannelSpotlightController\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelSpotlightController\" owner:self topLevelObjects:nil];\n\n\tself.searchResultsTable.doubleAction = @selector(delegatePostSelectChannelForDoubleClickedRow:);\n\n\tself.mouseEventMonitor =\n\t[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyDown\n\t\t\t\t\t\t\t\t\t\t  handler:^NSEvent *(NSEvent *event) {\n\t\t\t\t\t\t\t\t\t\t\t  return [self respondToKeyDownEvent:event];\n\t\t\t\t\t\t\t\t\t\t  }];\n\n\tself.searchResultsController.sortDescriptors = @[\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"distance\" ascending:NO selector:@selector(compare:)]\n\t];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(applicationAppearanceChanged:) name:TXApplicationAppearanceChangedNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(channelListChanged:) name:IRCClientChannelListWasModifiedNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(clientListChanged:) name:IRCWorldClientListWasModifiedNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(mainWindowSelectionChanged:) name:TVCMainWindowSelectionChangedNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(preferencesChanged:) name:TPCPreferencesUserDefaultsDidChangeNotification object:nil];\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\t[RZNotificationCenter() addObserver:self selector:@selector(licenseManagerDeactivatedLicense:) name:TDCLicenseManagerDeactivatedLicenseNotification object:nil];\n\t[RZNotificationCenter() addObserver:self selector:@selector(licenseManagerTrialExpired:) name:TDCLicenseManagerTrialExpiredNotification object:nil];\n#endif\n\n\t[self populateArrayController];\n\n\t[self applicationAppearanceChanged];\n\n\t[self.noResultsLabelLeadingConstraint archiveConstant];\n\n\t[self.searchResultsViewHeightConstraint archiveConstant];\n\n\t[self updatePredicate];\n}\n\n#pragma mark -\n#pragma mark Appearance\n\n- (void)applicationAppearanceChanged:(NSNotification *)notification\n{\n\t[self applicationAppearanceChanged];\n}\n\n- (void)applicationAppearanceChanged\n{\n\tTDCChannelSpotlightAppearance *appearance = [[TDCChannelSpotlightAppearance alloc] initWithWindow:(id)self.window];\n\n\tself.userInterfaceObjects = appearance;\n\n\t[self updateVibrancyWithAppearance:appearance];\n\n\t[self updateControlsWithAppearance:appearance];\n\n\t[self updateSearchResultsSelection];\n}\n\n- (void)updateVibrancyWithAppearance:(TDCChannelSpotlightAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tNSAppearance *appKitAppearance = appearance.appKitAppearance;\n\n\tswitch (appearance.appKitAppearanceTarget) {\n\t\tcase TXAppKitAppearanceTargetWindow:\n\t\t{\n\t\t\tself.window.appearance = appKitAppearance;\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n}\n\n- (void)updateControlsWithAppearance:(TDCChannelSpotlightAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tself.searchField.textColor = appearance.searchFieldTextColor;\n\n\tself.noResultsLabel.textColor = appearance.searchFieldNoResultsTextColor;\n}\n\n- (void)updateControlsState\n{\n\tNSString *searchString = self.searchField.stringValue;\n\n\tif (searchString.length == 0) {\n\t\tself.noResultsLabel.stringValue = @\"\";\n\n\t\t[self.noResultsLabelLeadingConstraint zeroOutConstant];\n\n\t\t[self.searchResultsViewHeightConstraint zeroOutConstant];\n\n\t\treturn;\n\t}\n\n\tif (self.searchResultsCount == 0) {\n\t\tself.noResultsLabel.stringValue = TXTLS(@\"TDCChannelSpotlightController[tyv-p6]\");\n\n\t\t[self.noResultsLabelLeadingConstraint restoreArchivedConstant];\n\n\t\t[self.searchResultsViewHeightConstraint zeroOutConstant];\n\n\t\treturn;\n\t}\n\n\tself.noResultsLabel.stringValue = @\"\";\n\n\t[self.noResultsLabelLeadingConstraint zeroOutConstant];\n\n\t[self.searchResultsViewHeightConstraint restoreArchivedConstant];\n\n\t[self selectFirstSearchResultIfNecessary];\n}\n\n- (void)updateSearchResultsSelection\n{\n\tNSTableView *table = self.searchResultsTable;\n\n\t[table invalidateBackgroundForSelection];\n}\n\n#pragma mark -\n#pragma mark Events\n\n- (nullable NSEvent *)respondToKeyDownEvent:(NSEvent *)event\n{\n\tif (self.window.isKeyWindow == NO) {\n\t\treturn event;\n\t}\n\n\tswitch (event.keyCode) {\n\t\tcase 18 ... 23: // 0-9 (top row)\n\t\tcase 25 ... 26:\n\t\tcase 28 ... 29:\n\t\tcase 82 ... 92: // 0-9 (number pad)\n\t\t{\n\t\t\tNSUInteger keyboardKeys = (event.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\t\t\tkeyboardKeys &= ~NSEventModifierFlagNumericPad;\n\n\t\t\tif (keyboardKeys == NSEventModifierFlagCommand) {\n\t\t\t\treturn [self handleCommandNumberEvent:event];\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t\tcase 36: // return\n\t\tcase 76: // enter\n\t\t{\n\t\t\t[self delegatePostSelectChannelForSelectedRow];\n\n\t\t\treturn nil;\n\t\t}\n\t\tcase 53: // escape\n\t\t{\n\t\t\t[self clearSearchStringOrClose];\n\n\t\t\treturn nil;\n\t\t}\n\t\tcase 126: // arrow up\n\t\tcase 125: // arrow down\n\t\tcase 116: // page up\n\t\tcase 121: // page down\n\t\t{\n\t\t\treturn [self handlePageUpDownEvent:event];\n\t\t}\n\t}\n\n\treturn event;\n}\n\n- (nullable NSEvent *)handlePageUpDownEvent:(NSEvent *)event\n{\n\tNSUInteger searchResultsCount = self.searchResultsCount;\n\n\tif (searchResultsCount == 0) {\n\t\treturn nil;\n\t}\n\n\tNSInteger selectedRow = self.searchResultsTable.selectedRow;\n\n\t// Wrap around table when we reach the top or bottom\n\tif (event.keyCode == 126 || event.keyCode == 116) { // up\n\t\tif (selectedRow == 0) {\n\t\t\t[self.searchResultsTable selectItemAtIndex:(searchResultsCount - 1)];\n\n\t\t\treturn nil;\n\t\t}\n\t} else if (event.keyCode == 125 || event.keyCode == 121) { // down\n\t\tif (selectedRow == (searchResultsCount - 1)) {\n\t\t\t[self.searchResultsTable selectItemAtIndex:0];\n\n\t\t\treturn nil;\n\t\t}\n\t}\n\n\t[self.searchResultsTable keyDown:event];\n\n\treturn nil;\n}\n\n- (nullable NSEvent *)handleCommandNumberEvent:(NSEvent *)event\n{\n\t NSInteger numberPressed = event.characters.integerValue;\n\n\tif (numberPressed < 0 || numberPressed > 9) {\n\t\treturn event;\n\t}\n\n\tNSInteger arrayIndex = (numberPressed - 1);\n\n\tif (arrayIndex < 0) {\n\t\tarrayIndex = 9;\n\t}\n\n\t[self delegatePostSelectChannelForSearchResultAtIndex:arrayIndex];\n\n\treturn nil;\n}\n\n- (void)delegatePostSelectChannelForDoubleClickedRow:(id)sender\n{\n\tNSInteger clickedRow = self.searchResultsTable.clickedRow;\n\n\t[self delegatePostSelectChannelForSearchResultAtIndex:clickedRow];\n}\n\n- (void)delegatePostSelectChannelForSelectedRow\n{\n\tNSInteger selectedRow = self.searchResultsTable.selectedRow;\n\n\t[self delegatePostSelectChannelForSearchResultAtIndex:selectedRow];\n}\n\n- (void)delegatePostSelectChannelForSearchResultAtIndex:(NSInteger)searchResultIndex\n{\n\tNSArray<TDCChannelSpotlightSearchResult *> *searchResults = self.searchResultsFiltered;\n\n\tif (searchResultIndex < 0 || searchResultIndex >= searchResults.count) {\n\t\treturn;\n\t}\n\n\tTDCChannelSpotlightSearchResult *searchResult = searchResults[searchResultIndex];\n\n\tIRCChannel *channel = searchResult.channel;\n\n\t[self delegatePostSelectChannel:channel];\n}\n\n- (void)delegatePostSelectChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ([self.delegate respondsToSelector:@selector(channelSpotlightController:selectChannel:)]) {\n\t\t[self.delegate channelSpotlightController:self selectChannel:channel];\n\t}\n\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark Window Management\n\n- (void)clearSearchStringOrClose\n{\n\t/* Mimic Spotlight behavior by clearing search string\n\t on first escape and closing on second escape. */\n\tif (self.searchField.stringValue.length > 0) {\n\t\tself.searchField.stringValue = @\"\";\n\n\t\t[self searchStringChanged];\n\n\t\treturn;\n\t}\n\n\t[self close];\n}\n\n- (void)close\n{\n\t[self saveWindowFrame];\n\n\t[self.window close];\n}\n\n- (void)show\n{\n\t[self restoreWindowFrame];\n\n\t[self.window makeKeyAndOrderFront:nil];\n}\n\n- (void)restoreWindowFrame\n{\n\tNSWindow *window = self.window;\n\n\t[window saveSizeAsDefault];\n\n\t[window restoreWindowStateForClass:self.class];\n}\n\n- (void)saveWindowFrame\n{\n\t/* Reset search back to none before closing so\n\t that the frame we save is same we open. */\n\t[self resetSearch];\n\n\tNSWindow *window = self.window;\n\n\t/* We call -restoreDefaultSizeAndDisplay: before saving\n\t the frame because the window wont register the changes\n\t to the constants in -resetSearch until next layout pass. */\n\t[window restoreDefaultSizeAndDisplay:NO];\n\n\t[window saveWindowStateForClass:self.class];\n}\n\n#pragma mark -\n#pragma mark Search Field\n\n- (NSString *)searchString\n{\n\treturn self.searchField.stringValue;\n}\n\n#pragma mark -\n#pragma mark Search Results\n\n- (void)updatePredicate\n{\n\tif ([TPCPreferences channelNavigationIsServerSpecific]) {\n\t\tNSString *clientId = mainWindow().selectedClient.uniqueIdentifier;\n\n\t\tself.searchResultsController.filterPredicate = [NSPredicate predicateWithFormat:@\"distance >= 0.5 && clientId LIKE[c] %@\", clientId];\n\t} else {\n\t\tself.searchResultsController.filterPredicate = [NSPredicate predicateWithFormat:@\"distance >= 0.5\"];\n\t}\n\n\t[self updateControlsState];\n}\n\n- (void)resetSearch\n{\n\tself.searchField.stringValue = @\"\";\n\n\t[self searchStringChanged];\n}\n\n- (void)selectFirstSearchResultIfNecessary\n{\n\tNSInteger selectedRow = self.searchResultsTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\t[self.searchResultsTable selectItemAtIndex:0];\n\t}\n}\n\n- (NSArray<TDCChannelSpotlightSearchResult *> *)searchResults\n{\n\treturn self.searchResultsController.content;\n}\n\n- (NSArray<TDCChannelSpotlightSearchResult *> *)searchResultsFiltered\n{\n\treturn self.searchResultsController.arrangedObjects;\n}\n\n- (NSUInteger)searchResultsCount\n{\n\treturn ((NSArray *)self.searchResultsController.arrangedObjects).count;\n}\n\n- (NSInteger)selectedSearchResult\n{\n\treturn self.searchResultsTable.selectedRow;\n}\n\n- (void)recalculateDistanceForSearchResults\n{\n\tNSString *searchString = self.searchField.stringValue;\n\n\tNSArray<TDCChannelSpotlightSearchResult *> *searchResults = self.searchResults;\n\n\tfor (TDCChannelSpotlightSearchResult *searchResult in searchResults) {\n\t\t[searchResult recalculateDistanceWith:searchString];\n\t}\n\n\t[self updateControlsState];\n}\n\n- (void)populateArrayController\n{\n\tNSPredicate *filterPredicate = self.searchResultsController.filterPredicate;\n\n\tself.searchResultsController.filterPredicate = nil;\n\n\tNSString *searchString = self.searchField.stringValue;\n\n\tNSMutableArray<TDCChannelSpotlightSearchResult *> *searchResults = [NSMutableArray array];\n\n\tfor (IRCClient *client in worldController().clientList) {\n\t\tfor (IRCChannel *channel in client.channelList) {\n\t\t\tTDCChannelSpotlightSearchResult *searchResult = [self searchResultForChannel:channel];\n\n\t\t\t[searchResult recalculateDistanceWith:searchString];\n\n\t\t\t[searchResults addObject:searchResult];\n\t\t}\n\t}\n\n\t[self.searchResultsController removeAllArrangedObjects];\n\n\t[self.searchResultsController addObjects:searchResults];\n\n\tself.searchResultsController.filterPredicate = filterPredicate;\n}\n\n- (TDCChannelSpotlightSearchResult *)searchResultForChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tTDCChannelSpotlightSearchResult *searchResult = [[TDCChannelSpotlightSearchResult alloc] initWithChannel:channel];\n\n\treturn searchResult;\n}\n\n- (void)searchStringChanged\n{\n\t[self recalculateDistanceForSearchResults];\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (nullable NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row\n{\n\treturn [[TDCChannelSpotlightSearchResultRowView alloc] initWithController:self];\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n- (void)mainWindowSelectionChanged:(NSNotification *)notification\n{\n\t/* Predicate is updated when selection changes because predicate may be configured\n\t to be per-server. This could be made more efficient by checking if it is server\n\t specific and comparing the selected client identifier to what is in predicate.\n\t That involves a lot more work for something that shouldn't be fired a lot. */\n\n\t[self updatePredicate];\n}\n\n- (void)preferencesChanged:(NSNotification *)notification\n{\n\tNSString *changedKey = notification.userInfo[@\"changedKey\"];\n\n\tif ([changedKey isEqualToString:@\"ChannelNavigationIsServerSpecific\"]) {\n\t\t[self updatePredicate];\n\t}\n}\n\n- (void)clientListChanged:(id)sender\n{\n\t[self populateArrayController];\n\n\t[self updateControlsState];\n}\n\n- (void)channelListChanged:(id)sender\n{\n\t[self populateArrayController];\n\n\t[self updateControlsState];\n}\n\n- (void)controlTextDidChange:(NSNotification *)notification\n{\n\tif (notification.object == self.searchField) {\n\t\t[self searchStringChanged];\n\t}\n}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)licenseManagerDeactivatedLicense:(NSNotification *)notification\n{\n\tif (TLOLicenseManagerIsTrialExpired() == NO) {\n\t\treturn;\n\t}\n\n\t[self close];\n}\n\n- (void)licenseManagerTrialExpired:(NSNotification *)notification\n{\n\t[self close];\n}\n#endif\n\n- (void)windowWillClose:(NSNotification *)notification\n{\n\t[NSEvent removeMonitor:self.mouseEventMonitor];\n\n\tself.mouseEventMonitor = nil;\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\tif ([self.delegate respondsToSelector:@selector(channelSpotlightControllerWillClose:)]) {\n\t\t[self.delegate channelSpotlightControllerWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightControls.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCChannelSpotlightControlsPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TDCChannelSpotlightPanel\n\n- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag\n{\n\tif ((self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag])) {\n\t\t[self prepareInitialState];\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\tself.styleMask = (self.styleMask | NSWindowStyleMaskFullSizeContentView);\n\n\tself.titlebarAppearsTransparent = YES;\n\n\tself.titleVisibility = NSWindowTitleHidden;\n\n\t[self standardWindowButton:NSWindowCloseButton].hidden = YES;\n\t[self standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;\n\t[self standardWindowButton:NSWindowZoomButton].hidden = YES;\n}\n\n- (BOOL)isMovable\n{\n\treturn YES;\n}\n\n- (BOOL)isMovableByWindowBackground\n{\n\treturn YES;\n}\n\n- (BOOL)canBecomeKeyWindow\n{\n\treturn YES;\n}\n\n- (BOOL)canBecomeMainWindow\n{\n\treturn YES;\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCChannelSpotlightTextField\n\n- (BOOL)mouseDownCanMoveWindow\n{\n\treturn YES;\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCChannelSpotlightImageView\n\n- (BOOL)mouseDownCanMoveWindow\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightSearchResult.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TDCChannelSpotlightSearchResultPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightSearchResult ()\n@property (nonatomic, weak, readwrite) IRCChannel *channel;\n@property (nonatomic, copy, readwrite) NSNumber *distance;\n@end\n\n@implementation TDCChannelSpotlightSearchResult\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super init])) {\n\t\tself.channel = channel;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.distance = @(0.0);\n}\n\n- (NSComparisonResult)compare:(TDCChannelSpotlightSearchResult *)other\n{\n\tdouble localDistance = self.distance.doubleValue;\n\n\tdouble remoteDistance = other.distance.doubleValue;\n\n\tif (localDistance > remoteDistance) {\n\t\treturn NSOrderedAscending;\n\t} else if (localDistance < remoteDistance) {\n\t\treturn NSOrderedDescending;\n\t}\n\n\treturn NSOrderedSame;\n}\n\n- (void)recalculateDistanceWith:(NSString *)searchString\n{\n\tNSParameterAssert(searchString != nil);\n\n\tif (searchString.length == 0) {\n\t\tself.distance = @(0.0);\n\n\t\treturn;\n\t}\n\n\tNSString *searchableString = self.channel.name;\n\n\tdouble distance = [searchableString compareWithWord:searchString lengthPenaltyWeight:1.0];\n\n\tself.distance = @(distance);\n}\n\n- (NSString *)clientId\n{\n\treturn self.channel.associatedClient.uniqueIdentifier;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Channel Spotlight/TDCChannelSpotlightSearchResultsTable.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXGlobalModels.h\"\n#import \"NSViewHelper.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TDCChannelSpotlightAppearancePrivate.h\"\n#import \"TDCChannelSpotlightControllerInternal.h\"\n#import \"TDCChannelSpotlightSearchResultPrivate.h\"\n#import \"TDCChannelSpotlightSearchResultsTablePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightSearchResultRowView ()\n@property (nonatomic, weak) TDCChannelSpotlightController *controller;\n@property (nonatomic, weak) TDCChannelSpotlightSearchResultCellView *childCell;\n@property (readonly) TDCChannelSpotlightAppearance *userInterfaceObjects;\n@end\n\n@interface TDCChannelSpotlightSearchResultCellView ()\n@property (readonly, copy) NSAttributedString *channelName;\n@property (readonly, copy) NSString *keyboardShortcut;\n@property (readonly, copy) NSString *unreadCountDescription;\n@property (nonatomic, weak) IBOutlet NSTextField *channelNameField;\n@property (nonatomic, weak) IBOutlet NSTextField *keyboardShortcutField;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *keyboardShortcutFieldOffsetConstraint;\n@property (nonatomic, weak) IBOutlet NSTextField *unreadCountDescriptionField;\n@property (nonatomic, assign) BOOL staticLabelsPopulated;\n@property (readonly) TDCChannelSpotlightAppearance *userInterfaceObjects;\n@property (readonly) TDCChannelSpotlightController *controller;\n@property (readonly) TDCChannelSpotlightSearchResultRowView *rowCell;\n@end\n\n@implementation TDCChannelSpotlightSearchResultCellView\n\n- (BOOL)wantsLayer\n{\n\treturn YES;\n}\n\n- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy\n{\n\treturn NSViewLayerContentsRedrawOnSetNeedsDisplay;\n}\n\n- (void)setInitialValues\n{\n\t[self channelNameChanged];\n}\n\n- (void)updateLayer\n{\n\t[self updateAppearance];\n\n\t[self keyboardShortcutChanged];\n}\n\n- (void)updateAppearance\n{\n\tTDCChannelSpotlightSearchResultRowView *rowCell = self.rowCell;\n\n\t[self updateTextFieldTextColorIsSelected:rowCell.isSelected];\n}\n\n- (void)updateTextFieldTextColorIsSelected:(BOOL)isSelected\n{\n\tTDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;\n\t\n\tif (isSelected == NO)\n\t{\n\t\tself.channelNameField.textColor = appearance.searchResultChannelNameTextColor;\n\n\t\tself.unreadCountDescriptionField.textColor = appearance.searchResultChannelDescriptionTextColor;\n\n\t\tself.keyboardShortcutField.textColor = appearance.searchResultKeyboardShortcutTextColor;\n\t\tself.keyboardShortcutFieldOffsetConstraint.constant = appearance.searchResultKeyboardShortcutDeselectedOffset;\n\t}\n\telse\n\t{\n\t\tNSColor *selectedTextColor = appearance.searchResultSelectedTextColor;\n\n\t\tself.channelNameField.textColor = selectedTextColor;\n\n\t\tself.unreadCountDescriptionField.textColor = selectedTextColor;\n\n\t\tself.keyboardShortcutField.textColor = selectedTextColor;\n\t\tself.keyboardShortcutFieldOffsetConstraint.constant = appearance.searchResultKeyboardShortcutSelectedOffset;\n\t}\n}\n\n- (NSAttributedString *)channelName\n{\n\tTDCChannelSpotlightSearchResult *searchResult = self.objectValue;\n\n\tif (searchResult == nil) {\n\t\treturn [NSAttributedString attributedString];\n\t}\n\n\tstatic NSMutableParagraphStyle *paragraphStyle = nil;\n\n\tif (paragraphStyle == nil) {\n\t\tparagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];\n\n\t\tparagraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;\n\t}\n\n\tNSString *channelName = searchResult.channel.name;\n\n\tNSFont *channelNameFieldFont = self.channelNameField.font;\n\n\tNSMutableAttributedString *resultString =\n\t[NSMutableAttributedString\n\t mutableAttributedStringWithString:TXTLS(@\"TDCChannelSpotlightController[jpw-cj]\", channelName)\n\t\t\t\t\t\t\tattributes:@{\n\t\t\t\t\t\t\t\tNSFontAttributeName : channelNameFieldFont,\n\t\t\t\t\t\t\t\tNSParagraphStyleAttributeName : paragraphStyle\n\t\t\t\t\t\t\t}];\n\n\tTDCChannelSpotlightController *controller = self.controller;\n\n\tNSString *searchString = controller.searchString;\n\n\t[resultString.string\n\t enumerateFirstOccurrenceOfCharactersInString:searchString\n\t\t\t\t\t\t\t\t\t\twithBlock:^(NSRange range, BOOL *stop) {\n\t\t\t\t\t\t\t\t\t\t\tNSFont *boldFont = [RZFontManager() convertFont:channelNameFieldFont toHaveTrait:NSBoldFontMask];\n\n\t\t\t\t\t\t\t\t\t\t\t[resultString addAttribute:NSFontAttributeName value:boldFont range:range];\n\t\t\t\t\t\t\t\t\t\t} options:NSCaseInsensitiveSearch];\n\n\tNSString *networkName = searchResult.channel.associatedClient.networkNameAlt;\n\n\t[resultString appendString:TXTLS(@\"TDCChannelSpotlightController[z68-5q]\", networkName)];\n\n\treturn resultString;\n}\n\n- (void)channelNameChanged\n{\n\t[self willChangeValueForKey:@\"channelName\"];\n\t[self didChangeValueForKey:@\"channelName\"];\n}\n\n- (NSString *)keyboardShortcut\n{\n\tTDCChannelSpotlightSearchResult *searchResult = self.objectValue;\n\n\tif (searchResult == nil) {\n\t\treturn @\"\";\n\t}\n\n\tTDCChannelSpotlightController *controller = self.controller;\n\n\tNSArray *searchResults = controller.searchResultsFiltered;\n\n\tNSUInteger searchResultIndex = [searchResults indexOfObjectIdenticalTo:searchResult];\n\n\tif (searchResultIndex == controller.selectedSearchResult) {\n\t\treturn @\"↩︎\";\n\t}\n\n\tif (searchResultIndex > 9) {\n\t\treturn @\"\";\n\t}\n\n\tNSUInteger keyboardShortcutIndex = (searchResultIndex + 1);\n\n\tif (keyboardShortcutIndex == 10) {\n\t\tkeyboardShortcutIndex = 0;\n\t}\n\n\treturn [NSString stringWithFormat:@\"⌘%lu\", keyboardShortcutIndex];\n}\n\n- (void)keyboardShortcutChanged\n{\n\t[self willChangeValueForKey:@\"keyboardShortcut\"];\n\t[self didChangeValueForKey:@\"keyboardShortcut\"];\n}\n\n- (NSString *)unreadCountDescription\n{\n\tTDCChannelSpotlightSearchResult *searchResult = self.objectValue;\n\n\tif (searchResult == nil) {\n\t\treturn @\"\";\n\t}\n\n\tNSUInteger nicknameHighlightCount = searchResult.channel.nicknameHighlightCount;\n\n\tNSString *nicknameHighlightCountDescription = nil;\n\n\tif (nicknameHighlightCount == 1) {\n\t\tnicknameHighlightCountDescription = TXTLS(@\"TDCChannelSpotlightController[0lz-oh]\",TXFormattedNumber(nicknameHighlightCount));\n\t} else {\n\t\tnicknameHighlightCountDescription = TXTLS(@\"TDCChannelSpotlightController[c4u-21]\", TXFormattedNumber(nicknameHighlightCount));\n\t}\n\n\tNSUInteger unreadCount = searchResult.channel.treeUnreadCount;\n\n\tNSString *unreadCountDescription = nil;\n\n\tif (unreadCount == 1) {\n\t\tunreadCountDescription = TXTLS(@\"TDCChannelSpotlightController[43s-x4]\", TXFormattedNumber(unreadCount));\n\t} else {\n\t\tunreadCountDescription = TXTLS(@\"TDCChannelSpotlightController[vzj-30]\", TXFormattedNumber(unreadCount));\n\t}\n\n\treturn TXTLS(@\"TDCChannelSpotlightController[et7-c5]\", nicknameHighlightCountDescription, unreadCountDescription);\n}\n\n- (void)unreadCountDescriptionChanged\n{\n\t[self willChangeValueForKey:@\"unreadCountDescription\"];\n\t[self didChangeValueForKey:@\"unreadCountDescription\"];\n}\n\n- (TDCChannelSpotlightSearchResultRowView *)rowCell\n{\n\treturn (id)self.superview;\n}\n\n- (TDCChannelSpotlightAppearance *)userInterfaceObjects\n{\n\treturn self.rowCell.userInterfaceObjects;\n}\n\n- (TDCChannelSpotlightController *)controller\n{\n\treturn self.rowCell.controller;\n}\n\n- (void)viewDidMoveToWindow\n{\n\t[super viewDidMoveToWindow];\n\n\tTDCChannelSpotlightSearchResult *searchResult = self.objectValue;\n\n\tIRCChannel *channel = searchResult.channel;\n\n\tif (self.window == nil)\n\t{\n\t\t[channel removeObserver:self forKeyPath:@\"nicknameHighlightCount\"];\n\t\t[channel removeObserver:self forKeyPath:@\"treeUnreadCount\"];\n\t}\n\telse\n\t{\n\t\t[channel addObserver:self forKeyPath:@\"nicknameHighlightCount\" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:nil];\n\t\t[channel addObserver:self forKeyPath:@\"treeUnreadCount\" options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:nil];\n\n\t\t[self setInitialValues];\n\t}\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"nicknameHighlightCount\"] ||\n\t\t[keyPath isEqualToString:@\"treeUnreadCount\"])\n\t{\n\t\t[self unreadCountDescriptionChanged];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCChannelSpotlightSearchResultRowView\n\n- (instancetype)initWithController:(TDCChannelSpotlightController *)controller\n{\n\tNSParameterAssert(controller != nil);\n\n\tif ((self = [super initWithFrame:NSZeroRect])) {\n\t\tself.controller = controller;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)setSelected:(BOOL)selected\n{\n\tsuper.selected = selected;\n\n\tif (selected == NO && self.invalidatingBackgroundForSelection) {\n\t\treturn;\n\t}\n\n\t[self setNeedsDisplayOnChild];\n}\n\n- (void)setNeedsDisplayOnChild\n{\n\tself.childCell.needsDisplay = YES;\n}\n\n- (void)drawSelectionInRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tBOOL isWindowActive = self.window.isActiveForDrawing;\n\n\tTDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;\n\n\tNSColor *selectionColor = nil;\n\n\tif (isWindowActive) {\n\t\tselectionColor = appearance.searchResultRowSelectionColorActiveWindow;\n\t} else {\n\t\tselectionColor = appearance.searchResultRowSelectionColorInactiveWindow;\n\t} // isWindowActive\n\n\tif (selectionColor) {\n\t\t[selectionColor set];\n\n\t\tNSRect selectionRect = self.bounds;\n\n\t\tNSRectFill(selectionRect);\n\t} else {\n\t\t[super drawSelectionInRect:dirtyRect];\n\t} // selectionColor\n}\n\n- (BOOL)isEmphasized\n{\n\tTDCChannelSpotlightAppearance *appearance = self.userInterfaceObjects;\n\n\tNSWindow *window = self.window;\n\n\treturn (appearance.searchResultRowEmphasized &&\n\t\t\t(window == nil || window.isKeyWindow));\n}\n\n- (nullable TDCChannelSpotlightSearchResultCellView *)childCell\n{\n\tif (self->_childCell == nil) {\n\t\tif (self.numberOfColumns == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tself->_childCell = [self viewAtColumn:0];\n\t}\n\n\treturn self->_childCell;\n}\n\n- (TDCChannelSpotlightAppearance *)userInterfaceObjects\n{\n\treturn self.controller.userInterfaceObjects;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialog.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TLOInternetAddressLookup.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOTimer.h\"\n#import \"IRCWorld.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TDCFileTransferDialogTableCellPrivate.h\"\n#import \"TDCFileTransferDialogTransferControllerPrivate.h\"\n#import \"TDCFileTransferDialogInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Refuse to have more than X number of items incoming at any given time. */\n#define _addReceiverHardLimit\t\t\t120\n\n@interface TDCFileTransferDialog () <NSMenuItemValidation>\n@property (nonatomic, weak) IBOutlet NSButton *clearButton;\n@property (nonatomic, weak) IBOutlet NSSegmentedCell *navigationControllerCell;\n@property (nonatomic, weak, readwrite) IBOutlet TVCBasicTableView *fileTransferTable;\n@property (nonatomic, strong) IBOutlet NSArrayController *fileTransfersController;\n@property (nonatomic, strong, nullable) TLOInternetAddressLookup *IPAddressRequest;\n@property (readonly) TDCFileTransferDialogSelection navigationSelection;\n@property (nonatomic, strong) TLOTimer *maintenanceTimer;\n@property (nonatomic, copy, nullable) NSURL *downloadDestinationURLPrivate;\n\n- (IBAction)hideWindow:(id)sender;\n\n- (IBAction)clear:(id)sender;\n\n- (IBAction)startTransferOfFile:(id)sender;\n- (IBAction)stopTransferOfFile:(id)sender;\n- (IBAction)removeTransferFromList:(id)sender;\n- (IBAction)openReceivedFile:(id)sender;\n- (IBAction)revealReceivedFileInFinder:(id)sender;\n\n- (IBAction)navigationSelectionDidChange:(id)sender;\n@end\n\n@implementation TDCFileTransferDialog\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCFileTransferDialog\" owner:self topLevelObjects:nil];\n\n\tself.maintenanceTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onMaintenanceTimer];\n\t} onQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(clientWillBeDestroyed:) name:IRCWorldWillDestroyClientNotification object:nil];\n}\n\n- (void)dealloc\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\t[self.maintenanceTimer stop];\n\t self.maintenanceTimer = nil;\n}\n\n- (void)show\n{\n\t[self show:YES restorePosition:YES];\n}\n\n- (void)show:(BOOL)makeKeyWindow\n{\n\t[self show:makeKeyWindow restorePosition:YES];\n}\n\n- (void)show:(BOOL)makeKeyWindow restorePosition:(BOOL)restorePosition\n{\n\tif (makeKeyWindow) {\n\t\t[self.window makeKeyAndOrderFront:nil];\n\t} else {\n\t\t[self.window orderFront:nil];\n\t}\n\n\tif (restorePosition) {\n\t\t[self.window restoreWindowStateForClass:self.class];\n\t}\n}\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingPort:(uint16_t)port\n{\n\tTDCFileTransferDialogTransferController *fileTransfer =\n\t[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {\n\t\treturn (controller.hostPort == port);\n\t}];\n\n\treturn fileTransfer;\n}\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferWithUniqueIdentifier:(NSString *)identifier\n{\n\tNSParameterAssert(identifier != nil);\n\n\tTDCFileTransferDialogTransferController *fileTransfer =\n\t[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {\n\t\treturn [identifier isEqualToString:controller.uniqueIdentifier];\n\t}];\n\n\treturn fileTransfer;\n}\n\n- (BOOL)fileTransferExistsWithToken:(NSString *)transferToken\n{\n\tNSParameterAssert(transferToken != nil);\n\n\tTDCFileTransferDialogTransferController *fileTransfer =\n\t[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {\n\t\treturn [transferToken isEqualToString:controller.transferToken];\n\t}];\n\n\treturn (fileTransfer != nil);\n}\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferSenderMatchingToken:(NSString *)transferToken\n{\n\tNSParameterAssert(transferToken != nil);\n\n\tTDCFileTransferDialogTransferController *fileTransfer =\n\t[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {\n\t\treturn ([transferToken isEqualToString:controller.transferToken] && controller.isSender);\n\t}];\n\n\treturn fileTransfer;\n}\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferReceiverMatchingToken:(NSString *)transferToken\n{\n\tNSParameterAssert(transferToken != nil);\n\n\tTDCFileTransferDialogTransferController *fileTransfer =\n\t[self fileTransferMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *controller) {\n\t\treturn ([transferToken isEqualToString:controller.transferToken] && controller.isSender == NO);\n\t}];\n\n\treturn fileTransfer;\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Stopping access to download destination bookmark\");\n\n\tif (self.downloadDestinationURLPrivate) {\n\t\t[self.downloadDestinationURLPrivate stopAccessingSecurityScopedResource];\n\t}\n\n\tLogToConsoleTerminationProgress(\"Closing file transfer window\");\n\n\t[self close];\n\n\tLogToConsoleTerminationProgress(\"Preparing all file transfers for destruction\");\n\n\t[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\t[fileTransfer prepareForPermanentDestruction];\n\t}];\n}\n\n- (nullable NSString *)addReceiverForClient:(IRCClient *)client nickname:(NSString *)nickname address:(NSString *)hostAddress port:(uint16_t)hostPort filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(hostAddress != nil);\n\tNSParameterAssert(filename != nil);\n\n\t/* A hard limit exists to prevent a bad person continuously sending file transfers \n\t which appear in the file transfer, exhausting resources. */\n\tif ([self receiverCount] > _addReceiverHardLimit) {\n\t\tLogToConsoleError(\"Max receiver count of %{public}i exceeded\", _addReceiverHardLimit);\n\n\t\treturn nil;\n\t}\n\n\tTDCFileTransferDialogTransferController *controller = [TDCFileTransferDialogTransferController receiverForClient:client nickname:nickname address:hostAddress port:hostPort filename:filename filesize:totalFilesize token:transferToken];\n\n\tif (controller == nil) {\n\t\treturn nil;\n\t}\n\n\t[self show:NO restorePosition:NO];\n\n\t[self addFileTransfer:controller];\n\n\tNSString *savePath = self.downloadDestinationURLPrivate.path;\n\n\tif ([TPCPreferences fileTransferRequestReplyAction] == TXFileTransferRequestReplyAutomaticallyDownload) {\n\t\tif (savePath == nil) {\n\t\t\tsavePath = [TPCPathInfo userDownloads];\n\t\t}\n\n\t\t[controller openWithPath:savePath];\n\t}\n\n\treturn controller.uniqueIdentifier;\n}\n\n- (nullable NSString *)addSenderForClient:(IRCClient *)client nickname:(NSString *)nickname path:(NSString *)path autoOpen:(BOOL)autoOpen\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(path != nil);\n\n\tTDCFileTransferDialogTransferController *controller = [TDCFileTransferDialogTransferController senderForClient:client nickname:nickname path:path];\n\n\tif (controller == nil) {\n\t\treturn nil;\n\t}\n\n\t[self show:YES restorePosition:NO];\n\n\t[self addFileTransfer:controller];\n\n\tif (autoOpen) {\n\t\t[controller open];\n\t}\n\n\treturn controller.uniqueIdentifier;\n}\n\n- (void)updateClearButton\n{\n\tNSArray *stoppedFileTransfers = [self stoppedFileTransfers];\n\n\tself.clearButton.enabled = (stoppedFileTransfers.count > 0);\n}\n\n- (void)addFileTransfer:(TDCFileTransferDialogTransferController *)controller\n{\n\t/* Resetting the predicate the each time a controller is added is stupid,\n\t but this is a low frequency task that we can forgive. */\n\tNSPredicate *filterPredicate = self.fileTransfersController.filterPredicate;\n\n\tself.fileTransfersController.filterPredicate = nil;\n\n\t[self.fileTransfersController insertObject:controller atArrangedObjectIndex:0];\n\n\tself.fileTransfersController.filterPredicate = filterPredicate;\n}\n\n- (void)removeFileTransfersMatchingClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tNSArray *fileTransfers = [self fileTransfersMatchingClient:client];\n\n\tif (fileTransfers.count == 0) {\n\t\treturn;\n\t}\n\n\t[fileTransfers makeObjectsPerformSelector:@selector(prepareForPermanentDestruction)];\n\n\t[self.fileTransfersController removeObjects:fileTransfers];\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n- (void)clientWillBeDestroyed:(NSNotification *)notification\n{\n\t[self removeFileTransfersMatchingClient:notification.object];\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (BOOL)validateMenuItem:(NSMenuItem *)item\n{\n\tNSInteger tag = item.tag;\n\n\tNSArray *selectedFileTransfers = [self selectedFileTransfers];\n\n\tif (selectedFileTransfers.count == 0) {\n\t\treturn NO;\n\t}\n\n\t/* Begin actual validation. */\n\tswitch (tag) {\n\t\tcase 3001:\t// Start Download\n\t\t{\n\t\t\tfor (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {\n\t\t\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\t\t\tif (transferStatus == TDCFileTransferDialogTransferStatusStopped ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusRecoverableError)\n\t\t\t\t{\n\t\t\t\t\treturn YES;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t\tcase 3003: // Stop Download\n\t\t{\n\t\t\tfor (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {\n\t\t\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\t\t\tif (transferStatus == TDCFileTransferDialogTransferStatusConnecting ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusReceiving ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusIsListeningAsSender ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusIsListeningAsReceiver ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusSending ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept ||\n\t\t\t\t\ttransferStatus == TDCFileTransferDialogTransferStatusWaitingForResumeAccept)\n\t\t\t\t{\n\t\t\t\t\treturn YES;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t\tcase 3004: // Remove Item\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t\tcase 3005: // Open File\n\t\t{\n\t\t\tfor (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {\n\t\t\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\t\t\tif (fileTransfer.isSender != NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (transferStatus == TDCFileTransferDialogTransferStatusComplete) {\n\t\t\t\t\treturn YES;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t\tcase 3006: // Reveal In Finder\n\t\t{\n\t\t\tfor (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {\n\t\t\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\t\t\tif (fileTransfer.isSender != NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (transferStatus == TDCFileTransferDialogTransferStatusComplete) {\n\t\t\t\t\treturn YES;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn NO; // Default validation to NO.\n}\n\n- (void)clear:(id)sender\n{\n\tNSArray *stoppedFileTransfers = [self stoppedFileTransfers];\n\n\t[stoppedFileTransfers makeObjectsPerformSelector:@selector(prepareForPermanentDestruction)];\n\n\t[self.fileTransfersController removeObjects:stoppedFileTransfers];\n\n\t[self updateClearButton];\n}\n\n- (void)startTransferOfFile:(id)sender\n{\n\tNSString *savePath = self.downloadDestinationURLPrivate.path;\n\n\tNSMutableArray<TDCFileTransferDialogTransferController *> *fileTransfersPending = [NSMutableArray array];\n\n\t/* Open all file transfers who are senders or have a path */\n\t[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {\n\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\tif (transferStatus != TDCFileTransferDialogTransferStatusStopped &&\n\t\t\ttransferStatus != TDCFileTransferDialogTransferStatusRecoverableError)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (fileTransfer.isSender || fileTransfer.path != nil) {\n\t\t\t[fileTransfer open];\n\n\t\t\treturn;\n\t\t} else if (fileTransfer.path == nil && savePath != nil) {\n\t\t\t[fileTransfer openWithPath:savePath];\n\n\t\t\treturn;\n\t\t}\n\n\t\t[fileTransfersPending addObject:fileTransfer];\n\t}];\n\n\t/* If there are file transfers that weren't opened because of a missing\n\t path, then we now prompt the user for where they want to save the files. */\n\tif (fileTransfersPending.count == 0) {\n\t\treturn;\n\t}\n\n\tNSOpenPanel *openDialog = [NSOpenPanel openPanel];\n\n\topenDialog.directoryURL = [TPCPathInfo userDownloadsURL];\n\n\topenDialog.allowsMultipleSelection = NO;\n\topenDialog.canChooseDirectories = YES;\n\topenDialog.canChooseFiles = NO;\n\topenDialog.canCreateDirectories = YES;\n\topenDialog.resolvesAliases = YES;\n\n\topenDialog.message = TXTLS(@\"TDCFileTransferDialog[dcm-w7]\");\n\n\topenDialog.prompt = TXTLS(@\"Prompts[xne-79]\");\n\n\t[openDialog beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {\n\t\tif (result != NSModalResponseOK) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *path = openDialog.URL.path;\n\n\t\tfor (TDCFileTransferDialogTransferController *fileTransfer in fileTransfersPending) {\n\t\t\t[fileTransfer openWithPath:path];\n\t\t}\n\t}];\n}\n\n- (void)stopTransferOfFile:(id)sender\n{\n\t[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {\n\t\t[fileTransfer closeAndPostNotification:NO];\n\t}];\n}\n\n- (void)removeTransferFromList:(id)sender\n{\n\tNSArray *selectedFileTransfers = [self selectedFileTransfers];\n\n\tfor (TDCFileTransferDialogTransferController *fileTransfer in selectedFileTransfers) {\n\t\t[fileTransfer prepareForPermanentDestruction];\n\t}\n\n\t[self.fileTransfersController removeObjects:selectedFileTransfers];\n}\n\n- (void)openReceivedFile:(id)sender\n{\n\t[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {\n\t\tif (fileTransfer.isSender != NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[RZWorkspace() openURL:fileTransfer.fileURL];\n\t}];\n}\n\n- (void)revealReceivedFileInFinder:(id)sender\n{\n\t[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {\n\t\tif (fileTransfer.isSender != NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[RZWorkspace() selectFile:fileTransfer.filePath inFileViewerRootedAtPath:@\"\"];\n\t}];\n}\n\n#pragma mark -\n#pragma mark Timer\n\n- (void)updateMaintenanceTimerOnMainThread\n{\n\tNSArray *activeFileTransfers = [self activeFileTransfers];\n\n\tif (self.maintenanceTimer.timerIsActive) {\n\t\tif (activeFileTransfers.count == 0) {\n\t\t\t[self.maintenanceTimer stop];\n\t\t}\n\t} else {\n\t\tif (activeFileTransfers.count > 0) {\n\t\t\t[self.maintenanceTimer start:1.0 onRepeat:YES];\n\t\t}\n\t}\n}\n\n- (void)updateMaintenanceTimer\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self updateMaintenanceTimerOnMainThread];\n\t});\n}\n\n- (void)onMaintenanceTimer\n{\n\tNSArray *activeFileTransfers = [self activeFileTransfers];\n\n\tfor (TDCFileTransferDialogTransferController *fileTransfer in activeFileTransfers) {\n\t\t[fileTransfer onMaintenanceTimer];\n\t}\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tTDCFileTransferDialogTransferController *fileTransfer = self.fileTransfersController.arrangedObjects[row];\n\n\tTDCFileTransferDialogTableCell *newView =\n\t(TDCFileTransferDialogTableCell *)[tableView makeViewWithIdentifier:@\"GroupView\" owner:self];\n\n\tfileTransfer.transferTableCell = newView;\n\n\treturn newView;\n}\n\n- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row\n{\n\tTDCFileTransferDialogTableCell *tableCell = [tableView viewAtColumn:0 row:row makeIfNecessary:NO];\n\n\t[tableCell prepareInitialState];\n}\n\n#pragma mark -\n#pragma mark Network Information\n\n- (nullable NSString *)IPAddress\n{\n\tif ([TPCPreferences fileTransferIPAddressDetectionMethod] == TXFileTransferIPAddressMethodManual) {\n\t\tNSString *userAddress = [TPCPreferences fileTransferManuallyEnteredIPAddress];\n\n\t\tif (userAddress.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\treturn userAddress;\n\t}\n\n\treturn self->_IPAddress;\n}\n\n- (void)clearIPAddress\n{\n\tself.IPAddress = nil;\n\n\t[self.IPAddressRequest cancelLookup];\n\tself.IPAddressRequest = nil;\n}\n\n- (void)requestIPAddress\n{\n\tif (self.IPAddressRequest != nil) {\n\t\treturn;\n\t}\n\n\tTLOInternetAddressLookup *lookupRequest = [[TLOInternetAddressLookup alloc] initWithDelegate:(id)self];\n\n\t[lookupRequest performLookup];\n\n\tself.IPAddressRequest = lookupRequest;\n}\n\n- (void)internetAddressLookupReturnedAddress:(NSString *)address\n{\n\tself.IPAddress = address;\n\n\t[self enumerateFileTransferSenders:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\tif (fileTransfer.transferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress) {\n\t\t\treturn;\n\t\t}\n\n\t\t[fileTransfer noteIPAddressLookupSucceeded];\n\t}];\n\n\tself.IPAddressRequest = nil;\n}\n\n- (void)internetAddressLookupFailed\n{\n\t[self enumerateFileTransferSenders:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\tif (fileTransfer.transferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress) {\n\t\t\treturn;\n\t\t}\n\n\t\t[fileTransfer noteIPAddressLookupFailed];\n\t}];\n\n\tself.IPAddressRequest = nil;\n}\n\n#pragma mark -\n#pragma mark Navigation\n\n- (TDCFileTransferDialogSelection)navigationSelection\n{\n\treturn self.navigationControllerCell.selectedSegment;\n}\n\n- (void)navigationSelectionDidChange:(id)sender\n{\n\tTDCFileTransferDialogSelection selection = self.navigationSelection;\n\n\tNSPredicate *filterPredicate = nil;\n\n\tif (selection == TDCFileTransferDialogSelectionSending) {\n\t\tfilterPredicate = [NSPredicate predicateWithFormat:@\"isSender == YES\"];\n\t} else if (selection == TDCFileTransferDialogSelectionReceiving) {\n\t\tfilterPredicate = [NSPredicate predicateWithFormat:@\"isSender == NO\"];\n\t}\n\n\tself.fileTransfersController.filterPredicate = filterPredicate;\n}\n\n#pragma mark -\n#pragma mark Transfer Search\n\n- (NSUInteger)receiverCount\n{\n\t__block NSUInteger receiverCount = 0;\n\n\t[self enumerateFileTransferReceivers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\treceiverCount += 1;\n\t}];\n\n\treturn receiverCount;\n}\n\n- (NSArray<TDCFileTransferDialogTransferController *> *)stoppedFileTransfers\n{\n\treturn [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *fileTransfer) {\n\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\tif (transferStatus != TDCFileTransferDialogTransferStatusComplete &&\n\t\t\ttransferStatus != TDCFileTransferDialogTransferStatusStopped &&\n\t\t\ttransferStatus != TDCFileTransferDialogTransferStatusFatalError &&\n\t\t\ttransferStatus != TDCFileTransferDialogTransferStatusRecoverableError)\n\t\t{\n\t\t\treturn NO;\n\t\t}\n\n\t\treturn YES;\n\t}];\n}\n\n- (NSArray<TDCFileTransferDialogTransferController *> *)activeFileTransfers\n{\n\treturn [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController *fileTransfer) {\n\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\tif (transferStatus != TDCFileTransferDialogTransferStatusReceiving &&\n\t\t\ttransferStatus != TDCFileTransferDialogTransferStatusSending)\n\t\t{\n\t\t\treturn NO;\n\t\t}\n\n\t\treturn YES;\n\t}];\n}\n\n- (NSArray<TDCFileTransferDialogTransferController *> *)fileTransfersMatchingCondition:(BOOL (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer))matchCondition\n{\n\tNSMutableArray<TDCFileTransferDialogTransferController *> *fileTransfers = [NSMutableArray array];\n\n\t[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\tif (matchCondition(fileTransfer) == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[fileTransfers addObject:fileTransfer];\n\t}];\n\n\treturn [fileTransfers copy];\n}\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingCondition:(BOOL (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer))matchCondition\n{\n\t__block TDCFileTransferDialogTransferController *fileTransferMatched = nil;\n\n\t[self enumerateFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop) {\n\t\tif (matchCondition(fileTransfer) == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\tfileTransferMatched = fileTransfer;\n\n\t\t*stop = YES;\n\t}];\n\n\treturn fileTransferMatched;\n}\n\n- (NSArray<TDCFileTransferDialogTransferController *> *)selectedFileTransfers\n{\n\tNSMutableArray<TDCFileTransferDialogTransferController *> *selectedFileTransfers = [NSMutableArray array];\n\n\t[self enumerateSelectedFileTransfers:^(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop) {\n\t\t[selectedFileTransfers addObject:fileTransfer];\n\t}];\n\n\treturn [selectedFileTransfers copy];\n}\n\n- (NSArray<TDCFileTransferDialogTransferController *> *)fileTransfersMatchingClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\treturn [self fileTransfersMatchingCondition:^BOOL(TDCFileTransferDialogTransferController * _Nonnull fileTransfer) {\n\t\treturn (fileTransfer.client == client);\n\t}];\n}\n\n- (void)enumerateSelectedFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, NSUInteger index, BOOL *stop))enumerationBlock\n{\n\tNSIndexSet *selectedRows = self.fileTransferTable.selectedRowIndexes;\n\n\t[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\tTDCFileTransferDialogTransferController *fileTransfer = self.fileTransfersController.arrangedObjects[index];\n\n\t\tenumerationBlock(fileTransfer, index, stop);\n\t}];\n}\n\n- (void)enumerateFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock\n{\n\t[self _enumerateFileTransfers:enumerationBlock limitScope:NO limitScopeToSenders:NO];\n}\n\n- (void)enumerateFileTransferReceivers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock\n{\n\t[self _enumerateFileTransfers:enumerationBlock limitScope:YES limitScopeToSenders:NO];\n}\n\n- (void)enumerateFileTransferSenders:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock\n{\n\t[self _enumerateFileTransfers:enumerationBlock limitScope:YES limitScopeToSenders:YES];\n}\n\n- (void)_enumerateFileTransfers:(void (NS_NOESCAPE ^)(TDCFileTransferDialogTransferController *fileTransfer, BOOL *stop))enumerationBlock limitScope:(BOOL)limitScope limitScopeToSenders:(BOOL)limitScopeToSenders\n{\n\tNSParameterAssert(enumerationBlock != nil);\n\n\tfor (TDCFileTransferDialogTransferController *fileTransfer in self.fileTransfersController.arrangedObjects) {\n\t\tif (limitScope && limitScopeToSenders != fileTransfer.isSender) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tBOOL stop = NO;\n\n\t\tenumerationBlock(fileTransfer, &stop);\n\n\t\tif (stop) {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Window Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.window saveWindowStateForClass:self.class];\n}\n\n- (void)hideWindow:(id)sender\n{\n\t[self close];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Destination Folder\n\n@implementation TDCFileTransferDialog (TDCFileTransferDialogDownloadDestinationExtension)\n\n- (nullable NSURL *)downloadDestinationURL\n{\n\treturn self.downloadDestinationURLPrivate;\n}\n\n- (void)startUsingDownloadDestinationURL\n{\n\tNSData *bookmark = [RZUserDefaults() dataForKey:@\"File Transfers -> File Transfer Download Folder Bookmark\"];\n\n\tif (bookmark == nil) {\n\t\treturn;\n\t}\n\n\tBOOL resolvedBookmarkIsStale = YES;\n\n\tNSError *resolvedBookmarkError = nil;\n\n\tNSURL *resolvedBookmark =\n\t[NSURL URLByResolvingBookmarkData:bookmark\n\t\t\t\t\t\t\t  options:NSURLBookmarkResolutionWithSecurityScope\n\t\t\t\t\t\trelativeToURL:nil\n\t\t\t\t  bookmarkDataIsStale:&resolvedBookmarkIsStale\n\t\t\t\t\t\t\t\terror:&resolvedBookmarkError];\n\n\tif (resolvedBookmark == nil) {\n\t\tLogToConsoleError(\"Error creating bookmark for URL: %{public}@\",\n\t\t\t  resolvedBookmarkError.localizedDescription);\n\n\t\treturn;\n\t}\n\n\tself.downloadDestinationURLPrivate = resolvedBookmark;\n\n\tif ([self.downloadDestinationURLPrivate startAccessingSecurityScopedResource] == NO) {\n\t\tLogToConsoleError(\"Failed to access bookmark\");\n\t}\n}\n\n- (void)setDownloadDestinationURL:(nullable NSData *)downloadDestinationURL\n{\n\tif ( self.downloadDestinationURLPrivate) {\n\t\t[self.downloadDestinationURLPrivate stopAccessingSecurityScopedResource];\n\t\t self.downloadDestinationURLPrivate = nil;\n\t}\n\n\t[RZUserDefaults() setObject:downloadDestinationURL forKey:@\"File Transfers -> File Transfer Download Folder Bookmark\"];\n\n\t[self startUsingDownloadDestinationURL];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialogTableCell.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXGlobalModels.h\"\n#import \"TLOLocalization.h\"\n#import \"TDCFileTransferDialogTransferControllerPrivate.h\"\n#import \"TDCFileTransferDialogTableCellPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _filenameFieldWithProgressBarYCord\t\t\t\t4\n#define _filenameFieldWithoutProgressBarYCord\t\t\t12\n\n#define _transferInfoFieldWithProgressBarYCord\t\t\t6\n#define _transferInfoFieldWithoutProgressBarYCord\t\t16\n\n@interface TDCFileTransferDialogTableCell ()\n@property (readonly) TDCFileTransferDialogTransferController *cellItem;\n@property (nonatomic, weak) IBOutlet NSProgressIndicator *progressIndicator;\n@property (nonatomic, weak) IBOutlet NSImageView *fileIconView;\n@property (nonatomic, weak) IBOutlet NSTextField *filenameTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filesizeTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *transferProgressTextField;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *filenameTextFieldConstraint;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *transferProgressTextFieldConstraint;\n@property (readonly) BOOL isReceiving;\n@property (readonly) TDCFileTransferDialogTransferStatus transferStatus;\n@property (readonly) uint64_t processedFilesize;\n@property (readonly) uint64_t totalFilesize;\n@property (readonly) uint64_t currentRecord;\n@property (readonly, copy) NSArray<NSNumber *> *speedRecords;\n@property (readonly, copy, nullable) NSString *errorMessageDescription;\n@property (readonly, copy, nullable) NSString *path;\n@property (readonly, copy) NSString *filename;\n@property (readonly, copy, nullable) NSString *filePath;\n@property (readonly, copy) NSString *hostAddress;\n@property (readonly, copy) NSString *peerNickname;\n@property (readonly) uint16_t hostPort;\n@end\n\n@implementation TDCFileTransferDialogTableCell\n\n#pragma mark -\n#pragma mark Status Information\n\n- (void)prepareInitialState\n{\n\tNSString *filename = self.filename;\n\n\tself.filenameTextField.stringValue = filename;\n\n\tuint64_t totalFilesize = self.totalFilesize;\n\n\tNSString *totalFilesizeString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:totalFilesize];\n\n\tself.filesizeTextField.stringValue = totalFilesizeString;\n\n\tself.progressIndicator.doubleValue = 0;\n\tself.progressIndicator.minValue = 0;\n\tself.progressIndicator.maxValue = totalFilesize;\n\n\tNSImage *iconImage = [RZWorkspace() iconForFileType:filename.pathExtension];\n\n\tself.fileIconView.image = iconImage;\n\n\t[self reloadStatusInformation];\n}\n\n- (void)reloadStatusInformation\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self _reloadStatusInformation];\n\t});\n}\n\n- (void)_reloadStatusInformation\n{\n\tTDCFileTransferDialogTransferStatus transferStatus = self.transferStatus;\n\n\tBOOL transferIsStopped = (transferStatus == TDCFileTransferDialogTransferStatusComplete ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusFatalError ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusRecoverableError ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusStopped ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsSender ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusIsListeningAsReceiver ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusInitializing ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept ||\n\t\t\t\t\t\t\t  transferStatus == TDCFileTransferDialogTransferStatusWaitingForResumeAccept);\n\n\tuint64_t processedFilesize = self.processedFilesize;\n\n\tif (transferIsStopped) {\n\t\tif (self.progressIndicator.hidden == NO) {\n\t\t\tself.progressIndicator.hidden = YES;\n\n\t\t\tself.filenameTextFieldConstraint.constant = _filenameFieldWithoutProgressBarYCord;\n\n\t\t\tself.transferProgressTextFieldConstraint.constant = _transferInfoFieldWithoutProgressBarYCord;\n\n\t\t\t[self layoutSubtreeIfNeeded];\n\t\t}\n\t} else {\n\t\tif (self.progressIndicator.hidden) {\n\t\t\tself.progressIndicator.hidden = NO;\n\n\t\t\tself.filenameTextFieldConstraint.constant = _filenameFieldWithProgressBarYCord;\n\n\t\t\tself.transferProgressTextFieldConstraint.constant = _transferInfoFieldWithProgressBarYCord;\n\n\t\t\t[self layoutSubtreeIfNeeded];\n\t\t}\n\t}\n\n\tif (transferIsStopped == NO) {\n\t\tif (transferStatus == TDCFileTransferDialogTransferStatusConnecting) {\n\t\t\tself.progressIndicator.indeterminate = YES;\n\n\t\t\t[self.progressIndicator startAnimation:nil];\n\t\t} else {\n\t\t\tself.progressIndicator.indeterminate = NO;\n\n\t\t\tself.progressIndicator.doubleValue = self.processedFilesize;\n\t\t}\n\t}\n\n\tswitch (transferStatus) {\n\t\tcase TDCFileTransferDialogTransferStatusStopped:\n\t\t{\n\t\t\tif (self.isReceiving) {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[jvh-u7]\", self.peerNickname);\n\t\t\t} else {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[w3h-p8]\", self.peerNickname);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusMappingListeningPort:\n\t\t{\n\t\t\tif (self.isReceiving) {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[495-90]\", self.peerNickname);\n\t\t\t} else {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[j1z-88]\", self.peerNickname);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress:\n\t\t{\n\t\t\tif (self.isReceiving) {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[6t1-mb]\", self.peerNickname);\n\t\t\t} else {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[onl-av]\", self.peerNickname);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusInitializing:\n\t\t{\n\t\t\tif (self.isReceiving) {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[42z-mg]\", self.peerNickname);\n\t\t\t} else {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[pcv-kg]\", self.peerNickname);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusIsListeningAsSender:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[ca5-2v]\", self.peerNickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusIsListeningAsReceiver:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[pip-z6]\", self.peerNickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusFatalError:\n\t\tcase TDCFileTransferDialogTransferStatusRecoverableError:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = self.errorMessageDescription;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusComplete:\n\t\t{\n\t\t\tif (self.isReceiving) {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[6gu-za]\", self.peerNickname);\n\t\t\t} else {\n\t\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[rx7-xy]\", self.peerNickname);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusSending:\n\t\tcase TDCFileTransferDialogTransferStatusReceiving:\n\t\t{\n\t\t\t/* Format time remaining */\n\t\t\tNSTimeInterval timeRemaining = 0;\n\n\t\t\tNSString *timeRemainingString = nil;\n\n\t\t\tuint64_t currentSpeed = self.currentSpeed;\n\n\t\t\tif (currentSpeed > 0) {\n\t\t\t\ttimeRemaining = ((self.totalFilesize - processedFilesize) / currentSpeed);\n\n\t\t\t\tif (timeRemaining > 0) {\n\t\t\t\t\ttimeRemainingString = TXHumanReadableTimeInterval(timeRemaining, YES, (NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Update status */\n\t\t\tNSString *totalFilesizeString = self.filesizeTextField.stringValue;\n\n\t\t\tNSString *currentSpeedString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:currentSpeed];\n\t\t\tNSString *processedFilesizeString = [NSByteCountFormatter stringFromByteCountWithPaddedDigits:processedFilesize];\n\n\t\t\tNSString *statusString = nil;\n\n\t\t\tif (self.isReceiving) {\n\t\t\t\tif (timeRemainingString) {\n\t\t\t\t\tstatusString = TXTLS(@\"TDCFileTransferDialog[9xn-7j]\", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname, timeRemainingString);\n\t\t\t\t} else {\n\t\t\t\t\tstatusString = TXTLS(@\"TDCFileTransferDialog[7dk-lp]\", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (timeRemainingString) {\n\t\t\t\t\tstatusString = TXTLS(@\"TDCFileTransferDialog[u17-ql]\", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname, timeRemainingString);\n\t\t\t\t} else {\n\t\t\t\t\tstatusString = TXTLS(@\"TDCFileTransferDialog[nvm-nd]\", processedFilesizeString, totalFilesizeString, currentSpeedString, self.peerNickname);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tself.transferProgressTextField.stringValue = statusString;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusConnecting:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[7nf-fr]\", self.peerNickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[cku-24]\", self.peerNickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCFileTransferDialogTransferStatusWaitingForResumeAccept:\n\t\t{\n\t\t\tself.transferProgressTextField.stringValue = TXTLS(@\"TDCFileTransferDialog[gxq-zu]\", self.peerNickname);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* Update clear button */\n\t[self updateClearButton];\n}\n\n#pragma mark -\n#pragma mark Proxy Methods\n\n- (void)updateClearButton\n{\n\t[self.cellItem updateClearButton];\n}\n\n- (void)onMaintenanceTimer\n{\n\t[self.cellItem onMaintenanceTimer];\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (TDCFileTransferDialogTransferController *)cellItem\n{\n\treturn self.objectValue;\n}\n\n- (TDCFileTransferDialogTransferStatus)transferStatus\n{\n\treturn self.cellItem.transferStatus;\n}\n\n- (BOOL)isReceiving\n{\n\treturn (self.cellItem.isSender == NO);\n}\n\n- (nullable NSString *)path\n{\n\treturn self.cellItem.path;\n}\n\n- (NSString *)filename\n{\n\treturn self.cellItem.filename;\n}\n\n- (nullable NSString *)filePath\n{\n\treturn self.cellItem.filePath;\n}\n\n- (NSString *)peerNickname\n{\n\treturn self.cellItem.peerNickname;\n}\n\n- (nullable NSString *)errorMessageDescription\n{\n\treturn self.cellItem.errorMessageDescription;\n}\n\n- (NSString *)hostAddress\n{\n\treturn self.cellItem.hostAddress;\n}\n\n- (uint16_t)hostPort\n{\n\treturn self.cellItem.hostPort;\n}\n\n- (uint64_t)totalFilesize\n{\n\treturn self.cellItem.totalFilesize;\n}\n\n- (uint64_t)processedFilesize\n{\n\treturn self.cellItem.processedFilesize;\n}\n\n- (uint64_t)currentRecord\n{\n\treturn self.cellItem.currentRecord;\n}\n\n- (uint64_t)currentSpeed\n{\n\tNSArray *speedRecords = self.speedRecords;\n\n\tif (speedRecords.count == 0) {\n\t\treturn 0;\n\t}\n\n\tuint64_t totalTransferred = 0;\n\n\tfor (NSNumber *record in speedRecords) {\n\t\ttotalTransferred += record.unsignedLongLongValue;\n\t}\n\n\treturn (totalTransferred / speedRecords.count);\n}\n\n- (NSArray<NSNumber *> *)speedRecords\n{\n\treturn self.cellItem.speedRecords;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/File Transfers/TDCFileTransferDialogTransferController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"GCDAsyncSocket.h\"\n#import \"TXGlobalModels.h\"\n#import \"IRCClientPrivate.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TDCFileTransferDialogTableCellPrivate.h\"\n#import \"TDCFileTransferDialogTransferControllerPrivate.h\"\n#import \"TDCFileTransferDialogInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define RECORDS_LENGTH  10\n#define MAX_QUEUE_SIZE  2\n#define BUFFER_SIZE\t (1024 * 64)\n#define RATE_LIMIT\t  (1024 * 1024 * 10)\n\n#define _connectTimeout\t\t\t30.0\n#define _sendDataTimeout\t\t30.0\n#define _resumeAcceptTimeout\t10.0\n\n@interface TDCFileTransferDialogTransferController ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, assign, readwrite) BOOL isResume;\n@property (nonatomic, assign, readwrite) BOOL isReversed;\n@property (nonatomic, assign, readwrite) BOOL isSender;\n@property (nonatomic, assign, readwrite) TDCFileTransferDialogTransferStatus transferStatus;\n@property (nonatomic, assign, readwrite) uint64_t totalFilesize;\n@property (nonatomic, assign, readwrite) uint64_t processedFilesize;\n@property (nonatomic, assign, readwrite) uint64_t currentRecord;\n@property (nonatomic, strong) NSMutableArray<NSNumber *> *speedRecordsPrivate;\n@property (nonatomic, copy, readwrite, nullable) NSString *errorMessageDescription;\n@property (nonatomic, copy, readwrite, nullable) NSString *path;\n@property (nonatomic, copy, readwrite) NSString *filename;\n@property (nonatomic, copy, readwrite) NSString *hostAddress;\n@property (nonatomic, copy, readwrite) NSString *peerNickname;\n@property (nonatomic, copy, readwrite, nullable) NSString *transferToken;\n@property (nonatomic, copy, readwrite) NSString *uniqueIdentifier;\n@property (nonatomic, assign, readwrite) uint16_t hostPort;\n@property (nonatomic, strong, nullable) NSFileHandle *fileHandle;\n@property (nonatomic, strong, nullable) XRPortMapper *portMapping;\n@property (nonatomic, assign) NSUInteger sendQueueSize;\n@property (nonatomic, strong, nullable) dispatch_queue_t serverDispatchQueue;\n@property (nonatomic, strong, nullable) dispatch_queue_t serverSocketQueue;\n@property (nonatomic, strong, nullable) GCDAsyncSocket *listeningServer;\n@property (nonatomic, strong, nullable) GCDAsyncSocket *listeningServerConnectedClient;\n@property (nonatomic, strong, nullable) GCDAsyncSocket *connectionToRemoteServer;\n@property (nonatomic, strong, nullable) id transferProgressHandler; // Used to prevent system sleep\n@property (readonly) uint64_t currentFilesize;\n@property (readonly) TDCFileTransferDialog *transferDialog;\n@property (readonly, nullable) GCDAsyncSocket *readSocket;\n@property (readonly, nullable) GCDAsyncSocket *writeSocket;\n@end\n\n@implementation TDCFileTransferDialogTransferController\n\n#pragma mark -\n#pragma mark Initialization\n\n+ (nullable instancetype)receiverForClient:(IRCClient *)client nickname:(NSString *)nickname address:(NSString *)hostAddress port:(uint16_t)hostPort filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(hostAddress != nil);\n\tNSParameterAssert(filename != nil);\n\n\t/* Construct controller */\n\tTDCFileTransferDialogTransferController *controller = [[self alloc] initWithClient:client];\n\n\tif (transferToken.length > 0) {\n\t\tcontroller.transferToken = transferToken;\n\n\t\tcontroller.isReversed = YES;\n\t}\n\n\tcontroller.isSender = NO;\n\n\tcontroller.peerNickname = nickname;\n\n\tcontroller.hostAddress = hostAddress;\n\tcontroller.hostPort = hostPort;\n\n\tcontroller.filename = filename;\n\n\tcontroller.totalFilesize = totalFilesize;\n\n\treturn controller;\n}\n\n+ (nullable instancetype)senderForClient:(IRCClient *)client nickname:(NSString *)nickname path:(NSString *)path\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(path != nil);\n\n\tNSString *filename = path.lastPathComponent;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tif ([TPCPreferences textEncryptionIsEnabled]) {\n\t\t/* Ask whether we should be allowed to add the file. */\n\t\tBOOL allowWithOTR = [sharedEncryptionManager()\n\t\t\t\t\t\t\t safeToTransferFile:filename\n\t\t\t\t\t\t\t\t\t\t\t to:[client encryptionAccountNameForUser:nickname]\n\t\t\t\t\t\t\t\t\t\t   from:[client encryptionAccountNameForLocalUser]\n\t\t\t\t\t\t isIncomingFileTransfer:NO];\n\n\t\tif (allowWithOTR == NO) {\n\t\t\treturn nil; // This operation is not allowed...\n\t\t}\n\t}\n#endif\n\n\t/* Gather file information */\n\tNSDictionary *fileAttributes = [RZFileManager() attributesOfItemAtPath:path error:NULL];\n\n\tif (fileAttributes == nil) {\n\t\treturn nil;\n\t}\n\n\tuint64_t totalFilesize = [fileAttributes fileSize];\n\n\tif (totalFilesize == 0) {\n\t\tLogToConsoleError(\"Fatal error: Cannot create sender because filesize == 0\");\n\n\t\treturn nil;\n\t}\n\n\tNSString *filePath = path.stringByDeletingLastPathComponent;\n\n\t/* Construct controller */\n\tTDCFileTransferDialogTransferController *controller = [[self alloc] initWithClient:client];\n\n\tcontroller.isReversed = [TPCPreferences fileTransferRequestsAreReversed];\n\n\tcontroller.isSender = YES;\n\n\tcontroller.peerNickname = nickname;\n\n\tcontroller.path = filePath;\n\tcontroller.filename = filename;\n\n\tcontroller.totalFilesize = totalFilesize;\n\n\treturn controller;\n}\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.speedRecordsPrivate = [NSMutableArray array];\n\n\tself.transferStatus = TDCFileTransferDialogTransferStatusStopped;\n\n\tself.uniqueIdentifier = [NSString stringWithUUID];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(clientDisconnected:) name:IRCClientDidDisconnectNotification object:self.client];\n\t[RZNotificationCenter() addObserver:self selector:@selector(peerNicknameChanged:) name:IRCClientUserNicknameChangedNotification object:self.client];\n}\n\n- (void)prepareForPermanentDestruction\n{\n\tself.transferTableCell = nil;\n\n\t[self closeAndPostNotification:NO];\n\n\t[RZNotificationCenter() removeObserver:self];\n}\n\n#pragma mark -\n#pragma mark Error Handling\n\n- (void)failWithNoSpaceLeftOnDevice\n{\n\t[self closeWithLocalizedError:TXTLS(@\"TDCFileTransferDialog[79f-s0]\")];\n}\n\n- (void)closeWithLocalizedError:(NSString *)errorLocalization\n{\n\t[self closeWithLocalizedError:errorLocalization description:nil isFatalError:NO];\n}\n\n- (void)closeWithLocalizedError:(NSString *)errorLocalization isFatalError:(BOOL)isFatalError\n{\n\t[self closeWithLocalizedError:errorLocalization description:nil isFatalError:isFatalError];\n}\n\n- (void)closeWithLocalizedError:(NSString *)errorLocalization description:(nullable NSString *)errorDescription\n{\n\t[self closeWithLocalizedError:errorLocalization description:errorDescription isFatalError:NO];\n}\n\n- (void)closeWithLocalizedError:(NSString *)errorLocalization description:(nullable NSString *)errorDescription isFatalError:(BOOL)isFatalError\n{\n\tNSParameterAssert(errorLocalization != nil);\n\n\tif (errorDescription == nil) {\n\t\tself.errorMessageDescription = TXTLS(errorLocalization, self.peerNickname);\n\t} else {\n\t\tself.errorMessageDescription = TXTLS(errorLocalization, self.peerNickname, errorDescription);\n\t}\n\n\tif (isFatalError) {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusFatalError;\n\t} else {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusRecoverableError;\n\t}\n\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark Dispatch Queue Management\n\n- (void)createDispatchQueues\n{\n\tNSString *uniqueId = [NSString stringWithUUID];\n\n\tNSString *dispatchQueueName = [NSString stringWithFormat:@\"Textual.TDCFileTransferDialogTransferController.DCC-SocketDispatchQueue-%@\", uniqueId];\n\n\tself.serverDispatchQueue =\n\tXRCreateDispatchQueueWithPriority(dispatchQueueName.UTF8String, DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);\n\n\tNSString *socketQueueName = [NSString stringWithFormat:@\"Textual.TDCFileTransferDialogTransferController.DCC-SocketReadWriteQueue-%@\", uniqueId];\n\n\tself.serverSocketQueue =\n\tXRCreateDispatchQueueWithPriority(socketQueueName.UTF8String, DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);\n}\n\n- (void)destroyDispatchQueues\n{\n\tself.serverDispatchQueue = nil;\n\n\tself.serverSocketQueue = nil;\n}\n\n#pragma mark -\n#pragma mark Opening/Closing Transfer\n\n- (void)disableSystemSleep\n{\n\tself.transferProgressHandler = [RZProcessInfo() beginActivityWithOptions:NSActivityUserInitiated reason:@\"Transferring file\"];\n}\n\n- (void)enableSystemSleep\n{\n\tif (self.transferProgressHandler == nil) {\n\t\treturn;\n\t}\n\n\t[RZProcessInfo() endActivity:self.transferProgressHandler];\n\n\tself.transferProgressHandler = nil;\n}\n\n- (BOOL)receiveUnencryptedFile\n{\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tif ([TPCPreferences textEncryptionIsEnabled]) {\n\t\tBOOL allowWithOTR = [sharedEncryptionManager()\n\t\t\t\t\t\t\t safeToTransferFile:self.filename\n\t\t\t\t\t\t\t\t\t\t\t to:[self.client encryptionAccountNameForUser:self.peerNickname]\n\t\t\t\t\t\t\t\t\t\t   from:[self.client encryptionAccountNameForLocalUser]\n\t\t\t\t\t\t isIncomingFileTransfer:YES];\n\n\t\tif (allowWithOTR == NO) {\n\t\t\treturn NO; // This operation is not allowed...\n\t\t}\n\t}\n#endif\n\n\treturn YES;\n}\n\n- (void)open\n{\n\t[self openWithPath:nil];\n}\n\n- (void)openWithPathOrUserDownloads\n{\n\tNSString *path = nil;\n\n\tif (self.path == nil) {\n\t\tpath = [TPCPathInfo userDownloads];\n\t}\n\n\t[self openWithPath:path];\n}\n\n- (void)openWithPath:(nullable NSString *)path\n{\n\tif (self.path == nil) {\n\t\tself.path = path;\n\t}\n\n\tif (self.client.isLoggedIn == NO) {\n\t\t[self _closeWithClientDisconnectedError];\n\n\t\treturn;\n\t}\n\n\tif (self.isSender) {\n\t\t[self openTransfer];\n\t} else {\n\t\tif ([self receiveUnencryptedFile] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self sendTransferResumeRequestToClient];\n\t}\n}\n\n- (void)openTransfer\n{\n\tif (self.isSender) {\n\t\tif (self.isReversed) {\n\t\t\t[self updateIPAddress];\n\t\t} else {\n\t\t\t[self openConnectionAsServer];\n\t\t}\n\t} else {\n\t\tif (self.isReversed) {\n\t\t\t[self openConnectionAsServer];\n\t\t} else {\n\t\t\t[self openConnectionToHost];\n\t\t}\n\t}\n}\n\n- (void)openConnectionToHost\n{\n\t[self closeAndPostNotification:NO];\n\n\t[self resetProperties];\n\n\t[self createDispatchQueues];\n\n\tself.transferStatus = TDCFileTransferDialogTransferStatusConnecting;\n\n\tGCDAsyncSocket *connectionToRemoteServer =\n\t[[GCDAsyncSocket alloc] initWithDelegate:(id)self\n\t\t\t\t\t\t\t   delegateQueue:self.serverDispatchQueue\n\t\t\t\t\t\t\t\t socketQueue:self.serverSocketQueue];\n\n\tNSError *connectionError = nil;\n\n\tBOOL isConnected = NO;\n\n\t/* Use the interface of the configured IP address instead of the default. */\n\t/* Default interface is used if IP address is not found locally. */\n\tNSString *networkInterface = [self networkInterfaceMatchingAddress];\n\n\tif (networkInterface) {\n\t\tisConnected = [connectionToRemoteServer connectToHost:self.hostAddress onPort:self.hostPort viaInterface:networkInterface withTimeout:_connectTimeout error:&connectionError];\n\t} else {\n\t\tisConnected = [connectionToRemoteServer connectToHost:self.hostAddress onPort:self.hostPort withTimeout:_connectTimeout error:&connectionError];\n\t}\n\n\tif (isConnected == NO) {\n\t\tif (connectionError) {\n\t\t\tLogToConsoleError(\"DCC Connect Error: %{public}@\", connectionError.localizedDescription);\n\t\t}\n\n\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[fn8-sx]\"];\n\n\t\treturn;\n\t}\n\n\tself.connectionToRemoteServer = connectionToRemoteServer;\n\n\t[self disableSystemSleep];\n}\n\n- (void)openConnectionAsServer\n{\n\t[self closeAndPostNotification:NO];\n\n\t[self resetProperties];\n\n\t[self createDispatchQueues];\n\n\tself.transferStatus = TDCFileTransferDialogTransferStatusInitializing;\n\n\tself.hostPort = [TPCPreferences fileTransferPortRangeStart];\n\n\twhile ([self tryToOpenConnectionAsServer] == NO) {\n\t\tself.hostPort += 1;\n\n\t\tif (self.hostPort > [TPCPreferences fileTransferPortRangeEnd]) {\n\t\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[vxc-sd]\"];\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t[self disableSystemSleep];\n}\n\n- (BOOL)tryToOpenConnectionAsServer\n{\n\tGCDAsyncSocket *listeningServer =\n\t[[GCDAsyncSocket alloc] initWithDelegate:(id)self\n\t\t\t\t\t\t\t   delegateQueue:self.serverDispatchQueue\n\t\t\t\t\t\t\t\t socketQueue:self.serverSocketQueue];\n\n\tBOOL isActive = [listeningServer acceptOnPort:self.hostPort error:NULL];\n\n\tif (isActive == NO) {\n\t\treturn NO;\n\t}\n\n\tself.listeningServer = listeningServer;\n\n\t/* Try to map the port */\n\tXRPortMapper *portMapping = [[XRPortMapper alloc] initWithPort:self.hostPort];\n\n\tportMapping.mapTCP = YES;\n\tportMapping.mapUDP = NO;\n\n\tportMapping.desiredPublicPort = self.hostPort;\n\n\tself.portMapping = portMapping;\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(portMapperDidFinishWork:) name:XRPortMapperDidChangedNotification object:self.portMapping];\n\n\tself.transferStatus = TDCFileTransferDialogTransferStatusMappingListeningPort;\n\n\tif ([self.portMapping open] == NO) {\n\t\t[self portMapperDidFinishWork:nil];\n\t}\n\n\treturn YES;\n}\n\n- (nullable NSString *)networkInterfaceMatchingAddress\n{\n\treturn [TPCPreferences fileTransferIPAddressInterfaceName];\n}\n\n- (void)portMapperDidFinishWork:(NSNotification *)aNotification\n{\n\tNSAssertReturn(self.transferStatus == TDCFileTransferDialogTransferStatusMappingListeningPort);\n\n\tif (self.portMapping.isMapped) {\n\t\t[self updateIPAddress];\n\n\t\tLogToConsoleInfo(\"Successful port mapping on port %{public}hu\", self.hostPort);\n\n\t\treturn;\n\t}\n\n\tLogToConsoleError(\"Port mapping failed with error code: %{public}i\", self.portMapping.error);\n\n\tif (self.isReversed) {\n\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[vxc-sd]\"];\n\n\t\treturn;\n\t}\n\n\t/* If mapping fails, we silently fail */\n\t/* We tried and it was successful, then that is good, but if we\n\t did not, still start listening just incase other conditions allow\n\t the transfer to still take place. */\n\t[self updateIPAddress];\n}\n\n- (void)updateIPAddress\n{\n\tLogStackTraceWithType(LogToConsoleTypeDebug);\n\n\tNSString *address = self.transferDialog.IPAddress;\n\n\tLogToConsoleDebug(\"TDCFileTransferDialog cached IP address: %{private}@\", address);\n\n\tTXFileTransferIPAddressMethodDetection detectionMethod = [TPCPreferences fileTransferIPAddressDetectionMethod];\n\t\n\tBOOL manuallyDetect = (detectionMethod == TXFileTransferIPAddressMethodManual);\n\t\n\tif (address == nil && manuallyDetect == NO) {\n\t\tNSString *publicAddress = self.portMapping.publicAddress;\n\n\t\tLogToConsoleDebug(\"Port mapper public IP address: %{private}@\", publicAddress);\n\n\t\tif (publicAddress.isIPAddress) {\n\t\t\tself.transferDialog.IPAddress = publicAddress;\n\n\t\t\taddress = publicAddress;\n\t\t}\n\t}\n\n\t/* Request address? */\n\tif (address == nil) {\n\t\tif (manuallyDetect || detectionMethod == TXFileTransferIPAddressMethodRouterOnly) {\n\t\t\tLogToConsoleError(\"User has set IP address detection to be manual but have no address set\");\n\n\t\t\t[self noteIPAddressLookupFailed];\n\t\t} else {\n\t\t\tLogToConsoleDebug(\"Performing IP address lookup using the Internet\");\n\n\t\t\t[self.transferDialog requestIPAddress];\n\n\t\t\tself.transferStatus = TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress;\n\t\t}\n\n\t\treturn;\n\t}\n\n\t[self noteIPAddressLookupSucceeded];\n}\n\n- (void)closePortMapping\n{\n\tif (self.portMapping == nil) {\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() removeObserver:self name:XRPortMapperDidChangedNotification object:self.portMapping];\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self.portMapping close];\n\n\t\tself.portMapping = nil;\n\t});\n}\n\n- (void)noteIPAddressLookupSucceeded\n{\n\tLogStackTraceWithType(LogToConsoleTypeDebug);\n\n\tif (self.isSender) {\n\t\tif (self.isReversed) {\n\t\t\tself.transferStatus = TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept;\n\t\t} else {\n\t\t\tself.transferStatus = TDCFileTransferDialogTransferStatusIsListeningAsSender;\n\t\t}\n\t} else {\n\t\tif (self.isReversed) {\n\t\t\tself.transferStatus = TDCFileTransferDialogTransferStatusIsListeningAsReceiver;\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t[self sendTransferRequestToClient];\n}\n\n- (void)noteIPAddressLookupFailed\n{\n\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[47s-1s]\"];\n}\n\n- (void)didReceiveResumeRequest:(uint64_t)proposedPosition\n{\n\tuint64_t currentFilesize = self.currentFilesize;\n\n\tif (proposedPosition == 0 || currentFilesize < proposedPosition) {\n\t\treturn;\n\t}\n\n\tself.isResume = YES;\n\n\tself.processedFilesize = proposedPosition;\n\n\t[self sendTransferResumeAcceptToClient];\n}\n\n- (void)didReceiveResumeAccept:(uint64_t)proposedPosition\n{\n\t[self cancelPerformRequestsWithSelector:@selector(transferResumeRequestTimeout) object:nil];\n\n\tuint64_t currentFilesize = self.currentFilesize;\n\n\tif (currentFilesize != proposedPosition) {\n\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[0ov-tr]\" isFatalError:YES];\n\n\t\treturn;\n\t}\n\n\tself.isResume = YES;\n\n\tself.processedFilesize = currentFilesize;\n\n\t[self openTransfer];\n}\n\n- (void)didReceiveSendRequest:(NSString *)hostAddress hostPort:(uint16_t)hostPort\n{\n\tNSParameterAssert(hostAddress != nil);\n\n\tself.hostAddress = hostAddress;\n\n\tself.hostPort = hostPort;\n\n\tself.processedFilesize = 0;\n\n\t[self openConnectionToHost];\n}\n\n- (void)buildTransferToken\n{\n\tNSUInteger loopedCount = 0;\n\n\tdo {\n\t\tNSString *transferToken = [NSString stringWithUnsignedInteger:TXRandomNumber(9999)];\n\n\t\tBOOL transferExists = [self.transferDialog fileTransferExistsWithToken:transferToken];\n\n\t\tif (transferExists == NO) {\n\t\t\tself.transferToken = transferToken;\n\n\t\t\tbreak;\n\t\t}\n\n\t\tloopedCount += 1;\n\t} while (loopedCount < 300);\n}\n\n- (void)sendTransferRequestToClient\n{\n\tif (self.isSender) {\n\t\tuint64_t currentFilesize = self.currentFilesize;\n\n\t\tif (self.isReversed) {\n\t\t\t[self buildTransferToken];\n\n\t\t\t[self.client sendFile:self.peerNickname port:0 filename:self.filename filesize:currentFilesize token:self.transferToken];\n\t\t} else {\n\t\t\t[self.client sendFile:self.peerNickname port:self.hostPort filename:self.filename filesize:currentFilesize token:nil];\n\t\t}\n\t} else {\n\t\tif (self.isReversed) {\n\t\t\t[self.client sendFile:self.peerNickname port:self.hostPort filename:self.filename filesize:self.totalFilesize token:self.transferToken];\n\t\t}\n\t}\n}\n\n- (void)sendTransferResumeRequestToClient\n{\n\tuint64_t currentFilesize = self.currentFilesize;\n\n\tif (currentFilesize == 0 || currentFilesize > self.totalFilesize) {\n\t\t[self transferResumeRequestTimeout];\n\n\t\treturn;\n\t}\n\n\t[self performSelectorInCommonModes:@selector(transferResumeRequestTimeout) withObject:nil afterDelay:_resumeAcceptTimeout];\n\n\tself.transferStatus = TDCFileTransferDialogTransferStatusWaitingForResumeAccept;\n\n\tif (self.isReversed) {\n\t\t[self.client sendFileResume:self.peerNickname port:0 filename:self.filename filesize:currentFilesize token:self.transferToken];\n\t} else {\n\t\t[self.client sendFileResume:self.peerNickname port:self.hostPort filename:self.filename filesize:currentFilesize token:nil];\n\t}\n}\n\n- (void)sendTransferResumeAcceptToClient\n{\n\tif (self.isReversed) {\n\t\t[self.client sendFileResumeAccept:self.peerNickname port:0 filename:self.filename filesize:self.processedFilesize token:self.transferToken];\n\t} else {\n\t\t[self.client sendFileResumeAccept:self.peerNickname port:self.hostPort filename:self.filename filesize:self.processedFilesize token:nil];\n\t}\n}\n\n- (void)transferResumeRequestTimeout\n{\n\t[self openTransfer];\n}\n\n- (void)peerNicknameChanged:(NSNotification *)notification\n{\n\tNSDictionary *userInfo = notification.userInfo;\n\n\tNSString *oldNickname = userInfo[@\"oldNickname\"];\n\n\tif ([self.peerNickname isEqualToString:oldNickname] == NO) {\n\t\treturn;\n\t}\n\n\tself.peerNickname = userInfo[@\"newNickname\"];\n}\n\n- (void)clientDisconnected:(NSNotification *)notification\n{\n\t[self closeWithClientDisconnectedError];\n}\n\n- (void)closeWithClientDisconnectedError\n{\n\t/* If the controller is already sending or receiving data, then a connection\n\t is already established to the peer which can function without a connection\n\t to IRC. If data is not being transferred then fail immediately. */\n\tTDCFileTransferDialogTransferStatus transferStatus = self.transferStatus;\n\n\tif (transferStatus != TDCFileTransferDialogTransferStatusConnecting &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusInitializing &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusIsListeningAsReceiver &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusIsListeningAsSender &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusMappingListeningPort &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusWaitingForLocalIPAddress &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept &&\n\t\ttransferStatus != TDCFileTransferDialogTransferStatusWaitingForResumeAccept)\n\t{\n\t\treturn;\n\t}\n\n\t[self _closeWithClientDisconnectedError];\n}\n\n- (void)_closeWithClientDisconnectedError\n{\n\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[12p-0v]\" isFatalError:NO];\n}\n\n- (void)close\n{\n\t[self closeAndPostNotification:YES];\n}\n\n- (void)closeAndPostNotification:(BOOL)postNotification\n{\n\t[self cancelPerformRequests];\n\n\tif ( self.listeningServer) {\n\t\t[self.listeningServer disconnect];\n\t\t self.listeningServer = nil;\n\t}\n\n\tif ( self.listeningServerConnectedClient) {\n\t\t[self.listeningServerConnectedClient disconnect];\n\t\t self.listeningServerConnectedClient = nil;\n\t}\n\n\tif ( self.connectionToRemoteServer) {\n\t\t[self.connectionToRemoteServer disconnect];\n\t\t self.connectionToRemoteServer = nil;\n\t}\n\n\t[self destroyDispatchQueues];\n\n\t[self closePortMapping];\n\n\t[self closeFileHandle];\n\n\tif (self.transferStatus != TDCFileTransferDialogTransferStatusComplete &&\n\t\tself.transferStatus != TDCFileTransferDialogTransferStatusFatalError &&\n\t\tself.transferStatus != TDCFileTransferDialogTransferStatusRecoverableError)\n\t{\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusStopped;\n\t}\n\n\tif (postNotification) {\n\t\tif (self.transferStatus == TDCFileTransferDialogTransferStatusFatalError ||\n\t\t\tself.transferStatus == TDCFileTransferDialogTransferStatusRecoverableError)\n\t\t{\n\t\t\tif (self.isSender) {\n\t\t\t\t[self.client notifyFileTransfer:TXNotificationTypeFileTransferSendFailed nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];\n\t\t\t} else {\n\t\t\t\t[self.client notifyFileTransfer:TXNotificationTypeFileTransferReceiveFailed nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];\n\t\t\t}\n\t\t}\n\t\telse if (self.transferStatus == TDCFileTransferDialogTransferStatusComplete)\n\t\t{\n\t\t\tif (self.isSender) {\n\t\t\t\t[self.client notifyFileTransfer:TXNotificationTypeFileTransferSendSuccessful nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];\n\t\t\t} else {\n\t\t\t\t[self.client notifyFileTransfer:TXNotificationTypeFileTransferReceiveSuccessful nickname:self.peerNickname filename:self.filename filesize:self.totalFilesize requestIdentifier:self.uniqueIdentifier];\n\t\t\t}\n\t\t}\n\t}\n\n\t[self.transferDialog updateMaintenanceTimer];\n\n\t[self enableSystemSleep];\n}\n\n#pragma mark -\n#pragma mark Timer\n\n- (void)onMaintenanceTimer\n{\n\tNSAssertReturn(self.transferStatus == TDCFileTransferDialogTransferStatusReceiving ||\n\t\t\t\t   self.transferStatus == TDCFileTransferDialogTransferStatusSending);\n\n\tXRPerformBlockSynchronouslyOnQueue(self.serverDispatchQueue, ^{\n\t\t@synchronized(self.speedRecords) {\n\t\t\t[self.speedRecordsPrivate addObject:@(self.currentRecord)];\n\n\t\t\tif (self.speedRecordsPrivate.count > RECORDS_LENGTH) {\n\t\t\t\t[self.speedRecordsPrivate removeObjectAtIndex:0];\n\t\t\t}\n\t\t}\n\n\t\tself.currentRecord = 0;\n\n\t\t[self reloadStatusInformation];\n\t});\n\n\t[self send];\n}\n\n#pragma mark -\n#pragma mark File Handle\n\n- (void)setNonexistentFilename\n{\n\tNSString *filePath = self.filePath;\n\n\tif ([RZFileManager() fileExistsAtPath:filePath] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *filenameExtension = self.filename.pathExtension;\n\n\tNSString *filenameWithoutExtension = self.filename.stringByDeletingPathExtension;\n\n\tNSUInteger i = 1;\n\n\tdo {\n\t\tNSString *newFilename = nil;\n\n\t\tif (filenameExtension.length == 0) {\n\t\t\tnewFilename = [NSString stringWithFormat:@\"%@_%lu\", filenameWithoutExtension, i];\n\t\t} else {\n\t\t\tnewFilename = [NSString stringWithFormat:@\"%@_%lu.%@\", filenameWithoutExtension, i, filenameExtension];\n\t\t}\n\n\t\tfilePath = [self.path stringByAppendingPathComponent:newFilename];\n\n\t\ti += 1;\n\t} while ([RZFileManager() fileExistsAtPath:filePath]);\n\n\tself.filename = filePath.lastPathComponent;\n}\n\n- (BOOL)openFileHandle\n{\n\tNSString *filePath = self.filePath;\n\n\tif (self.isSender == NO && self.isResume == NO) {\n\t\t[self setNonexistentFilename];\n\n\t\t[RZFileManager() createFileAtPath:filePath contents:[NSData data] attributes:nil];\n\t}\n\n\tNSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];\n\n\tif (fileHandle == nil) {\n\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[nab-dx]\"];\n\n\t\treturn NO;\n\t}\n\n\tif (self.isResume) {\n\t\t[fileHandle seekToFileOffset:self.processedFilesize];\n\t}\n\n\tself.fileHandle = fileHandle;\n\n\treturn YES;\n}\n\n- (void)closeFileHandle\n{\n\tif (self.fileHandle == nil) {\n\t\treturn;\n\t}\n\n\t[self.fileHandle closeFile];\n\n\tself.fileHandle = nil;\n}\n\n#pragma mark -\n#pragma mark Socket Delegate\n\n- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket\n{\n\tif (self.isActingAsServer == NO) {\n\t\treturn;\n\t}\n\n\tif (self.listeningServerConnectedClient == nil) {\n\t\tself.listeningServerConnectedClient = newSocket;\n\t} else {\n\t\t[newSocket disconnect];\n\n\t\treturn;\n\t}\n\n\tif (self.isReversed) {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusReceiving;\n\t} else {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusSending;\n\t}\n\n\t[self.transferDialog updateMaintenanceTimer];\n\n\tif ([self openFileHandle] == NO) {\n\t\treturn;\n\t}\n\n\tif (self.isReversed) {\n\t\t[self.readSocket readDataWithTimeout:(-1) tag:0];\n\t} else {\n\t\t[self send];\n\t}\n}\n\n- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port\n{\n\tif (self.isActingAsClient == NO) {\n\t\treturn;\n\t}\n\n\tif (self.isReversed == NO) {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusReceiving;\n\t} else {\n\t\tself.transferStatus = TDCFileTransferDialogTransferStatusSending;\n\t}\n\n\t[self.transferDialog updateMaintenanceTimer];\n\n\tif ([self openFileHandle] == NO) {\n\t\treturn;\n\t}\n\n\tif (self.isReversed == NO) {\n\t\t[self.readSocket readDataWithTimeout:(-1) tag:0];\n\t} else {\n\t\t[self send];\n\t}\n}\n\n- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error\n{\n\tif (self.transferStatus == TDCFileTransferDialogTransferStatusComplete ||\n\t\tself.transferStatus == TDCFileTransferDialogTransferStatusFatalError ||\n\t\tself.transferStatus == TDCFileTransferDialogTransferStatusRecoverableError)\n\t{\n\t\treturn;\n\t}\n\n\tif (error) {\n\t\t[self closeWithLocalizedError:@\"TDCFileTransferDialog[s79-3a]\" description:error.localizedDescription];\n\t} else {\n\t\t[self close];\n\t}\n}\n\n- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag\n{\n\tif (self.isSender != NO) {\n\t\treturn;\n\t}\n\n\t/* Update progress */\n\tself.currentRecord += data.length;\n\n\tself.processedFilesize += data.length;\n\n\tif (data.length > 0) {\n\t\t@try {\n\t\t\t[self.fileHandle writeData:data];\n\t\t}\n\t\t@catch (NSException *exception) {\n\t\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\t\tLogStackTrace();\n\n\t\t\tif ([exception.reason contains:@\"No space left on device\"]) {\n\t\t\t\t[self failWithNoSpaceLeftOnDevice];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self closeWithLocalizedError:TXTLS(@\"TDCFileTransferDialog[05g-c8]\")];\n\n\t\t\treturn;\n\t\t} // @catch\n\t}\n\n\t/* Send acknowledgement back to server */\n\tuint32_t processedFilesize = (self.processedFilesize & 0xFFFFFFFF);\n\n\tunsigned char ackPacket[4];\n\n\tackPacket[0] = ((processedFilesize >> 24) & 0xFF);\n\tackPacket[1] = ((processedFilesize >> 16) & 0xFF);\n\tackPacket[2] = ((processedFilesize >> 8) & 0xFF);\n\tackPacket[3] =  (processedFilesize & 0xFF);\n\n\tNSData *ackPacketData = [NSData dataWithBytes:ackPacket length:4];\n\n\t[self.readSocket writeData:ackPacketData withTimeout:(-1) tag:0];\n\n\t/* Continue requesting data if the transfer is not complete */\n\tif (self.processedFilesize < self.totalFilesize) {\n\t\t[self.readSocket readDataWithTimeout:(-1) tag:0];\n\n\t\treturn;\n\t}\n\n\t/* Update status and tear down transfer */\n\tself.transferStatus = TDCFileTransferDialogTransferStatusComplete;\n\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark Socket Write\n\n- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag\n{\n\tif (self.isSender == NO) {\n\t\treturn;\n\t}\n\n\t/* Acknowledge sent data */\n\tself.sendQueueSize -= 1;\n\n\t/* Continue sending data if the transfer is not complete */\n\tif (self.processedFilesize < self.totalFilesize) {\n\t\t[self send];\n\n\t\treturn;\n\t}\n\n\t/* Wait until the send queue has cleared before closing \n\t connection. Just because we finished processing the \n\t data here doesn't mean it has been sent yet. */\n\tif (self.sendQueueSize > 0) {\n\t\treturn;\n\t}\n\n\t/* Update status and tear down transfer */\n\tself.transferStatus = TDCFileTransferDialogTransferStatusComplete;\n\n\t[self close];\n}\n\n- (void)send\n{\n\tif (self.isSender == NO) {\n\t\treturn;\n\t}\n\n\tif (self.transferStatus != TDCFileTransferDialogTransferStatusSending) {\n\t\treturn;\n\t}\n\n\tdo {\n\t\tif (self.currentRecord >= RATE_LIMIT) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (self.sendQueueSize >= MAX_QUEUE_SIZE) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (self.processedFilesize >= self.totalFilesize) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSData *dataToWrite = [self.fileHandle readDataOfLength:BUFFER_SIZE];\n\n\t\tself.currentRecord += dataToWrite.length;\n\n\t\tself.processedFilesize += dataToWrite.length;\n\n\t\tself.sendQueueSize += 1;\n\n\t\t[self.writeSocket writeData:dataToWrite withTimeout:_sendDataTimeout tag:0];\n\t} while (1);\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)updateClearButton\n{\n\t[self.transferDialog updateClearButton];\n}\n\n- (void)reloadStatusInformation\n{\n\tTDCFileTransferDialogTableCell *transferTableCell = self.transferTableCell;\n\n\tif (transferTableCell == nil) {\n\t\treturn;\n\t}\n\n\t[transferTableCell reloadStatusInformation];\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (nullable GCDAsyncSocket *)writeSocket\n{\n\tif (self.isReversed) {\n\t\treturn self.connectionToRemoteServer;\n\t} else {\n\t\treturn self.listeningServerConnectedClient;\n\t}\n}\n\n- (nullable GCDAsyncSocket *)readSocket\n{\n\tif (self.isReversed) {\n\t\treturn self.listeningServerConnectedClient;\n\t} else {\n\t\treturn self.connectionToRemoteServer;\n\t}\n}\n\n- (BOOL)isActingAsServer\n{\n\treturn ((self.isSender\t\t && self.isReversed == NO) ||\n\t\t\t(self.isSender == NO && self.isReversed));\n}\n\n- (BOOL)isActingAsClient\n{\n\treturn ((self.isSender == NO && self.isReversed == NO) ||\n\t\t\t(self.isSender\t\t && self.isReversed));\n}\n\n- (TDCFileTransferDialog *)transferDialog\n{\n\treturn [TXSharedApplication sharedFileTransferDialog];\n}\n\n- (NSArray<NSNumber *> *)speedRecords\n{\n\t@synchronized (self.speedRecordsPrivate) {\n\t\treturn [self.speedRecordsPrivate copy];\n\t}\n}\n\n- (nullable NSString *)filePath\n{\n\tNSString *path = self.path;\n\n\tNSString *filename = self.filename;\n\n\tif (path == nil || filename == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [path stringByAppendingPathComponent:filename];\n}\n\n- (nullable NSURL *)fileURL\n{\n\tNSString *filePath = self.filePath;\n\n\tif (filePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:filePath];\n}\n\n- (uint64_t)currentFilesize\n{\n\tNSString *filePath = self.filePath;\n\n\tif (filePath == nil) {\n\t\treturn 0;\n\t}\n\n\tif ([RZFileManager() fileExistsAtPath:filePath] == NO) {\n\t\treturn 0;\n\t}\n\n\tNSDictionary *fileAttributes = [RZFileManager() attributesOfItemAtPath:filePath error:NULL];\n\n\treturn fileAttributes.fileSize;\n}\n\n- (void)setTransferStatus:(TDCFileTransferDialogTransferStatus)transferStatus\n{\n\tif (self->_transferStatus != transferStatus) {\n\t\tself->_transferStatus = transferStatus;\n\n\t\t[self reloadStatusInformation];\n\t}\n}\n\n- (void)resetProperties\n{\n\tif (self.isResume == NO) {\n\t\tself.processedFilesize = 0;\n\t}\n\n\tself.currentRecord = 0;\n\n\tself.errorMessageDescription = nil;\n\n\tself.sendQueueSize = 0;\n\n\t@synchronized(self.speedRecordsPrivate) {\n\t\t[self.speedRecordsPrivate removeAllObjects];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerDialog.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"NSViewHelper.h\"\n#import \"TXGlobalModels.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TDCLicenseManagerMigrateAppStoreSheetPrivate.h\"\n#import \"TDCLicenseManagerRecoverLostLicenseSheetPrivate.h\"\n#import \"TDCLicenseUpgradeActivateSheetPrivate.h\"\n#import \"TDCLicenseUpgradeCommonActionsPrivate.h\"\n#import \"TDCLicenseUpgradeDialogPrivate.h\"\n#import \"TDCLicenseUpgradeEligibilitySheetPrivate.h\"\n#import \"TDCProgressIndicatorSheetPrivate.h\"\n#import \"TLOTimer.h\"\n#import \"TLOLicenseManagerDownloaderPrivate.h\"\n#import \"TLOLicenseManagerLastGenPrivate.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLONotificationController.h\"\n#import \"TDCAlert.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\nNSString * const TDCLicenseManagerActivatedLicenseNotification = @\"TDCLicenseManagerActivatedLicenseNotification\";\nNSString * const TDCLicenseManagerDeactivatedLicenseNotification = @\"TDCLicenseManagerDeactivatedLicenseNotification\";\nNSString * const TDCLicenseManagerTrialExpiredNotification = @\"TDCLicenseManagerTrialExpiredNotification\";\n\n#define _upgradeDialogRemindMeInterval \t\t345600 // 4 days\n\n@interface TDCLicenseManagerDialog () <NSControlTextEditingDelegate>\n@property (nonatomic, strong) IBOutlet NSView *contentViewUnregisteredTextualView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewRegisteredTextualView;\n@property (nonatomic, weak) IBOutlet NSTextField *unregisteredViewLicenseKeyTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *unregisteredViewTrialInformationTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicenseKeyTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicenseOwnerTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *registeredViewLicensePurchaseDateTextField;\n@property (nonatomic, weak) IBOutlet NSButton *registeredViewDeactivateTextualButton;\n@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewActivateTextualButton;\n@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewCancelButton;\n@property (nonatomic, weak) IBOutlet NSButton *unregisteredViewRecoveryLostLicenseButton;\n@property (nonatomic, weak) IBOutlet NSImageView *unregisteredViewMacAppStoreIconImageView;\n@property (nonatomic, strong, nullable) TDCProgressIndicatorSheet *progressIndicator;\n@property (nonatomic, strong, nullable) TLOLicenseManagerDownloader *licenseManagerDownloader;\n@property (nonatomic, strong, nullable) TDCLicenseManagerMigrateAppStoreSheet *migrateAppStoreSheet;\n@property (nonatomic, strong, nullable) TDCLicenseManagerRecoverLostLicenseSheet *recoverLostLicenseSheet;\n@property (nonatomic, strong, nullable) TDCLicenseUpgradeDialog *upgradeDialog;\n@property (nonatomic, strong, nullable) TDCLicenseUpgradeActivateSheet *upgradeActivateSheet;\n@property (nonatomic, assign) BOOL textualIsRegistered;\n@property (nonatomic, assign) BOOL isSilentOnSuccess;\n@property (nonatomic, assign) BOOL operationInProgress;\n@property (nonatomic, strong) TLOTimer *trialTimer;\n\n- (IBAction)unregisteredViewActivateTextual:(id)sender;\n- (IBAction)unregisteredViewCancel:(id)sender;\n- (IBAction)unregisteredViewMigrateMacAppStorePurchase:(id)sender;\n- (IBAction)unregisteredViewPurchaseTextual:(id)sender;\n- (IBAction)unregisteredViewRecoveryLostLicense:(id)sender;\n\n- (IBAction)registeredViewDeactivateTextual:(id)sender;\n@end\n\n@interface TLONotificationController ()\n- (void)scheduleLicenseManagerNotificationWithTitle:(NSString *)title message:(NSString *)message;\n@end\n\n@implementation TDCLicenseManagerDialog\n\n#pragma mark -\n#pragma mark Dialog Foundation\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseManagerDialog\" owner:self topLevelObjects:nil];\n\n\t[self populateMacAppStoreIconImageView];\n\n\t[self updateSelectedPane];\n}\n\n- (void)show\n{\n\tBOOL windowVisible = self.window.visible;\n\n\t[super show];\n\n\tif (windowVisible == NO) {\n\t\t[self.window restoreWindowStateForClass:self.class];\n\t}\n}\n\n- (void)applicationDidFinishLaunching\n{\n\t[self scheduleTimeRemainingInTrialNotification];\n\n\t[self toggleTrialTimer];\n\n\t[self activateLicenseKeyUsingArgumentDictionary];\n\n\t[self upgradeDialogAppFinishedLaunchingRoutine];\n}\n\n- (void)populateMacAppStoreIconImageView\n{\n\t/* Read the app store icon image from the actual App Store app so \n\t that we do not have to update it if Apple does. */\n\tNSBundle *appStoreApplication = [NSBundle bundleWithPath:@\"/Applications/App Store.app\"];\n\n\tif (appStoreApplication == nil) {\n\t\tappStoreApplication = [NSBundle bundleWithPath:@\"/System/Applications/App Store.app\"];\n\t}\n\n\tif (appStoreApplication == nil) {\n\t\treturn;\n\t}\n\n\tNSString *appStoreIconPath = [appStoreApplication pathForResource:@\"AppIcon\" ofType:@\"icns\"];\n\n\tif (appStoreIconPath == nil) {\n\t\treturn;\n\t}\n\n\tNSImage *appStoreIconImage = [[NSImage alloc] initWithContentsOfFile:appStoreIconPath];\n\n\tself.unregisteredViewMacAppStoreIconImageView.image = appStoreIconImage;\n}\n\n- (void)updateSelectedPane\n{\n\tNSView *contentView = nil;\n\n\tself.textualIsRegistered = TLOLicenseManagerTextualIsRegistered();\n\n\tif (self.textualIsRegistered)\n\t{\n\t\tNSString *licenseKey = TLOLicenseManagerLicenseKey();\n\t\tNSString *licenseKeyOwner = TLOLicenseManagerLicenseOwnerName();\n\t\tNSString *licenseKeyCreationDate = TLOLicenseManagerLicenseCreationDateFormatted();\n\n\t\tself.registeredViewLicenseKeyTextField.stringValue = licenseKey;\n\t\tself.registeredViewLicenseOwnerTextField.stringValue = licenseKeyOwner;\n\t\tself.registeredViewLicensePurchaseDateTextField.stringValue = licenseKeyCreationDate;\n\n\t\tcontentView = self.contentViewRegisteredTextualView;\n\t}\n\telse // textualIsRegistered\n\t{\n\t\tcontentView = self.contentViewUnregisteredTextualView;\n\n\t\tNSString *formattedTrialInformation = [self timeRemainingInTrialFormattedMessage];\n\n\t\tself.unregisteredViewTrialInformationTextField.stringValue = formattedTrialInformation;\n\t}\n\n\t[self.window replaceContentView:contentView];\n}\n\n#pragma mark -\n#pragma mark Trial Timer\n\n- (void)toggleTrialTimer\n{\n\tif (TLOLicenseManagerTextualIsRegistered()) {\n\t\t[self stopTrialTimer];\n\t} else {\n\t\t[self startTrialTimer];\n\t}\n}\n\n- (void)startTrialTimer\n{\n\tif (self.trialTimer != nil) {\n\t\treturn;\n\t}\n\n\tNSTimeInterval timeRemaining = (TLOLicenseManagerTimeRemainingTrial() * (-1.0));\n\n\tif (timeRemaining == 0) {\n\t\treturn;\n\t}\n\n\tTLOTimer *trialTimer = [TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onTrialTimer];\n\t}];\n\n\tself.trialTimer = trialTimer;\n\n\t[trialTimer start:timeRemaining];\n}\n\n- (void)stopTrialTimer\n{\n\tif (self.trialTimer == nil) {\n\t\treturn;\n\t}\n\n\t[self.trialTimer stop];\n\tself.trialTimer = nil;\n}\n\n- (void)onTrialTimer\n{\n\t[self stopTrialTimer];\n\n\t[RZNotificationCenter() postNotificationName:TDCLicenseManagerTrialExpiredNotification object:self];\n}\n\n#pragma mark -\n#pragma mark Activate License\n\n- (void)unregisteredViewPurchaseTextual:(id)sender\n{\n\tNSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKey];\n\n\tif (lastGenLicenseKey != nil) {\n\t\tBOOL upgradeLicense =\n\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[dpo-ln]\", lastGenLicenseKey.prettyLicenseKey)\n\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[12h-3w]\")\n\t\t\t\t\t\t  defaultButton:TXTLS(@\"TLOLicenseManager[qrx-aq]\")\n\t\t\t\t\t\talternateButton:TXTLS(@\"TLOLicenseManager[zp8-8q]\")];\n\n\t\tif (upgradeLicense) {\n\t\t\t[self showUpgradeDialogForLicenseKey:lastGenLicenseKey];\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t[menuController() openStandaloneStoreWebpage:nil];\n}\n\n- (void)unregisteredViewCancel:(id)sender\n{\n\t[self close];\n}\n\n- (void)updateUnregisteredViewActivationButton\n{\n\tif (self.textualIsRegistered) {\n\t\treturn; // Cancel operation...\n\t}\n\n\tNSString *licenseKeyValue = self.unregisteredViewLicenseKeyTextField.stringValue.trim;\n\n\tif (TLOLicenseManagerLicenseKeyIsValid(licenseKeyValue)) {\n\t\tself.unregisteredViewActivateTextualButton.enabled = YES;\n\t} else {\n\t\tself.unregisteredViewActivateTextualButton.enabled = NO;\n\t}\n}\n\n- (void)unregisteredViewActivateTextual:(id)sender\n{\n\tNSString *licenseKeyValue = self.unregisteredViewLicenseKeyTextField.stringValue;\n\n\t[self attemptToActivateLicenseKey:licenseKeyValue];\n}\n\n- (void)activateLicenseKeyUsingArgumentDictionary\n{\n\tif (TLOLicenseManagerTextualIsRegistered()) {\n\t\treturn; // Nothing to do here...\n\t}\n\n\tNSDictionary *commandLineArguments = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSArgumentDomain];\n\n\tNSString *argumentLicenseKey = commandLineArguments[@\"-licenseKey\"];\n\n\tif (argumentLicenseKey == nil) {\n\t\treturn;\n\t}\n\n\t[self activateLicenseKey:argumentLicenseKey silently:YES];\n}\n\n- (void)activateLicenseKey:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\t[self activateLicenseKey:licenseKey silently:NO];\n}\n\n- (void)activateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\t/* This method is allowed to be invoked by another class in order\n\t to activate a license. It is not invoked by this class on its own. */\n\tif (TLOLicenseManagerLicenseKeyIsValid(licenseKey)) {\n\t\t[self attemptToActivateLicenseKey:licenseKey silently:silently];\n\t}\n}\n\n- (void)attemptToActivateLicenseKey:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\t[self attemptToActivateLicenseKey:licenseKey silently:NO];\n}\n\n- (void)attemptToActivateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\t/* User can click a link or do something else while an activation is already in\n\t progress, so we try to recognize when that happens so that we can prevent\n\t confusion when an operation is already in progress. */\n\t/* This is the only place in the dialog where user can perform an action by\n\t outside influence. Everything else is internalized which means this check is\n\t only necessary here... at least for now. */\n\tif (self.operationInProgress) {\n\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[vnu-5e]\")\n\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[0uc-io]\", licenseKey.prettyLicenseKey)\n\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\talternateButton:nil];\n\n\t\treturn;\n\t}\n\n\t/* Do not activate license we are already using. */\n\tif (licenseKey == TLOLicenseManagerLicenseKey()) {\n\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[fxu-su]\")\n\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[bw3-sc]\", licenseKey.prettyLicenseKey)\n\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\talternateButton:nil];\n\n\t\treturn;\n\t}\n\n\t/* The activate sheet will close itself when user clicks to make purchase,\n\t but if user activates a license by other means (such as clicking the link\n\t in their e-mail), then we dismiss it here, so that we can do activation. */\n\t[self closeUpgradeActivateSheet];\n\n\t/* Perform activation */\n\tself.isSilentOnSuccess = silently;\n\n\t[self beginProgressIndicator];\n\n\t__weak TDCLicenseManagerDialog *weakSelf = self;\n\n\tTLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];\n\n\tlicenseManagerDownloader.actionBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {\n\t\treturn (TLOLicenseManagerWriteLicenseFileContents(statusContext) == TLOLicenseManagerActionResultSuccess);\n\t};\n\n\tlicenseManagerDownloader.errorBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {\n\t\tif (statusCode != 0 || statusContext == nil) {\n\t\t\treturn NO;\n\t\t}\n\n\t\t/* lastGenLicenseKey will only be non-nil if the contents of licenseContents\n\t\t are for a license that have not been upgraded to Textual 7 yet. */\n\t\tNSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKeyForLicenseContents:statusContext];\n\n\t\tif (lastGenLicenseKey != nil) {\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[5bu-ov]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[pmv-qp]\", lastGenLicenseKey.prettyLicenseKey)\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"TLOLicenseManager[53u-lt]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\n\t\t\t[weakSelf showUpgradeDialogForLicenseKey:lastGenLicenseKey];\n\n\t\t\t/* We return YES so no error is displayed except the one above. */\n\t\t\treturn YES;\n\t\t}\n\n\t\t/* We did not handle the error. */\n\t\treturn NO;\n\t};\n\n\tlicenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {\n\t\t[weakSelf licenseManagerDownloaderCompletionBlock];\n\n\t\tif (operationSuccessful) {\n\t\t\tweakSelf.unregisteredViewLicenseKeyTextField.stringValue = @\"\";\n\n\t\t\t[weakSelf toggleTrialTimer];\n\n\t\t\t[RZNotificationCenter() postNotificationName:TDCLicenseManagerActivatedLicenseNotification object:weakSelf];\n\n\t\t\t/* We close the upgrade dialog if a key is activated because\n\t\t\t why would we keep it around under that condition? */\n\t\t\t[weakSelf closeUpgradeDialog];\n\n\t\t\t/* Reset context for activate sheet. */\n\t\t\t[weakSelf resetUpgradeActivateSheetContext];\n\t\t}\n\n\t\tweakSelf.operationInProgress = NO;\n\t};\n\n\tself.operationInProgress = YES;\n\n\tlicenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;\n\n\t[licenseManagerDownloader activateLicense:licenseKey.trim];\n\n\tself.licenseManagerDownloader = licenseManagerDownloader;\n}\n\n#pragma mark -\n#pragma mark License Upgrade Launch Routine\n\n- (void)upgradeDialogAppFinishedLaunchingRoutine\n{\n\t/* There is no reason to perform this check if this copy of Textual\n\t is already registered. */\n\tif (TLOLicenseManagerTextualIsRegistered()) {\n\t\t/* If Textual is registered, then we reset these values because\n\t\t there is no reason to have them hanging around. */\n\t\t[self resetUpgradeActivateSheetContext];\n\n\t\treturn;\n\t}\n\n\t/* Check if we have license key saved from Textual 6 upgrade dialog. */\n\tif ([self showUpgradeActivateSheet]) {\n\t\treturn;\n\t}\n\n\t/* Show upgrade dialog */\n\t[self showUpgradeDialogForLastGenLicense];\n}\n\n- (void)showUpgradeDialogForLastGenLicense\n{\n\t/* Is there even a last generation key? */\n\tNSString *lastGenLicenseKey = [TLOLicenseManagerLastGen licenseKey];\n\n\tif (lastGenLicenseKey == nil) {\n\t\treturn;\n\t}\n\n\t/* When was the last time the user was nagged? */\n\t/* Unless user hits \"Remind Me Later\", then the upgrade dialog is\n\t not hidden due to time limit. This change was made so that if the\n\t user is performing some type of action that causes them to miss the\n\t dialog, such as installing an update, it will show next launch. */\n\tBOOL remindMeLater = [RZUserDefaults() boolForKey:@\"Textual 7 Upgrade -> Tv7 -> Remind Me Later\"];\n\n\tNSTimeInterval lastCheckTime = [RZUserDefaults() doubleForKey:@\"Textual 7 Upgrade -> Tv7 -> Last Dialog Presentation (LMD)\"];\n\n\tNSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];\n\n\tif (lastCheckTime > 0 && remindMeLater) {\n\t\tif ((currentTime - lastCheckTime) < _upgradeDialogRemindMeInterval) {\n\t\t\tLogToConsoleInfo(\"Not enough time has passed since last presentation\");\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t[RZUserDefaults() setDouble:currentTime forKey:@\"Textual 7 Upgrade -> Tv7 -> Last Dialog Presentation (LMD)\"];\n\n\t[RZUserDefaults() removeObjectForKey:@\"Textual 7 Upgrade -> Tv7 -> Remind Me Later\"];\n\n\t/* Nag user */\n\t[self showUpgradeDialogForLicenseKey:lastGenLicenseKey];\n}\n\n#pragma mark -\n#pragma mark License Upgrade Dialog\n\n- (void)showUpgradeDialogForLicenseKey:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tif (self.upgradeDialog) {\n\t\tif ([self.upgradeDialog.licenseKey isEqualToString:licenseKey]) {\n\t\t\t[self.upgradeDialog show];\n\n\t\t\treturn;\n\t\t} else {\n\t\t\t[self.upgradeDialog close];\n\t\t}\n\t}\n\n\t  TDCLicenseUpgradeDialog *upgradeDialog =\n\t[[TDCLicenseUpgradeDialog alloc] initWithLicenseKey:licenseKey];\n\n\tupgradeDialog.delegate = self;\n\n\t[upgradeDialog show];\n\n\tself.upgradeDialog = upgradeDialog;\n}\n\n- (void)closeUpgradeDialog\n{\n\tif (self.upgradeDialog) {\n\t\t[self.upgradeDialog close];\n\t}\n}\n\n- (void)licenseUpgradeDialogEligibilityChanged:(TDCLicenseUpgradeDialog *)sender\n{\n\t/* Record eligibility status so that we might present an activate sheet\n\t next time the user opens the app. */\n\t[self setUpgradeActivateSheetContextWithDialog:sender];\n}\n\n- (void)licenseUpgradeDialogWRemindMeLater:(TDCLicenseUpgradeDialog *)sender\n{\n\t[RZUserDefaults() setBool:YES forKey:@\"Textual 7 Upgrade -> Tv7 -> Remind Me Later\"];\n}\n\n- (void)licenseUpgradeDialogWillClose:(TDCLicenseUpgradeDialog *)sender\n{\n\tself.upgradeDialog = nil;\n}\n\n#pragma mark -\n#pragma mark Upgrade Activate Sheet\n\n- (BOOL)showUpgradeActivateSheet\n{\n\t/* Do we have a properly formatted license key? */\n\tNSString *licenseKey = [RZUserDefaults() objectForKey:@\"Textual 7 Upgrade -> Tv7 -> Eligible License Key\"];\n\n\tif (licenseKey == nil) {\n\t\treturn NO;\n\t}\n\n\tif (TLOLicenseManagerLicenseKeyIsValid(licenseKey) == NO) {\n\t\treturn NO;\n\t}\n\n\t/* Do we have an eligibility that is acceptable? */\n\tNSUInteger eligibility = [RZUserDefaults() unsignedIntegerForKey:@\"Textual 7 Upgrade -> Tv7 -> Eligibility\"];\n\n\tif (eligibility != TLOLicenseUpgradeEligibilityDiscount &&\n\t\teligibility != TLOLicenseUpgradeEligibilityFree &&\n\t\teligibility != TLOLicenseUpgradeEligibilityAlreadyUpgraded)\n\t{\n\t\treturn NO;\n\t}\n\n\t/* Show ourselves because we will place the sheet on self. */\n\t[self show];\n\n\t/* Create sheet and start it. */\n\t  TDCLicenseUpgradeActivateSheet *activateSheet =\n\t[[TDCLicenseUpgradeActivateSheet alloc] initWithLicenseKey:licenseKey eligibility:eligibility];\n\n\tactivateSheet.delegate = self;\n\n\tactivateSheet.window = self.window;\n\n\t[activateSheet start];\n\n\tself.upgradeActivateSheet = activateSheet;\n\n\t/* Inform launch routine to do nothing more. */\n\treturn YES;\n}\n\n- (void)closeUpgradeActivateSheet\n{\n\tif (self.upgradeActivateSheet) {\n\t\t[self.upgradeActivateSheet endSheet];\n\t}\n}\n\n- (void)setUpgradeActivateSheetContextWithDialog:(TDCLicenseUpgradeDialog *)upgradeDialog\n{\n\tNSParameterAssert(upgradeDialog != nil);\n\n\t[RZUserDefaults() setUnsignedInteger:upgradeDialog.eligibility forKey:@\"Textual 7 Upgrade -> Tv7 -> Eligibility\"];\n\n\t[RZUserDefaults() setObject:upgradeDialog.licenseKey forKey:@\"Textual 7 Upgrade -> Tv7 -> Eligible License Key\"];\n}\n\n- (void)resetUpgradeActivateSheetContext\n{\n\t/* We reset these values for any successful activation.\n\t It is probably more proper to compare the key activated to the context,\n\t but I don't think it will matter in the real world. */\n\t[RZUserDefaults() removeObjectForKey:@\"Textual 7 Upgrade -> Tv7 -> Eligibility\"];\n\n\t[RZUserDefaults() removeObjectForKey:@\"Textual 7 Upgrade -> Tv7 -> Eligible License Key\"];\n}\n\n- (void)upgradeActivateSheetActivateLicense:(TDCLicenseUpgradeActivateSheet *)sender\n{\n\tNSString *licenseKey = sender.licenseKey;\n\n\t[sender endSheet];\n\n\t[self attemptToActivateLicenseKey:licenseKey];\n}\n\n- (void)upgradeActivateSheetPurchaseUpgrade:(TDCLicenseUpgradeActivateSheet *)sender\n{\n\t[TDCLicenseUpgradeCommonActions purchaseUpgradeForLicense:sender.licenseKey];\n}\n\n- (void)upgradeActivateSheetSuppressed:(TDCLicenseUpgradeActivateSheet *)sender\n{\n\t[self resetUpgradeActivateSheetContext];\n}\n\n- (void)upgradeActivateSheetWillClose:(TDCLicenseUpgradeActivateSheet *)sender\n{\n\tself.upgradeActivateSheet = nil;\n}\n\n#pragma mark -\n#pragma mark Recover Lost License\n\n- (void)unregisteredViewRecoveryLostLicense:(id)sender\n{\n\t  TDCLicenseManagerRecoverLostLicenseSheet *recoverLostLicenseSheet =\n\t[[TDCLicenseManagerRecoverLostLicenseSheet alloc] initWithWindow:self.window];\n\n\trecoverLostLicenseSheet.delegate = self;\n\n\t[recoverLostLicenseSheet start];\n\n\tself.recoverLostLicenseSheet = recoverLostLicenseSheet;\n}\n\n- (void)licenseManagerRecoverLostLicenseSheet:(TDCLicenseManagerRecoverLostLicenseSheet *)sender onOk:(NSString *)contactAddress\n{\n\t__weak TDCLicenseManagerDialog *weakSelf = self;\n\n\tTLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];\n\n\tlicenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {\n\t\t[weakSelf licenseManagerDownloaderCompletionBlock];\n\t};\n\n\tlicenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;\n\n\t[licenseManagerDownloader requestLostLicenseKeyForContactAddress:contactAddress];\n\n\tself.licenseManagerDownloader = licenseManagerDownloader;\n}\n\n- (void)licenseManagerRecoverLostLicenseSheetWillClose:(TDCLicenseManagerRecoverLostLicenseSheet *)sender\n{\n\tself.recoverLostLicenseSheet = nil;\n\n\tif (self.licenseManagerDownloader) {\n\t\t[self beginProgressIndicator];\n\t}\n}\n\n#pragma mark -\n#pragma mark Deactivate License\n\n- (void)registeredViewDeactivateTextual:(id)sender\n{\n\tBOOL deactivateCopy = [TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[z87-wb]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"TLOLicenseManager[pg1-a9]\")\n\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\tif (deactivateCopy == NO) {\n\t\treturn; // Cancel operation...\n\t}\n\n\t/* License deactivation does not use a progress indicator because\n\t it does not have to touch the network. It will only delete a file\n\t on the hard drive which is typically instant. */\n\t__weak TDCLicenseManagerDialog *weakSelf = self;\n\n\tTLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];\n\n\tlicenseManagerDownloader.actionBlock = ^BOOL(NSUInteger statusCode, id _Nullable statusContext) {\n\t\treturn (TLOLicenseManagerDeleteLicenseFile() == TLOLicenseManagerActionResultSuccess);\n\t};\n\n\tlicenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {\n\t\t[weakSelf licenseManagerDownloaderCompletionBlock];\n\n\t\t[weakSelf toggleTrialTimer];\n\n\t\t[RZNotificationCenter() postNotificationName:TDCLicenseManagerDeactivatedLicenseNotification object:weakSelf];\n\t};\n\n\tlicenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;\n\n\t[licenseManagerDownloader deactivateLicense];\n\n//\tself.licenseManagerDownloader = licenseManagerDownloader;\n}\n\n#pragma mark -\n#pragma mark Mac App Store Receipt Processing\n\n- (void)unregisteredViewMigrateMacAppStorePurchase:(id)sender\n{\n\t  TDCLicenseManagerMigrateAppStoreSheet *migrateAppStoreSheet =\n\t[[TDCLicenseManagerMigrateAppStoreSheet alloc] initWithWindow:self.window];\n\n\tmigrateAppStoreSheet.delegate = self;\n\n\t[migrateAppStoreSheet start];\n\n\tself.migrateAppStoreSheet = migrateAppStoreSheet;\n}\n\n- (void)licenseManagerMigrateAppStoreSheet:(TDCLicenseManagerMigrateAppStoreSheet *)sender\n\t\t\t\t\t\t\tconvertReceipt:(NSString *)receiptData\n\t\t\t\t\t\t  licenseOwnerName:(NSString *)licenseOwnerName\n\t\t\t\tlicenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress\n{\n\t__weak TDCLicenseManagerDialog *weakSelf = self;\n\n\tTLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];\n\n\tlicenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {\n\t\t[weakSelf licenseManagerDownloaderCompletionBlock];\n\t};\n\n\tlicenseManagerDownloader.isSilentOnSuccess = self.isSilentOnSuccess;\n\n\t[licenseManagerDownloader migrateMacAppStorePurchase:receiptData\n\t\t\t\t\t\t\t\t\t\t\t licenseOwnerName:licenseOwnerName\n\t\t\t\t\t\t\t\t   licenseOwnerContactAddress:licenseOwnerContactAddress];\n\n\tself.licenseManagerDownloader = licenseManagerDownloader;\n}\n\n- (void)licenseManagerMigrateAppStoreSheetWillClose:(TDCLicenseManagerMigrateAppStoreSheet *)sender\n{\n\tself.migrateAppStoreSheet = nil;\n\n\tif (self.licenseManagerDownloader) {\n\t\t[self beginProgressIndicator];\n\t}\n}\n\n#pragma mark -\n#pragma mark NSTextField Delegate\n\n- (void)controlTextDidChange:(NSNotification *)obj\n{\n\tif (obj.object == self.unregisteredViewLicenseKeyTextField) {\n\t\t[self updateUnregisteredViewActivationButton];\n\t}\n}\n\n#pragma mark -\n#pragma mark Helper Methods\n\n- (void)licenseManagerDownloaderCompletionBlock\n{\n\tself.licenseManagerDownloader = nil;\n\n\t[self endProgressIndicator];\n\n\t[self updateSelectedPane];\n\n\t[self updateUnregisteredViewActivationButton];\n\n\tself.isSilentOnSuccess = NO; // Reset flag regardless of state.\n\t\t\t\t\t\t\t\t // This flag is one-time use.\n}\n\n- (void)beginProgressIndicator\n{\n\tself.progressIndicator = [[TDCProgressIndicatorSheet alloc] initWithWindow:self.window];\n\n\t[self.progressIndicator start];\n}\n\n- (void)endProgressIndicator\n{\n\tif (self.progressIndicator == nil) {\n\t\treturn;\n\t}\n\n\t[self.progressIndicator stop];\n\n\tself.progressIndicator = nil;\n}\n\n#pragma mark -\n#pragma mark Notification Center\n\n- (NSString *)timeRemainingInTrialFormattedMessage\n{\n\tNSTimeInterval timeLeft = TLOLicenseManagerTimeRemainingTrial();\n\n\tif (timeLeft >= 0) {\n\t\treturn TXTLS(@\"TLOLicenseManager[kn7-ju]\");\n\t}\n\n\tNSString *formattedTimeRemainingString = TXHumanReadableTimeInterval(timeLeft, YES, NSCalendarUnitDay);\n\n\treturn TXTLS(@\"TLOLicenseManager[wdl-3f]\", formattedTimeRemainingString);\n}\n\n- (void)scheduleTimeRemainingInTrialNotification\n{\n\tif (TLOLicenseManagerTextualIsRegistered() || TLOLicenseManagerIsTrialExpired()) {\n\t\treturn; // Do not schedule notification...\n\t}\n\n\tNSString *title = [self timeRemainingInTrialFormattedMessage];\n\n\tNSString *message = TXTLS(@\"TLOLicenseManager[ccj-ag]\");\n\n\t[sharedNotificationController() scheduleLicenseManagerNotificationWithTitle:title message:message];\n}\n\n#pragma mark -\n#pragma mark Window Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.window saveWindowStateForClass:self.class];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerMigrateAppStoreSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CoreServices/CoreServices.h>\n\n#import \"TPCPathInfo.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCLicenseManagerMigrateAppStoreSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* \n * TDCLicenseManagerMigrateAppStoreSheet presents an open dialog to\n * find a copy of Textual with a receipt then presents a sheet asking\n * for the user's e-mail address as long as a valid receipt is present.\n */\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n#define _licenseOwnerNameMaximumLength\t\t\t\t\t\t255\n#define _licenseOwnerContactAddressMaximumLength\t\t\t2000\n\n@interface TDCLicenseManagerMigrateAppStoreSheet ()\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *licenseOwnerNameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *licenseOwnerContactAddressTextField;\n@property (nonatomic, copy) NSString *cachedReceiptData;\n@end\n\n@implementation TDCLicenseManagerMigrateAppStoreSheet\n\n#pragma mark -\n#pragma mark Contact Address Sheet\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseManagerMigrateAppStoreSheet\" owner:self topLevelObjects:nil];\n}\n\n- (void)startContactAddressSheet\n{\n\t/* E-mail address text field configuration */\n\tself.licenseOwnerContactAddressTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.licenseOwnerContactAddressTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.licenseOwnerContactAddressTextField.textDidChangeCallback = self;\n\n\tself.licenseOwnerContactAddressTextField.stringValue = [XRAddressBook myEmailAddress];\n\n\tself.licenseOwnerContactAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\tif (currentValue.length > _licenseOwnerContactAddressMaximumLength) {\n\t\t\treturn TXTLS(@\"CommonErrors[2cb-af]\", _licenseOwnerContactAddressMaximumLength);\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* First & last name text field configuration */\n\tself.licenseOwnerNameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.licenseOwnerNameTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.licenseOwnerNameTextField.textDidChangeCallback = self;\n\n\tself.licenseOwnerNameTextField.stringValue = [XRAddressBook myName];\n\n\tself.licenseOwnerNameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\tif (currentValue.length > _licenseOwnerNameMaximumLength) {\n\t\t\treturn TXTLS(@\"CommonErrors[2cb-af]\", _licenseOwnerNameMaximumLength);\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Begin sheet... */\n\t[self startSheet];\n}\n\n- (void)start\n{\n\t[self findTextualUsingLaunchServices];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *receiptData = self.cachedReceiptData;\n\n\tNSString *licenseOwnerName = self.licenseOwnerNameTextField.value;\n\n\tNSString *licenseOwnerContactAddress = self.licenseOwnerContactAddressTextField.value;\n\n\t[self.delegate licenseManagerMigrateAppStoreSheet:self\n\t\t\t\t\t\t\t\t\t   convertReceipt:receiptData\n\t\t\t\t\t\t\t\t\t licenseOwnerName:licenseOwnerName\n\t\t\t\t\t\t   licenseOwnerContactAddress:licenseOwnerContactAddress];\n\n\t[super ok:sender];\n}\n\n- (BOOL)okOrError\n{\n\tif ([self okOrErrorForTextField:self.licenseOwnerNameTextField] == NO) {\n\t\treturn NO;\n\t}\n\n\tif ([self okOrErrorForTextField:self.licenseOwnerContactAddressTextField] == NO) {\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Open Dialog\n\n- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError\n{\n\tNSString *applicationName = nil;\n\n\tif ([self canUseApplicationAtURL:url applicationName:&applicationName] == NO) {\n\t\tif (outError) {\n\t\t\tNSMutableDictionary *userInfo = [NSMutableDictionary dictionary];\n\n\t\t\tuserInfo[NSURLErrorKey] = url;\n\n\t\t\tuserInfo[NSLocalizedDescriptionKey] = TXTLS(@\"TLOLicenseManager[b6l-ka]\", applicationName);\n\n\t\t\tuserInfo[NSLocalizedRecoverySuggestionErrorKey] = TXTLS(@\"TLOLicenseManager[sdj-xd]\");\n\n\t\t\t*outError = [NSError errorWithDomain:TXErrorDomain code:27984 userInfo:userInfo];\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n- (void)findTextualUsingLaunchServices\n{\n\tCFURLRef searchScopeURL = (__bridge CFURLRef)[NSURL URLWithString:@\"textual://knowledge-base\"];\n\n\tNSArray *matchedApplications = (__bridge_transfer NSArray *)LSCopyApplicationURLsForURL(searchScopeURL, kLSRolesViewer);\n\n\tNSURL *matchedApplication = nil;\n\n\tfor (NSURL *applicationURL in matchedApplications) {\n\t\tif ([self canUseApplicationAtURL:applicationURL applicationName:NULL]) {\n\t\t\tmatchedApplication = applicationURL;\n\n\t\t\tLogToConsoleInfo(\"Automatically detected Mac App Store Textual 7 at the following path: %{public}@\",\n\t\t\t\tmatchedApplication.standardizedTildePath);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (matchedApplication) {\n\t\t[self haveApplicationAtURL:matchedApplication];\n\t} else {\n\t\t[self presentOpenDialog];\n\t}\n}\n\n- (void)presentOpenDialog\n{\n\tNSOpenPanel *d = [NSOpenPanel openPanel];\n\n\tNSURL *applicationsPath = [TPCPathInfo systemApplicationsURL];\n\n\tif (applicationsPath) {\n\t\td.directoryURL = applicationsPath;\n\t}\n\n\td.allowedFileTypes = @[@\"app\"];\n\n\td.delegate = (id)self;\n\n\td.allowsMultipleSelection = NO;\n\td.canChooseDirectories = NO;\n\td.canChooseFiles = YES;\n\td.canCreateDirectories = NO;\n\td.resolvesAliases = YES;\n\n\td.message = TXTLS(@\"TLOLicenseManager[vft-qo]\");\n\n\td.prompt = TXTLS(@\"Prompts[xne-79]\");\n\n\t[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {\n\t\tif (result == NSModalResponseOK) {\n\t\t\t[self haveApplicationAtURL:d.URL];\n\t\t} else {\n\t\t\t[self cancel:nil];\n\t\t}\n\t}];\n}\n\n- (void)haveApplicationAtURL:(NSURL *)applicationURL\n{\n\tNSParameterAssert(applicationURL != nil);\n\n\tNSString *receiptData = [self receiptDataForApplicationAtURL:applicationURL];\n\n\tif (receiptData) {\n\t\tself.cachedReceiptData = receiptData;\n\n\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t[self startContactAddressSheet];\n\t\t});\n\n\t\treturn;\n\t}\n\n\t[self cancel:nil];\n}\n\n#pragma mark -\n#pragma mark Helper Methods\n\n- (nullable NSString *)receiptDataForApplicationAtURL:(NSURL *)applicationURL\n{\n\tNSParameterAssert(applicationURL != nil);\n\n\t/* Locate application bundle and determine whether the receipt\n\t file is even contained within it. */\n\tNSBundle *applicationBundle = [NSBundle bundleWithURL:applicationURL];\n\n\tif (applicationBundle == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *receiptFileURL = applicationBundle.appStoreReceiptURL;\n\n\tif (receiptFileURL == nil) {\n\t\treturn nil;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:receiptFileURL] == NO) {\n\t\treturn nil;\n\t}\n\n\t/* If the receipt file exists, request the data and cache the base64\n\t value of the receipt data. */\n\tNSError *receiptDataReadError = nil;\n\n\tNSData *receiptData = [NSData dataWithContentsOfURL:receiptFileURL options:0 error:&receiptDataReadError];\n\n\tif (receiptData == nil) {\n\t\tLogToConsoleError(\"Failed to read the contents of the receipt file '%{public}@': %{public}@\",\n\t\t\treceiptFileURL.standardizedTildePath, receiptDataReadError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\treturn [XRBase64Encoding encodeData:receiptData];\n}\n\n- (BOOL)canUseApplicationAtURL:(NSURL *)applicationURL applicationName:(NSString * _Nullable * _Nullable)applicationName\n{\n\t/* The license API performs validation of the uploaded receipt which\n\t means that the the only thing we need to know at this point is that\n\t the bundle identifier of the application is a known value and that\n\t the receipt file actually does exist in the application. */\n\tNSBundle *applicationBundle = [NSBundle bundleWithURL:applicationURL];\n\n\tif (applicationBundle == nil) {\n\t\treturn NO;\n\t}\n\n\t/* Pass to caller the application name of the bundle. */\n\tif ( applicationName) {\n\t\t*applicationName = applicationBundle.displayName;\n\t}\n\n\t/* Compare bundle identifier. */\n\t/* The bundle identifier used for comparison is hard coded is because\n\t the bundle identifier for the running copy can be different than the\n\t value that we are expecting from an older copy which we cannot change. */\n\tNSString *applicationBundleID = [applicationBundle objectForInfoDictionaryKey:@\"CFBundleIdentifier\"];\n\n\tif (applicationBundleID == nil ||\n\t\t([applicationBundleID isEqualToString:@\"com.codeux.irc.textual5\"] == NO &&\n\t\t [applicationBundleID isEqualToString:@\"com.codeux.apps.textual-mas\"] == NO))\n\t{\n\t\treturn NO;\n\t}\n\n\t/* Determine whether a receipt file exists. */\n\tNSURL *receiptFileURL = applicationBundle.appStoreReceiptURL;\n\n\tif (receiptFileURL == nil) {\n\t\treturn NO;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:receiptFileURL] == NO) {\n\t\treturn NO;\n\t}\n\n\t/* Return successful result */\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.delegate licenseManagerMigrateAppStoreSheetWillClose:self];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseManagerRecoverLostLicenseSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCLicenseManagerRecoverLostLicenseSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n#define _licenseOwnerContactAddressMaximumLength\t\t\t2000\n\n@interface TDCLicenseManagerRecoverLostLicenseSheet ()\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *contactAddressTextField;\n@end\n\n@implementation TDCLicenseManagerRecoverLostLicenseSheet\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseManagerRecoverLostLicenseSheet\" owner:self topLevelObjects:nil];\n}\n\n- (void)start\n{\n\tself.contactAddressTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.contactAddressTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.contactAddressTextField.textDidChangeCallback = self;\n\n\tself.contactAddressTextField.stringValue = [XRAddressBook myEmailAddress];\n\n\tself.contactAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\tif (currentValue.length > _licenseOwnerContactAddressMaximumLength) {\n\t\t\treturn TXTLS(@\"CommonErrors[2cb-af]\", _licenseOwnerContactAddressMaximumLength);\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t[self startSheet];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *contactAddress = self.contactAddressTextField.value;\n\n\t[self.delegate licenseManagerRecoverLostLicenseSheet:self onOk:contactAddress];\n\n\t[super ok:sender];\n}\n\n- (BOOL)okOrError\n{\n\treturn [self okOrErrorForTextField:self.contactAddressTextField];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.delegate licenseManagerRecoverLostLicenseSheetWillClose:self];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeActivateSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TDCLicenseUpgradeActivateSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseUpgradeActivateSheet ()\n@property (nonatomic, copy, readwrite) NSString *licenseKey;\n@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;\n@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleDiscount;\n@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleFree;\n@property (nonatomic, weak) IBOutlet NSTextField *sheetEligibleDiscountTitleTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *sheetEligibleFreeTitleTextField;\n@property (nonatomic, weak) IBOutlet NSButton *sheetEligibleDiscountSuppressionButton;\n@property (nonatomic, weak) IBOutlet NSButton *sheetEligibleFreeSuppressionButton;\n\n- (IBAction)actionActivateLicense:(id)sender;\n- (IBAction)actionPurchaseUpgrade:(id)sender;\n- (IBAction)actionCancel:(id)sender;\n@end\n\n@implementation TDCLicenseUpgradeActivateSheet\n\n#pragma mark -\n#pragma mark Dialog Foundation\n\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey eligibility:(TLOLicenseUpgradeEligibility)eligibility\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.licenseKey = licenseKey;\n\n\t\tself.eligibility = eligibility;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseUpgradeActivateSheet\" owner:self topLevelObjects:nil];\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)startSheet\n{\n\tNSTextField *sheetTitleTextField = nil;\n\n\tif (self.eligibility == TLOLicenseUpgradeEligibilityDiscount)\n\t{\n\t\tself.sheet = self.sheetEligibleDiscount;\n\n\t\tsheetTitleTextField = self.sheetEligibleDiscountTitleTextField;\n\t}\n\telse if (self.eligibility == TLOLicenseUpgradeEligibilityFree ||\n\t\t\t self.eligibility == TLOLicenseUpgradeEligibilityAlreadyUpgraded)\n\t{\n\t\tself.sheet = self.sheetEligibleFree;\n\n\t\tsheetTitleTextField = self.sheetEligibleFreeTitleTextField;\n\t}\n\telse\n\t{\n\t\tNSAssert(NO, @\"Cannot display a sheet for this type of eligibility\");\n\t}\n\n\tsheetTitleTextField.stringValue =\n\t[NSString stringWithFormat:\n\t\t sheetTitleTextField.stringValue, self.licenseKey.prettyLicenseKey];\n\n\t[super startSheet];\n}\n\n- (void)actionActivateLicense:(id)sender\n{\n\t[self.delegate upgradeActivateSheetActivateLicense:self];\n}\n\n- (void)actionPurchaseUpgrade:(id)sender\n{\n\t[self.delegate upgradeActivateSheetPurchaseUpgrade:self];\n}\n\n- (void)actionCancel:(id)sender\n{\n\t/* Only one of two sheets can ever be visible so just check if one is on. */\n\tif (self.sheetEligibleDiscountSuppressionButton.state == NSControlStateValueOn ||\n\t\tself.sheetEligibleFreeSuppressionButton.state == NSControlStateValueOn)\n\t{\n\t\t[self.delegate upgradeActivateSheetSuppressed:self];\n\t}\n\n\t[self endSheet];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.delegate upgradeActivateSheetWillClose:self];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeCommonActions.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TLOpenLink.h\"\n#import \"TDCLicenseUpgradeCommonActionsPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@implementation TDCLicenseUpgradeCommonActions\n\n+ (void)contactSupport\n{\n\t[menuController() contactSupport:nil];\n}\n\n+ (void)activateLicense:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\t[menuController() manageLicense:nil activateLicenseKey:licenseKey];\n}\n\n+ (void)purchaseUpgradeForLicense:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tNSString *linkToOpen = [NSString stringWithFormat:@\"https://www.codeux.com/textual/version-7-upgrade/upgradeLicense/%@\", licenseKey];\n\n\t[TLOpenLink openWithString:linkToOpen inBackground:NO];\n}\n\n+ (void)learnMore\n{\n\tNSURL *urlToOpen = [NSURL URLWithString:@\"https://www.codeux.com/textual/version-7-upgrade/learnMore\"];\n\n\t[TLOpenLink open:urlToOpen inBackground:NO];\n}\n\n+ (void)openStandaloneStore\n{\n\t[menuController() openStandaloneStoreWebpage:nil];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeDialog.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TDCLicenseUpgradeCommonActionsPrivate.h\"\n#import \"TDCLicenseUpgradeDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseUpgradeDialog ()\n@property (nonatomic, copy, readwrite) NSString *licenseKey;\n@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;\n@property (nonatomic, strong, nullable) TDCLicenseUpgradeEligibilitySheet *EligibilitySheet;\n@property (nonatomic, weak) IBOutlet NSButton *upgradeDialogContinueTrialButton;\n@property (nonatomic, weak) IBOutlet NSTextField *upgradeDialogTrialPeriodTextField;\n\n- (IBAction)actionLearnMore:(id)sender;\n- (IBAction)actionPurchaseUpgrade:(id)sender;\n- (IBAction)actionContinueTrial:(id)sender;\n- (IBAction)actionRemindMeLater:(id)sender;\n@end\n\n@implementation TDCLicenseUpgradeDialog\n\n#pragma mark -\n#pragma mark Dialog Foundation\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tif ((self = [super init])) {\n\t\tself.licenseKey = licenseKey;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseUpgradeDialog\" owner:self topLevelObjects:nil];\n\n\tself.eligibility = TLOLicenseUpgradeEligibilityUnknown;\n}\n\n- (void)show\n{\n\tself.upgradeDialogContinueTrialButton.enabled = (TLOLicenseManagerIsTrialExpired() == NO);\n\n\tself.upgradeDialogTrialPeriodTextField.stringValue = [[TXSharedApplication sharedLicenseManagerDialog] timeRemainingInTrialFormattedMessage];\n\n\t[super show];\n}\n\n#pragma mark -\n#pragma mark Eligibility Sheet Actions\n\n- (void)checkEligibility\n{\n\tif (self.EligibilitySheet != nil) {\n\t\treturn;\n\t}\n\n\t  TDCLicenseUpgradeEligibilitySheet *eligibilitySheet =\n\t[[TDCLicenseUpgradeEligibilitySheet alloc] initWithLicenseKey:self.licenseKey];\n\n\teligibilitySheet.delegate = self;\n\n\teligibilitySheet.window = self.window;\n\n\t[eligibilitySheet checkEligibility];\n\n\tself.EligibilitySheet = eligibilitySheet;\n}\n\n- (void)closeEligibilitySheet\n{\n\tif (self.EligibilitySheet) {\n\t\t[self.EligibilitySheet endSheet];\n\t}\n}\n\n- (void)upgradeEligibilitySheetContactSupport:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\t[TDCLicenseUpgradeCommonActions contactSupport];\n}\n\n- (void)upgradeEligibilitySheetActivateLicense:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\t[TDCLicenseUpgradeCommonActions activateLicense:sender.licenseKey];\n}\n\n- (void)upgradeEligibilitySheetPurchaseUpgrade:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\t[TDCLicenseUpgradeCommonActions purchaseUpgradeForLicense:sender.licenseKey];\n}\n\n- (void)upgradeEligibilitySheetPurchaseStandalone:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\t[TDCLicenseUpgradeCommonActions openStandaloneStore];\n}\n\n- (void)upgradeEligibilitySheetChanged:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\tself.eligibility = sender.eligibility;\n\n\t[self.delegate licenseUpgradeDialogEligibilityChanged:self];\n}\n\n- (void)upgradeEligibilitySheetWillClose:(TDCLicenseUpgradeEligibilitySheet *)sender\n{\n\tself.EligibilitySheet = nil;\n}\n\n#pragma mark -\n#pragma mark Upgrade Dialog Actions\n\n- (void)actionLearnMore:(id)sender\n{\n\t[TDCLicenseUpgradeCommonActions learnMore];\n}\n\n- (void)actionPurchaseUpgrade:(id)sender\n{\n\t[self checkEligibility];\n}\n\n- (void)actionContinueTrial:(id)sender\n{\n\t[self.delegate licenseUpgradeDialogWRemindMeLater:self];\n\n\t[self close];\n}\n\n- (void)actionRemindMeLater:(id)sender\n{\n\t[self.delegate licenseUpgradeDialogWRemindMeLater:self];\n\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self closeEligibilitySheet];\n\n\t[self.delegate licenseUpgradeDialogWillClose:self];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/License Manager/Standalone/TDCLicenseUpgradeEligibilitySheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TXGlobalModels.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLicenseManagerDownloaderPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCProgressIndicatorSheetPrivate.h\"\n#import \"TDCLicenseUpgradeEligibilitySheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseUpgradeEligibilitySheet ()\n@property (nonatomic, copy, readwrite) NSString *licenseKey;\n@property (nonatomic, assign, readwrite) TLOLicenseUpgradeEligibility eligibility;\n@property (nonatomic, strong) TLOLicenseManagerDownloader *licenseManagerDownloader;\n@property (nonatomic, strong) TDCProgressIndicatorSheet *progressIndicator;\n@property (nonatomic, strong) IBOutlet NSWindow *sheetNotEligible;\n@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleDiscount;\n@property (nonatomic, strong) IBOutlet NSWindow *sheetEligibleFree;\n@property (nonatomic, assign) BOOL checkingEligibility;\n\n- (IBAction)actionContactSupport:(id)sender;\n- (IBAction)actionActivateLicense:(id)sender;\n- (IBAction)actionPurchaseUpgrade:(id)sender;\n- (IBAction)actionPurchaseStandalone:(id)sender;\n- (IBAction)actionClose:(id)sender;\n@end\n\n@implementation TDCLicenseUpgradeEligibilitySheet\n\n#pragma mark -\n#pragma mark Dialog Foundation\n\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.licenseKey = licenseKey;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCLicenseUpgradeEligibilitySheet\" owner:self topLevelObjects:nil];\n\n\tself.eligibility = TLOLicenseUpgradeEligibilityUnknown;\n}\n\n- (void)startSheet\n{\n\tLogToConsoleError(\"This method does nothing. Use -checkEligibility instead\");\n\tLogStackTrace();\n}\n\n- (void)endSheet\n{\n\t[self _cancelEligibilityCheck];\n\n\t[super endSheet];\n}\n\n- (void)endSheetEarly\n{\n\t/* If we end sheet early, before self.sheet is ever defined,\n\t then trying to close it wont fire this delegate call.\n\t We fake the call to the delegate so that the sheet can be released. */\n\t[self windowWillClose:nil];\n}\n\n- (void)checkEligibility\n{\n\t[self _checkEligibility];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)_beginProgressIndicator\n{\n\t[self _beginProgressIndicatorInWindow:self.window];\n}\n\n- (void)_beginProgressIndicatorInWindow:(NSWindow *)window\n{\n\tself.progressIndicator = [[TDCProgressIndicatorSheet alloc] initWithWindow:window];\n\n\t[self.progressIndicator start];\n}\n\n- (void)_endProgressIndicator\n{\n\tif (self.progressIndicator == nil) {\n\t\treturn;\n\t}\n\n\t[self.progressIndicator stop];\n\n\tself.progressIndicator = nil;\n}\n\n#pragma mark -\n#pragma mark Eligibility Sheet Actions\n\n- (void)_presentEligibilityCheckFailedSheetWithError:(NSString *)errorMessage\n{\n\tNSParameterAssert(errorMessage != nil);\n\n\t[TDCAlert alertSheetWithWindow:self.window\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[8hb-y3]\", errorMessage)\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[wmk-xg]\", self.licenseKey.prettyLicenseKey)\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[dn3-4r]\")\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t   if (buttonClicked == TDCAlertResponseAlternate) {\n\t\t\t\t\t\t   [self actionContactSupport:nil];\n\t\t\t\t\t   }\n\t\t\t\t\t   \n\t\t\t\t\t   [self endSheetEarly];\n\t\t\t\t   }];\n}\n\n- (void)_cancelEligibilityCheck\n{\n\tif (self.checkingEligibility == NO) {\n\t\treturn;\n\t}\n\n\t[self.licenseManagerDownloader cancelRequest];\n\n\t[self _checkEligibilityCompletionBlock];\n}\n\n- (void)_checkEligibility\n{\n\tif (self.eligibility != TLOLicenseUpgradeEligibilityUnknown) {\n\t\t[self _eligibilityDetermined];\n\n\t\treturn;\n\t}\n\n\t[self _checkEligibilityOfLicense:self.licenseKey];\n}\n\n- (void)_checkEligibilityOfLicense:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tif (self.checkingEligibility == NO) {\n\t\tself.checkingEligibility = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\t[self _beginProgressIndicator];\n\n\t__weak TDCLicenseUpgradeEligibilitySheet *weakSelf = self;\n\n\tTLOLicenseManagerDownloader *licenseManagerDownloader = [TLOLicenseManagerDownloader new];\n\n\tlicenseManagerDownloader.completionBlock = ^(BOOL operationSuccessful, NSUInteger statusCode, id _Nullable statusContext) {\n\t\t[weakSelf _checkEligibilityCompletionBlock];\n\n\t\t[weakSelf _extractEligibilityFromResponseWithStatusCode:statusCode statusContext:statusContext];\n\t};\n\n\tlicenseManagerDownloader.isSilentOnFailure = YES;\n\tlicenseManagerDownloader.isSilentOnSuccess = YES;\n\n\t[licenseManagerDownloader checkUpgradeEligibilityOfLicense:licenseKey];\n\n\tself.licenseManagerDownloader = licenseManagerDownloader;\n}\n\n- (void)_checkEligibilityCompletionBlock\n{\n\tself.licenseManagerDownloader = nil;\n\n\t[self _endProgressIndicator];\n\n\tself.checkingEligibility = NO;\n}\n\n- (void)_extractEligibilityFromResponseWithStatusCode:(NSUInteger)statusCode statusContext:(nullable NSDictionary<NSString *, id> *)statusContext\n{\n\tLogToConsoleDebug(\"Status code: %{public}lu\", statusCode);\n\n#define _presentEligibilityCheckFailedSheet \t\\\n\t[self _presentEligibilityCheckFailedSheetWithError:errorMessage]; \t\\\n\treturn;\n\n\t/* Check for common status codes. */\n\tif (statusCode != 0) {\n\t\tNSString *errorMessage = nil;\n\n\t\tif (statusCode == TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy) {\n\t\t\terrorMessage = TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[9uu-go]\");\n\t\t} else {\n\t\t\terrorMessage = TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[awy-4i]\", statusCode);\n\t\t}\n\n\t\t_presentEligibilityCheckFailedSheet\n\t}\n\n\t/* There is never a time a status context should be nil for this check. */\n\tif (statusContext == nil) {\n\t\tNSString *errorMessage = TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[z70-6s]\");\n\n\t\t_presentEligibilityCheckFailedSheet\n\t}\n\n\t/* Ensure the response we received is a type we support. */\n\tid eligibilityObject = statusContext[@\"licenseUpgradeEligibility\"];\n\n\tif (eligibilityObject == nil || [eligibilityObject isKindOfClass:[NSNumber class]] == NO) {\n\t\tLogToConsoleError(\"'licenseUpgradeEligibility' is nil or not of kind 'NSNumber'\");\n\n\t\tNSString *errorMessage = TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[gc5-ko]\");\n\n\t\t_presentEligibilityCheckFailedSheet\n\t}\n\n\t/* Save eligibility */\n\tNSUInteger eligibility = [eligibilityObject unsignedIntegerValue];\n\n\tif (eligibility != TLOLicenseUpgradeEligibilityDiscount &&\n\t\teligibility != TLOLicenseUpgradeEligibilityFree &&\n\t\teligibility != TLOLicenseUpgradeEligibilityNot &&\n\t\teligibility != TLOLicenseUpgradeEligibilityAlreadyUpgraded)\n\t{\n\t\tNSString *errorMessage = TXTLS(@\"TDCLicenseUpgradeEligibilitySheet[5s6-sb]\", eligibility);\n\n\t\t_presentEligibilityCheckFailedSheet\n\t}\n\n\tself.eligibility = eligibility;\n\n\t/* Present sheet */\n\t[self _eligibilityDetermined];\n\n\t/* Inform delegate */\n\t[self.delegate upgradeEligibilitySheetChanged:self];\n\n#undef _presentEligibilityCheckFailedSheet\n}\n\n- (void)_eligibilityDetermined\n{\n\tif (self.eligibility == TLOLicenseUpgradeEligibilityDiscount) {\n\t\tself.sheet = self.sheetEligibleDiscount;\n\t} else if (self.eligibility == TLOLicenseUpgradeEligibilityNot) {\n\t\tself.sheet = self.sheetNotEligible;\n\t} else if (self.eligibility == TLOLicenseUpgradeEligibilityFree ||\n\t\t\t   self.eligibility == TLOLicenseUpgradeEligibilityAlreadyUpgraded)\n\t{\n\t\tself.sheet = self.sheetEligibleFree;\n\t}\n\n\t[super startSheet];\n}\n\n- (void)actionContactSupport:(id)sender\n{\n\t[self.delegate upgradeEligibilitySheetContactSupport:self];\n}\n\n- (void)actionActivateLicense:(id)sender\n{\n\t[self.delegate upgradeEligibilitySheetActivateLicense:self];\n}\n\n- (void)actionPurchaseUpgrade:(id)sender\n{\n\t[self.delegate upgradeEligibilitySheetPurchaseUpgrade:self];\n}\n\n- (void)actionPurchaseStandalone:(id)sender\n{\n\t[self.delegate upgradeEligibilitySheetPurchaseStandalone:self];\n}\n\n- (void)actionClose:(id)sender\n{\n\t[self endSheet];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.delegate upgradeEligibilitySheetWillClose:self];\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Preferences/TDCPreferencesController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelper.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesReload.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCThemeControllerPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"IRC.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClient.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCWorld.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.H\"\n#import \"TVCNotificationConfigurationViewControllerPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n#import \"TDCPreferencesNotificationConfigurationPrivate.h\"\n#import \"TDCPreferencesUserStyleSheetPrivate.h\"\n#import \"TDCPreferencesControllerPrivate.h\"\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n#import <Sparkle/Sparkle.h>\n#endif\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _scrollbackSaveLinesMin\t\t100\n#define _scrollbackSaveLinesMax\t\t50000\n#define _scrollbackVisibleLinesMin\t100\n#define _scrollbackVisibleLinesMax\t15000\n#define _inlineMediaWidthMax\t\t2000\n#define _inlineMediaWidthMin\t\t40\n#define _inlineMediaHeightMax\t\t6000\n#define _inlineMediaHeightMin\t\t0\n\n#define _fileTransferPortRangeMin\t\t\t1024\n#define _fileTransferPortRangeMax\t\t\tTXMaximumTCPPort\n\n#define _toolbarItemIndexGeneral\t\t\t\t\t101\n#define _toolbarItemIndexHighlights\t\t\t\t\t104\n#define _toolbarItemIndexNotifications\t\t\t\t103\n#define _toolbarItemIndexBehavior\t\t\t\t\t102\n#define _toolbarItemIndexControls\t\t\t\t\t107\n#define _toolbarItemIndexInterface\t\t\t\t\t105\n#define _toolbarItemIndexStyle\t\t\t\t\t\t106\n#define _toolbarItemIndexAddons\t\t\t\t\t\t109\n#define _toolbarItemIndexAdvanced\t\t\t\t\t108\n\n#define _toolbarItemIndexChannelManagement\t\t\t108000\n#define _toolbarItemIndexCommandScope\t\t\t\t108001\n#define _toolbarItemIndexFloodControl\t\t\t\t108002\n#define _toolbarItemIndexIncomingData\t\t\t\t108003\n#define _toolbarItemIndexCompatibility\t\t\t\t108004\n#define _toolbarItemIndexFileTransfers\t\t\t\t108005\n#define _toolbarItemIndexInlineMedia\t\t\t\t108006\n#define _toolbarItemIndexLogLocation\t\t\t\t108007\n#define _toolbarItemIndexDefaultIdentity\t\t\t108008\n#define _toolbarItemIndexDefaultIRCopMessages\t\t108009\n#define _toolbarItemIndexOffRecordMessaging\t\t\t108010\n#define _toolbarItemIndexHiddenPreferences\t\t\t108011 // unused\n\n#define _addonsToolbarInstalledAddonsMenuItemIndex\t\t109000\n#define _addonsToolbarItemMultiplier\t\t\t\t\t995\n\n#define _unsignedIntegerString(_value_)\t\t\t[NSString stringWithUnsignedInteger:_value_]\n\n@interface TDCPreferencesController ()\n@property (nonatomic, strong) IBOutlet NSArrayController *excludeKeywordsArrayController;\n@property (nonatomic, strong) IBOutlet NSArrayController *highlightKeywordsArrayController;\n@property (nonatomic, strong) IBOutlet NSArrayController *installedScriptsController;\n@property (nonatomic, weak) IBOutlet NSButton *addExcludeKeywordButton;\n@property (nonatomic, weak) IBOutlet NSButton *highlightNicknameButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *themeSelectionButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *transcriptFolderButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *fileTransferDownloadDestinationButton;\n@property (nonatomic, weak) IBOutlet NSTableView *excludeKeywordsTable;\n@property (nonatomic, weak) IBOutlet NSTableView *installedScriptsTable;\n@property (nonatomic, weak) IBOutlet NSTableView *highlightKeywordsTable;\n@property (nonatomic, weak) IBOutlet NSTextField *fileTransferManuallyEnteredIPAddressTextField;\n@property (nonatomic, strong) IBOutlet NSView *contentViewGeneral;\n@property (nonatomic, strong) IBOutlet NSView *contentViewHighlights;\n@property (nonatomic, strong) IBOutlet NSView *contentViewNotifications;\n@property (nonatomic, strong) IBOutlet NSView *contentViewBehavior;\n@property (nonatomic, strong) IBOutlet NSView *contentViewControls;\n@property (nonatomic, strong) IBOutlet NSView *contentViewInterface;\n@property (nonatomic, strong) IBOutlet NSView *contentViewStyle;\n@property (nonatomic, strong) IBOutlet NSView *contentViewInstalledAddons;\n@property (nonatomic, strong) IBOutlet NSView *contentViewChannelManagement;\n@property (nonatomic, strong) IBOutlet NSView *contentViewCommandScope;\n@property (nonatomic, strong) IBOutlet NSView *contentViewCompatibility;\n@property (nonatomic, strong) IBOutlet NSView *contentViewFloodControl;\n@property (nonatomic, strong) IBOutlet NSView *contentViewIncomingData;\n@property (nonatomic, strong) IBOutlet NSView *contentViewFileTransfers;\n@property (nonatomic, strong) IBOutlet NSView *contentViewInlineMedia;\n@property (nonatomic, strong) IBOutlet NSView *contentViewLogLocation;\n@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultIdentity;\n@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultIRCopMessages;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@property (nonatomic, strong) IBOutlet NSView *contentViewOffRecordMessaging;\n#endif\n\n@property (nonatomic, strong) IBOutlet NSView *contentViewHiddenPreferences;\n@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesDontCheck;\n@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesAutomaticallyCheck;\n@property (nonatomic, weak) IBOutlet NSButton *checkForUpdatesAutomaticallyDownload;\n@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToServerConsoleButton;\n@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToSelectedChannelButton;\n@property (nonatomic, weak) IBOutlet NSButton *forwardNoticeToQueryButton;\n@property (nonatomic, weak) IBOutlet NSButton *inlineMediaEnabledButton;\n@property (nonatomic, weak) IBOutlet NSStackView *contentViewGeneralStackView;\n@property (nonatomic, weak) IBOutlet NSView *contentViewGeneralCheckForUpdatesView;\n@property (nonatomic, weak) IBOutlet NSView *contentViewGeneralShareDataView;\n@property (nonatomic, strong) IBOutlet NSToolbar *navigationToolbar;\n@property (nonatomic, strong) IBOutlet NSMenu *installedAddonsMenu;\n@property (nonatomic, assign) BOOL reloadingTheme;\n@property (nonatomic, assign) BOOL reloadingThemeBySelection;\n@property (nonatomic, weak) IBOutlet NSView *notificationControllerHostView;\n@property (nonatomic, strong) IBOutlet TVCNotificationConfigurationViewController *notificationController;\n@property (nonatomic, strong) TDCPreferencesUserStyleSheet *userStyleSheet;\n\n- (IBAction)onAddExcludeKeyword:(id)sender;\n- (IBAction)onAddHighlightKeyword:(id)sender; // changed\n- (IBAction)onChangedAppearance:(id)sender;\n- (IBAction)onChangedCheckForUpdates:(id)sender;\n- (IBAction)onChangedCheckForBetaUpdates:(id)sender;\n- (IBAction)onChangedChannelViewArrangement:(id)sender;\n- (IBAction)onChangedDisableNicknameColorHashing:(id)sender;\n- (IBAction)onChangedForwardNoticeTo:(id)sender;\n- (IBAction)onChangedHighlightLogging:(id)sender;\n- (IBAction)onChangedHighlightType:(id)sender;\n- (IBAction)onChangedInlineMediaOption:(id)sender;\n- (IBAction)onChangedInputHistoryScheme:(id)sender;\n- (IBAction)onChangedMainInputTextViewFontSize:(id)sender; // changed\n- (IBAction)onChangedMainWindowSegmentedController:(id)sender;\n- (IBAction)onChangedScrollbackSaveLimit:(id)sender;\n- (IBAction)onChangedScrollbackVisibleLimit:(id)sender;\n- (IBAction)onChangedServerListUnreadBadgeColor:(id)sender;\n- (IBAction)onChangedTheme:(id)sender;\n- (IBAction)onChangedThemeSelection:(id)sender;  // changed\n- (IBAction)onChangedTranscriptFolder:(id)sender;\n- (IBAction)onChangedTransparency:(id)sender;\n- (IBAction)onChangedUserListModeColor:(id)sender;\n- (IBAction)onChangedUserListModeSortOrder:(id)sender;\n- (IBAction)onFileTransferDownloadDestinationFolderChanged:(id)sender;\n- (IBAction)onFileTransferIPAddressDetectionMethodChanged:(id)sender;\n- (IBAction)onModifyUserStyleSheetRules:(id)sender;\n- (IBAction)onOpenPathToScripts:(id)sender;\n- (IBAction)onOpenPathToTheme:(id)sender; // changed\n- (IBAction)onPrefPaneSelected:(id)sender;\n- (IBAction)onResetServerListUnreadBadgeColorsToDefault:(id)sender;\n- (IBAction)onResetUserListModeColorsToDefaults:(id)sender;\n- (IBAction)onSelectNewFont:(id)sender;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (IBAction)offRecordMessagingPolicyChanged:(id)sender;\n- (IBAction)offRecordMessagingOpenOfficialWebsite:(id)sender;\n- (IBAction)offRecordMessagingOpenHelpDocument:(id)sender;\n#endif\n@end\n\n@implementation TDCPreferencesController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCPreferences\" owner:self topLevelObjects:nil];\n}\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tNSMutableArray *notifications = [NSMutableArray array];\n\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeAddressBookMatch]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeConnect]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeDisconnect]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeHighlight]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeInvite]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeKick]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeChannelMessage]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeChannelNotice]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeNewPrivateMessage]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypePrivateMessage]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypePrivateNotice]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserJoined]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserParted]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeUserDisconnected]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveRequested]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferSendSuccessful]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveSuccessful]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferSendFailed]];\n\t[notifications addObject:[TDCPreferencesNotificationConfiguration objectWithEventType:TXNotificationTypeFileTransferReceiveFailed]];\n\n\tself.notificationController.notifications = notifications;\n\n\t[self.notificationController attachToView:self.notificationControllerHostView];\n\n\t[self setUpToolbarItemsAndMenus];\n\n\t[self updateCheckForUpdatesMatrix];\n\t[self updateFileTransferDownloadDestinationFolder];\n\t[self updateForwardNoticeToMatrix];\n\t[self updateInlineMediaEnabled];\n\t[self updateThemeSelection];\n\t[self updateTranscriptFolder];\n\n\t[self onChangedHighlightType:nil];\n\n\t[self onFileTransferIPAddressDetectionMethodChanged:nil];\n\n\tself.installedScriptsTable.sortDescriptors = @[\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"string\" ascending:YES selector:@selector(caseInsensitiveCompare:)]\n\t];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(onThemeListDidChange:)\n\t\t\t\t\t\t\t\t   name:TPCThemeControllerThemeListDidChangeNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(onThemeWillReload:)\n\t\t\t\t\t\t\t\t   name:TVCMainWindowWillReloadThemeNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(onThemeReloadComplete:)\n\t\t\t\t\t\t\t\t   name:TVCMainWindowDidReloadThemeNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 0\n\t/* Hide preferences for updates when support is not enabled. */\n\t[self.contentViewGeneralStackView setVisibilityPriority:NSStackViewVisibilityPriorityNotVisible\n\t\t\t\t\t\t\t\t\t\t\t\t\tforView:self.contentViewGeneralCheckForUpdatesView];\n#endif\n\n\t[self.contentViewGeneral layoutSubtreeIfNeeded];\n\n\t[self restoreWindowFrame];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)show\n{\n\t[self show:TDCPreferencesControllerSelectionDefault];\n}\n\n- (void)show:(TDCPreferencesControllerSelection)selection\n{\n\tswitch (selection) {\n\t\tcase TDCPreferencesControllerSelectionNotifications:\n\t\t{\n\t\t\t[self _showPane:self.contentViewNotifications selectedItem:_toolbarItemIndexNotifications];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCPreferencesControllerSelectionStyle:\n\t\t{\n\t\t\t[self _showPane:self.contentViewStyle selectedItem:_toolbarItemIndexStyle];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TDCPreferencesControllerSelectionHiddenPreferences:\n\t\t{\n\t\t\t[self _showPane:self.contentViewHiddenPreferences selectedItem:_toolbarItemIndexAdvanced];\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t[self _showPane:self.contentViewGeneral selectedItem:_toolbarItemIndexGeneral];\n\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n- (void)_showPane:(NSView *)view selectedItem:(NSInteger)selectedItem\n{\n\t[self firstPane:view selectedItem:selectedItem];\n\n\t[super show];\n}\n\n#pragma mark -\n#pragma mark NSToolbar Delegates\n\n - (void)setUpToolbarItemsAndMenus\n{\n\tNSArray *plugins = sharedPluginManager().pluginsWithPreferencePanes;\n\n\tif (plugins.count > 0) {\n\t\t[self.installedAddonsMenu addItem:[NSMenuItem separatorItem]];\n\t}\n\n\t[plugins enumerateObjectsUsingBlock:^(THOPluginItem *plugin, NSUInteger index, BOOL *stop) {\n\t\tNSUInteger tagIndex = (index + _addonsToolbarItemMultiplier);\n\n\t\tNSMenuItem *pluginMenu = [NSMenuItem menuItemWithTitle:plugin.pluginPreferencesPaneMenuItemTitle\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttarget:self\n\t\t\t\t\t\t\t\t\t\t\t\t\t\taction:@selector(onPrefPaneSelected:)];\n\n\t\tpluginMenu.tag = tagIndex;\n\n\t\t[self.installedAddonsMenu addItem:pluginMenu];\n\t}];\n}\n\n - (void)onPrefPaneSelected:(id)sender\n{\n#define _de(matchTag, view, selectionIndex)\t\t\\\n\t\tcase (matchTag): {\t\\\n\t\t\t[self firstPane:(view) selectedItem:(selectionIndex)];\t\\\n\t\t\tbreak;\t\t\\\n\t\t}\n\n\tswitch ([sender tag]) {\n\n\t\t_de(_toolbarItemIndexGeneral, self.contentViewGeneral, _toolbarItemIndexGeneral)\n\n\t\t_de(_toolbarItemIndexHighlights, self.contentViewHighlights, _toolbarItemIndexHighlights)\n\t\t_de(_toolbarItemIndexNotifications, self.contentViewNotifications, _toolbarItemIndexNotifications)\n\n\t\t_de(_toolbarItemIndexBehavior, self.contentViewBehavior, _toolbarItemIndexBehavior)\n\t\t_de(_toolbarItemIndexControls, self.contentViewControls, _toolbarItemIndexControls)\n\t\t_de(_toolbarItemIndexInterface, self.contentViewInterface, _toolbarItemIndexInterface)\n\t\t_de(_toolbarItemIndexStyle, self.contentViewStyle, _toolbarItemIndexStyle)\n\n\t\t_de(_toolbarItemIndexChannelManagement, self.contentViewChannelManagement, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexCommandScope, self.contentViewCommandScope, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexCompatibility, self.contentViewCompatibility, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexFloodControl, self.contentViewFloodControl, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexIncomingData, self.contentViewIncomingData, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexFileTransfers, self.contentViewFileTransfers, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexInlineMedia, self.contentViewInlineMedia, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexLogLocation, self.contentViewLogLocation, _toolbarItemIndexAdvanced);\n\t\t_de(_toolbarItemIndexDefaultIdentity, self.contentViewDefaultIdentity, _toolbarItemIndexAdvanced)\n\t\t_de(_toolbarItemIndexDefaultIRCopMessages, self.contentViewDefaultIRCopMessages, _toolbarItemIndexAdvanced)\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t\t_de(_toolbarItemIndexOffRecordMessaging, self.contentViewOffRecordMessaging, _toolbarItemIndexAdvanced)\n#endif\n\n\t\t_de(_addonsToolbarInstalledAddonsMenuItemIndex, self.contentViewInstalledAddons, _toolbarItemIndexAddons)\n\n\t\tdefault:\n\t\t{\n\t\t\tif ([sender tag] < _addonsToolbarItemMultiplier) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSUInteger pluginIndex = ([sender tag] - _addonsToolbarItemMultiplier);\n\n\t\t\tTHOPluginItem *plugin = sharedPluginManager().pluginsWithPreferencePanes[pluginIndex];\n\n\t\t\tNSView *preferencesView = plugin.pluginPreferencesPaneView;\n\n\t\t\t[self firstPane:preferencesView selectedItem:_toolbarItemIndexAddons];\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n#undef _de\n}\n\n- (void)firstPane:(NSView *)view selectedItem:(NSInteger)selectedItem\n{\n\t[self.window replaceContentView:view];\n\n\tif (selectedItem >= 0) {\n\t\tself.navigationToolbar.selectedItemIdentifier = _unsignedIntegerString(selectedItem);\n\t} else {\n\t\tself.navigationToolbar.selectedItemIdentifier = nil;\n\t}\n}\n\n- (void)restoreWindowFrame\n{\n\tNSWindow *window = self.window;\n\n\t[window saveSizeAsDefault];\n\n\t[window restoreWindowStateForClass:self.class];\n}\n\n- (void)saveWindowFrame\n{\n\tNSWindow *window = self.window;\n\n\t[window restoreDefaultSizeAndDisplay:NO];\n\n\t[window saveWindowStateForClass:self.class];\n}\n\n#pragma mark -\n#pragma mark KVC Properties\n\n- (NSArray<NSDictionary *> *)installedScripts\n{\n\tNSMutableArray *scriptsInstalled = [NSMutableArray array];\n\n\t[scriptsInstalled addObjectsFromArray:sharedPluginManager().supportedAppleScriptCommands];\n\t[scriptsInstalled addObjectsFromArray:sharedPluginManager().supportedUserInputCommands];\n\n\treturn scriptsInstalled.stringArrayControllerObjects;\n}\n\n- (NSString *)scrollbackSaveLimit\n{\n\treturn _unsignedIntegerString([TPCPreferences scrollbackSaveLimit]);\n}\n\n- (void)setScrollbackSaveLimit:(NSString *)value\n{\n\t[TPCPreferences setScrollbackSaveLimit:value.integerValue];\n}\n\n- (NSString *)scrollbackVisibleLimit\n{\n\treturn _unsignedIntegerString([TPCPreferences scrollbackVisibleLimit]);\n}\n\n- (void)setScrollbackVisibleLimit:(NSString *)value\n{\n\t[TPCPreferences setScrollbackVisibleLimit:value.integerValue];\n}\n\n- (NSString *)completionSuffix\n{\n\treturn [TPCPreferences tabCompletionSuffix];\n}\n\n- (void)setCompletionSuffix:(NSString *)value\n{\n\t[TPCPreferences setTabCompletionSuffix:value];\n}\n\n- (NSString *)inlineMediaMaxWidth\n{\n\treturn _unsignedIntegerString([TPCPreferences inlineMediaMaxWidth]);\n}\n\n- (NSString *)inlineMediaMaxHeight\n{\n\treturn _unsignedIntegerString([TPCPreferences inlineMediaMaxHeight]);\n}\n\n- (void)setInlineMediaMaxWidth:(NSString *)value\n{\n\t[TPCPreferences setInlineMediaMaxWidth:value.integerValue];\n}\n\n- (void)setInlineMediaMaxHeight:(NSString *)value\n{\n\t[TPCPreferences setInlineMediaMaxHeight:value.integerValue];\n}\n\n- (NSString *)themeChannelViewFontName\n{\n\tNSFont *currentFont = [TPCPreferences themeChannelViewFont];\n\n\treturn currentFont.displayName;\n}\n\n- (CGFloat)themeChannelViewFontSize\n{\n\treturn [TPCPreferences themeChannelViewFontSize];\n}\n\n- (void)setThemeChannelViewFontName:(NSString *)value\n{\n\treturn;\n}\n\n- (void)setThemeChannelViewFontSize:(CGFloat)value\n{\n\treturn;\n}\n\n- (NSString *)fileTransferPortRangeStart\n{\n\treturn _unsignedIntegerString([TPCPreferences fileTransferPortRangeStart]);\n}\n\n- (NSString *)fileTransferPortRangeEnd\n{\n\treturn _unsignedIntegerString([TPCPreferences fileTransferPortRangeEnd]);\n}\n\n- (void)setFileTransferPortRangeStart:(NSString *)value\n{\n\t[TPCPreferences setFileTransferPortRangeStart:value.integerValue];\n}\n\n- (void)setFileTransferPortRangeEnd:(NSString *)value\n{\n\t[TPCPreferences setFileTransferPortRangeEnd:value.integerValue];\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic\n{\n\t[TPCPreferences setTextEncryptionIsOpportunistic:textEncryptionIsOpportunistic];\n}\n\n- (BOOL)textEncryptionIsOpportunistic\n{\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\treturn NO;\n\t}\n\n\tif ([TPCPreferences textEncryptionIsRequired]) {\n\t\treturn YES;\n\t}\n\n\treturn [TPCPreferences textEncryptionIsOpportunistic];\n}\n\n- (BOOL)textEncryptionIsOpportunisticPreferenceEnabled\n{\n\treturn ([TPCPreferences textEncryptionIsEnabled] &&\n\t\t\t[TPCPreferences textEncryptionIsRequired] == NO);\n}\n\n- (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired\n{\n\t[TPCPreferences setTextEncryptionIsRequired:textEncryptionIsRequired];\n\n\t[self willChangeValueForKey:@\"textEncryptionIsOpportunistic\"];\n\t[self didChangeValueForKey:@\"textEncryptionIsOpportunistic\"];\n}\n\n- (BOOL)textEncryptionIsRequired\n{\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\treturn NO;\n\t}\n\n\treturn [TPCPreferences textEncryptionIsRequired];\n}\n\n- (BOOL)textEncryptionIsRequiredPreferenceEnabled\n{\n\treturn [TPCPreferences textEncryptionIsEnabled];\n}\n\n- (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled\n{\n\t[TPCPreferences setTextEncryptionIsEnabled:textEncryptionIsEnabled];\n\n\t[self willChangeValueForKey:@\"textEncryptionIsOpportunistic\"];\n\t[self willChangeValueForKey:@\"textEncryptionIsOpportunisticPreferenceEnabled\"];\n\t[self willChangeValueForKey:@\"textEncryptionIsRequired\"];\n\t[self willChangeValueForKey:@\"textEncryptionIsRequiredPreferenceEnabled\"];\n\n\t[self didChangeValueForKey:@\"textEncryptionIsOpportunistic\"];\n\t[self didChangeValueForKey:@\"textEncryptionIsOpportunisticPreferenceEnabled\"];\n\t[self didChangeValueForKey:@\"textEncryptionIsRequired\"];\n\t[self didChangeValueForKey:@\"textEncryptionIsRequiredPreferenceEnabled\"];\n}\n\n- (BOOL)textEncryptionIsEnabled\n{\n\treturn [TPCPreferences textEncryptionIsEnabled];\n}\n#else\n- (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic\n{\n\n}\n\n- (BOOL)textEncryptionIsOpportunistic\n{\n\n}\n\n- (BOOL)textEncryptionIsOpportunisticPreferenceEnabled\n{\n\n}\n\n- (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired\n{\n\n}\n\n- (BOOL)textEncryptionIsRequired\n{\n\n}\n\n- (BOOL)textEncryptionIsRequiredPreferenceEnabled\n{\n\n}\n\n- (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled\n{\n\n}\n\n- (BOOL)textEncryptionIsEnabled\n{\n\n}\n#endif\n\n- (BOOL)highlightCurrentNickname\n{\n\tif ([TPCPreferences highlightMatchingMethod] == TXNicknameHighlightMatchTypeRegularExpression) {\n\t\treturn NO;\n\t}\n\n\treturn [TPCPreferences highlightCurrentNickname];\n}\n\n- (void)setHighlightCurrentNickname:(BOOL)value\n{\n\t[TPCPreferences setHighlightCurrentNickname:value];\n}\n\n- (BOOL)appNapEnabled\n{\n\treturn [TPCPreferences appNapEnabled];\n}\n\n- (void)setAppNapEnabled:(BOOL)appNapEnabled\n{\n\t[TPCPreferences setAppNapEnabled:appNapEnabled];\n}\n\n- (BOOL)onlySpeakEventsForSelection\n{\n\treturn [TPCPreferences onlySpeakEventsForSelection];\n}\n\n- (void)setOnlySpeakEventsForSelection:(BOOL)onlySpeakEventsForSelection\n{\n\t[TPCPreferences setOnlySpeakEventsForSelection:onlySpeakEventsForSelection];\n\n\t[self willChangeValueForKey:@\"channelMessageSpeakChannelName\"];\n\t[self didChangeValueForKey:@\"channelMessageSpeakChannelName\"];\n}\n\n- (BOOL)channelMessageSpeakChannelName\n{\n\tif ([TPCPreferences onlySpeakEventsForSelection]) {\n\t\treturn NO;\n\t}\n\n\treturn [TPCPreferences channelMessageSpeakChannelName];\n}\n\n- (void)setChannelMessageSpeakChannelName:(BOOL)channelMessageSpeakChannelName\n{\n\t[TPCPreferences setChannelMessageSpeakChannelName:channelMessageSpeakChannelName];\n}\n\n- (BOOL)channelMessageSpeakNickname\n{\n\treturn [TPCPreferences channelMessageSpeakNickname];\n}\n\n- (void)setChannelMessageSpeakNickname:(BOOL)channelMessageSpeakNickname\n{\n\t[TPCPreferences setChannelMessageSpeakNickname:channelMessageSpeakNickname];\n}\n\n- (NSColor *)serverListUnreadCountBadgeHighlightColor\n{\n\tNSColor *value = [RZUserDefaults() colorForKey:@\"Server List Unread Message Count Badge Colors -> Highlight\"];\n\n\tif (value == nil) {\n\t\tvalue = [NSColor clearColor];\n\t}\n\n\treturn value;\n}\n\n- (void)setServerListUnreadCountBadgeHighlightColor:(NSColor *)serverListUnreadCountBadgeHighlightColor\n{\n\tNSColor *newValue = serverListUnreadCountBadgeHighlightColor;\n\n\tif ([newValue isEqual:[NSColor clearColor]]) {\n\t\tnewValue = nil;\n\t}\n\n\t[RZUserDefaults() setColor:newValue\n\t\t\t\t\t\tforKey:@\"Server List Unread Message Count Badge Colors -> Highlight\"];\n}\n\n- (NSColor *)userListNoModeColor\n{\n\tNSColor *value = [RZUserDefaults() colorForKey:@\"User List Mode Badge Colors -> no mode\"];\n\n\tif (value == nil) {\n\t\tvalue = [NSColor clearColor];\n\t}\n\n\treturn value;\n}\n\n- (void)setUserListNoModeColor:(NSColor *)userListNoModeColor\n{\n\tNSColor *newValue = userListNoModeColor;\n\n\tif ([newValue isEqual:[NSColor clearColor]]) {\n\t\tnewValue = nil;\n\t}\n\n\t[RZUserDefaults() setColor:newValue\n\t\t\t\t\t\tforKey:@\"User List Mode Badge Colors -> no mode\"];\n}\n\n- (BOOL)logTranscript\n{\n\treturn [TPCPreferences logToDisk];\n}\n\n- (void)setLogTranscript:(BOOL)logTranscript\n{\n\t[TPCPreferences setLogToDisk:logTranscript];\n}\n\n- (BOOL)inlineMediaLimitToBasics\n{\n\treturn [TPCPreferences inlineMediaLimitToBasics];\n}\n\n- (void)setInlineMediaLimitToBasics:(BOOL)inlineMediaLimitToBasics\n{\n\t[TPCPreferences setInlineMediaLimitToBasics:inlineMediaLimitToBasics];\n\n\t[self willChangeValueForKey:@\"inlineMediaLimitBasicsToFiles\"];\n\t[self didChangeValueForKey:@\"inlineMediaLimitBasicsToFiles\"];\n}\n\n- (BOOL)inlineMediaLimitBasicsToFiles\n{\n\t/* Show value as enabled when basics is disabled */\n\tif ([TPCPreferences inlineMediaLimitToBasics] == NO) {\n\t\treturn NO; // UI negates bool so return NO for YES\n\t}\n\n\treturn [TPCPreferences inlineMediaLimitBasicsToFiles];\n}\n\n- (void)setInlineMediaLimitBasicsToFiles:(BOOL)inlineMediaLimitBasicsToFiles\n{\n\t[TPCPreferences setInlineMediaLimitBasicsToFiles:inlineMediaLimitBasicsToFiles];\n}\n\n- (BOOL)validateValue:(inout id *)value forKey:(NSString *)key error:(out NSError **)outError\n{\n\tif ([key isEqualToString:@\"scrollbackSaveLimit\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tif (valueInteger < _scrollbackSaveLinesMin) {\n\t\t\t*value = _unsignedIntegerString(_scrollbackSaveLinesMin);\n\t\t} else if (valueInteger > _scrollbackSaveLinesMax) {\n\t\t\t*value = _unsignedIntegerString(_scrollbackSaveLinesMax);\n\t\t}\n\t} else if ([key isEqualToString:@\"scrollbackVisibleLimit\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tif (valueInteger < _scrollbackVisibleLinesMin && valueInteger != 0) {\n\t\t\t*value = _unsignedIntegerString(_scrollbackVisibleLinesMin);\n\t\t} else if (valueInteger > _scrollbackVisibleLinesMax) {\n\t\t\t*value = _unsignedIntegerString(_scrollbackVisibleLinesMax);\n\t\t}\n\t} else if ([key isEqualToString:@\"inlineMediaMaxWidth\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tif (valueInteger < _inlineMediaWidthMin) {\n\t\t\t*value = _unsignedIntegerString(_inlineMediaWidthMin);\n\t\t} else if (_inlineMediaWidthMax < valueInteger) {\n\t\t\t*value = _unsignedIntegerString(_inlineMediaWidthMax);\n\t\t}\n\t} else if ([key isEqualToString:@\"inlineMediaMaxHeight\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tif (valueInteger < _inlineMediaHeightMin) {\n\t\t\t*value = _unsignedIntegerString(_inlineMediaHeightMin);\n\t\t} else if (_inlineMediaHeightMax < valueInteger) {\n\t\t\t*value = _unsignedIntegerString(_inlineMediaHeightMax);\n\t\t}\n\t} else if ([key isEqualToString:@\"fileTransferPortRangeStart\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tNSUInteger valueRangeEnd = [TPCPreferences fileTransferPortRangeEnd];\n\n\t\tif (valueInteger < _fileTransferPortRangeMin) {\n\t\t\t*value = _unsignedIntegerString(_fileTransferPortRangeMin);\n\t\t} else if (_fileTransferPortRangeMax < valueInteger) {\n\t\t\t*value = _unsignedIntegerString(_fileTransferPortRangeMax);\n\t\t}\n\n\t\tvalueInteger = [*value integerValue];\n\n\t\tif (valueInteger > valueRangeEnd) {\n\t\t\t*value = _unsignedIntegerString(valueRangeEnd);\n\t\t}\n\t} else if ([key isEqualToString:@\"fileTransferPortRangeEnd\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tNSUInteger valueRangeStart = [TPCPreferences fileTransferPortRangeStart];\n\n\t\tif (valueInteger < _fileTransferPortRangeMin) {\n\t\t\t*value = _unsignedIntegerString(_fileTransferPortRangeMin);\n\t\t} else if (_fileTransferPortRangeMax < valueInteger) {\n\t\t\t*value = _unsignedIntegerString(_fileTransferPortRangeMax);\n\t\t}\n\n\t\tvalueInteger = [*value integerValue];\n\n\t\tif (valueInteger < valueRangeStart) {\n\t\t\t*value = _unsignedIntegerString(valueRangeStart);\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark File Transfer Destination Folder Popup\n\n- (void)updateFileTransferDownloadDestinationFolder\n{\n\tTDCFileTransferDialog *transferController = [TXSharedApplication sharedFileTransferDialog];\n\n\tNSURL *path = transferController.downloadDestinationURL;\n\n\tNSMenuItem *item = [self.fileTransferDownloadDestinationButton itemAtIndex:0];\n\n\tif (path == nil) {\n\t\titem.image = nil;\n\n\t\titem.title = TXTLS(@\"TDCPreferencesController[721-ie]\");\n\t} else {\n\t\tNSImage *icon = [RZWorkspace() iconForFile:path.path];\n\n\t\titem.image = icon;\n\n\t\ticon.size = NSMakeSize(16, 16);\n\n\t\titem.title = path.lastPathComponent;\n\t}\n}\n\n- (void)onFileTransferDownloadDestinationFolderChanged:(id)sender\n{\n\tTDCFileTransferDialog *transferController = [TXSharedApplication sharedFileTransferDialog];\n\n\tif (self.fileTransferDownloadDestinationButton.selectedTag == 2) {\n\t\tNSOpenPanel *d = [NSOpenPanel openPanel];\n\n\t\td.allowsMultipleSelection = NO;\n\t\td.canChooseDirectories = YES;\n\t\td.canChooseFiles = NO;\n\t\td.canCreateDirectories = YES;\n\t\td.resolvesAliases = YES;\n\n\t\td.prompt = TXTLS(@\"Prompts[xne-79]\");\n\n\t\t[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger returnCode) {\n\t\t\t[self.fileTransferDownloadDestinationButton selectItemAtIndex:0];\n\n\t\t\tif (returnCode != NSModalResponseOK) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSURL *path = d.URLs[0];\n\n\t\t\tNSError *bookmarkError = nil;\n\n\t\t\tNSData *bookmark = [path bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope\n\t\t\t\t\t\t\t  includingResourceValuesForKeys:nil\n\t\t\t\t\t\t\t\t\t\t\t   relativeToURL:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&bookmarkError];\n\n\t\t\tif (bookmark == nil) {\n\t\t\t\tLogToConsoleError(\"Error creating bookmark for URL ('%{public}@'): %{public}@\",\n\t\t\t\t\tpath.standardizedTildePath, bookmarkError.localizedDescription);\n\t\t\t}\n\n\t\t\t[transferController setDownloadDestinationURL:bookmark];\n\n\t\t\t[self updateFileTransferDownloadDestinationFolder];\n\t\t}];\n\t}\n\telse if (self.fileTransferDownloadDestinationButton.selectedTag == 3)\n\t{\n\t\t[self.fileTransferDownloadDestinationButton selectItemAtIndex:0];\n\n\t\t[transferController setDownloadDestinationURL:nil];\n\n\t\t[self updateFileTransferDownloadDestinationFolder];\n\t}\n}\n\n#pragma mark -\n#pragma mark Transcript Folder Popup\n\n- (void)updateTranscriptFolder\n{\n\tNSURL *path = [TPCPathInfo transcriptFolderURL];\n\n\tNSMenuItem *item = [self.transcriptFolderButton itemAtIndex:0];\n\n\tif (path == nil) {\n\t\titem.image = nil;\n\n\t\titem.title = TXTLS(@\"TDCPreferencesController[70s-c6]\");\n\t} else {\n\t\tNSImage *icon = [RZWorkspace() iconForFile:path.path];\n\n\t\titem.image = icon;\n\n\t\ticon.size = NSMakeSize(16, 16);\n\n\t\titem.title = path.lastPathComponent;\n\t}\n}\n\n- (void)onChangedTranscriptFolder:(id)sender\n{\n\tif (self.transcriptFolderButton.selectedTag == 2) {\n\t\tNSOpenPanel *d = [NSOpenPanel openPanel];\n\n\t\td.allowsMultipleSelection = NO;\n\t\td.canChooseDirectories = YES;\n\t\td.canChooseFiles = NO;\n\t\td.canCreateDirectories = YES;\n\t\td.resolvesAliases = YES;\n\n\t\td.prompt = TXTLS(@\"Prompts[xne-79]\");\n\n\t\t[d beginSheetModalForWindow:self.window completionHandler:^(NSInteger returnCode) {\n\t\t\t[self.transcriptFolderButton selectItemAtIndex:0];\n\n\t\t\tif (returnCode != NSModalResponseOK) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSURL *path = d.URLs[0];\n\n\t\t\tNSError *bookmarkError = nil;\n\n\t\t\tNSData *bookmark = [path bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope\n\t\t\t\t\t\t\t  includingResourceValuesForKeys:nil\n\t\t\t\t\t\t\t\t\t\t\t   relativeToURL:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&bookmarkError];\n\n\t\t\tif (bookmark == nil) {\n\t\t\t\tLogToConsoleError(\"Error creating bookmark for URL ('%{public}@'): %{public}@\",\n\t\t\t\t\tpath.standardizedTildePath, bookmarkError.localizedDescription);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self setTranscriptFolderURL:bookmark];\n\t\t}];\n\t}\n\telse if (self.transcriptFolderButton.selectedTag == 3)\n\t{\n\t\t[self.transcriptFolderButton selectItemAtIndex:0];\n\n\t\t[self setTranscriptFolderURL:nil];\n\t}\n}\n\n- (void)setTranscriptFolderURL:(nullable NSData *)transcriptFolderURL\n{\n\t[TPCPathInfo setTranscriptFolderURL:transcriptFolderURL];\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionLogTranscripts];\n\n\t[self updateTranscriptFolder];\n}\n\n#pragma mark -\n#pragma mark Theme\n\n- (void)updateThemeSelection\n{\n\t[self.themeSelectionButton removeAllItems];\n\n\tNSString *currentThemeName = themeController().name;\n\n\tTPCThemeStorageLocation currentStorageLocation = themeController().storageLocation;\n\n\t[themeController() enumerateAvailableThemesWithBlock:^(NSString *themeName, TPCThemeStorageLocation storageLocation, BOOL multipleVariants, BOOL *stop) {\n\t\tNSString *displayName = themeName;\n\n\t\tif (multipleVariants) {\n\t\t\tdisplayName = [NSString stringWithFormat:@\"%@ (%@)\",\n\t\t\t\tthemeName, [TPCThemeController descriptionForStorageLocation:storageLocation]];\n\t\t}\n\n\t\tNSMenuItem *item = [NSMenuItem menuItemWithTitle:displayName target:nil action:nil];\n\n\t\titem.representedObject =\n\t\t@{\n\t\t  @\"themeName\" : themeName,\n\t\t  @\"storageLocation\" : @(storageLocation)\n\t\t};\n\n\t\tif ([currentThemeName isEqualToString:themeName] &&\n\t\t\tcurrentStorageLocation == storageLocation)\n\t\t{\n\t\t\titem.tag = 100; // Tag for item to select\n\t\t}\n\n\t\t[self.themeSelectionButton.menu addItem:item];\n\t}];\n\n\t[self.themeSelectionButton selectItemWithTag:100];\n}\n\n- (void)onChangedThemeSelection:(id)sender\n{\n\tNSMenuItem *selectedItem = self.themeSelectionButton.selectedItem;\n\n\tNSDictionary *context = selectedItem.representedObject;\n\n\tNSString *newThemeName = context[@\"themeName\"];\n\n\tTPCThemeStorageLocation newStorageLocation = [context unsignedIntegerForKey:@\"storageLocation\"];\n\n\tNSString *newTheme = [TPCThemeController buildFilename:newThemeName forStorageLocation:newStorageLocation];\n\n\tNSString *currentTheme = [TPCPreferences themeName];\n\n\tif ([currentTheme isEqualToString:newTheme]) {\n\t\treturn;\n\t}\n\n\t[TPCPreferences setThemeName:newTheme];\n\n\tself.reloadingThemeBySelection = YES;\n\n\t[self onChangedTheme:nil];\n}\n\n- (void)onChangedThemeSelectionReloadComplete:(NSNotification *)notification\n{\n\tNSMutableString *forcedValuesMutable = [NSMutableString string];\n\n\tif ([TPCPreferences themeNicknameFormatPreferenceUserConfigurable] == NO) {\n\t\t[forcedValuesMutable appendString:TXTLS(@\"TDCPreferencesController[77t-de]\")];\n\n\t\t[forcedValuesMutable appendString:@\"\\n\"];\n\t}\n\n\tif ([TPCPreferences themeTimestampFormatPreferenceUserConfigurable] == NO) {\n\t\t[forcedValuesMutable appendString:TXTLS(@\"TDCPreferencesController[ddh-hr]\")];\n\n\t\t[forcedValuesMutable appendString:@\"\\n\"];\n\t}\n\n\tif ([TPCPreferences themeChannelViewFontPreferenceUserConfigurable] == NO) {\n\t\t[forcedValuesMutable appendString:TXTLS(@\"TDCPreferencesController[we8-i8]\")];\n\n\t\t[forcedValuesMutable appendString:@\"\\n\"];\n\t}\n\n\tNSString *forcedValues = forcedValuesMutable.trim;\n\n\tif (forcedValues.length == 0) {\n\t\treturn;\n\t}\n\n\tNSString *currentTheme = [TPCPreferences themeName];\n\n\tNSString *themeName = [TPCThemeController extractThemeName:currentTheme];\n\n\t[TDCAlert alertSheetWithWindow:[NSApp keyWindow]\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCPreferencesController[q4o-2f]\", themeName, forcedValues)\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCPreferencesController[uc0-z7]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t\tsuppressionKey:@\"theme_override_info\"\n\t\t\t\t   suppressionText:nil\n\t\t\t\t   completionBlock:nil];\n}\n\n- (void)onSelectNewFont:(id)sender\n{\n\tNSFont *currentFont = [TPCPreferences themeChannelViewFont];\n\n\t[RZFontManager() setSelectedFont:currentFont isMultiple:NO];\n\n\t[RZFontManager() orderFrontFontPanel:self];\n\n\tRZFontManager().action = @selector(onChangedChannelViewFont:);\n}\n\n- (void)onChangedChannelViewFont:(NSFontManager *)sender\n{\n\tNSFont *currentFont = [TPCPreferences themeChannelViewFont];\n\n\tNSFont *newFont = [sender convertFont:currentFont];\n\n\t[self willChangeValueForKey:@\"themeChannelViewFontName\"];\n\t[self willChangeValueForKey:@\"themeChannelViewFontSize\"];\n\n\t[TPCPreferences setThemeChannelViewFontName:newFont.fontName];\n\t[TPCPreferences setThemeChannelViewFontSize:newFont.pointSize];\n\n\t[self didChangeValueForKey:@\"themeChannelViewFontName\"];\n\t[self didChangeValueForKey:@\"themeChannelViewFontSize\"];\n\n\t[self onChangedTheme:nil];\n}\n\n- (void)onChangedTransparency:(id)sender\n{\n\t[mainWindow() updateAlphaValueToReflectPreferences];\n}\n\n#pragma mark -\n#pragma mark User Style Sheet Rules\n\n- (void)onModifyUserStyleSheetRules:(id)sender\n{\n\tTDCPreferencesUserStyleSheet *sheet = [[TDCPreferencesUserStyleSheet alloc] initWithWindow:self.window];\n\n\tsheet.delegate = (id)self;\n\n\t[sheet start];\n\n\tself.userStyleSheet = sheet;\n}\n\n- (void)userStyleSheetRulesChanged:(TDCPreferencesUserStyleSheet *)sender\n{\n\t[self onChangedTheme:nil];\n}\n\n- (void)userStyleSheetWillClose:(TDCPreferencesUserStyleSheet *)sender\n{\n\tself.userStyleSheet = nil;\n}\n\n#pragma mark -\n#pragma mark Forward Notice To\n\n- (void)updateForwardNoticeToMatrix\n{\n\tTXNoticeSendLocation location = [TPCPreferences locationToSendNotices];\n\n\tself.forwardNoticeToServerConsoleButton.state = (location == TXNoticeSendLocationServerConsole);\n\tself.forwardNoticeToSelectedChannelButton.state = (location == TXNoticeSendLocationSelectedChannel);\n\tself.forwardNoticeToQueryButton.state = (location == TXNoticeSendLocationQuery);\n}\n\n- (void)onChangedForwardNoticeTo:(id)sender\n{\n\t[TPCPreferences setLocationToSendNotices:[sender tag]];\n}\n\n#pragma mark -\n#pragma mark Updates\n\n- (void)updateCheckForUpdatesMatrix\n{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tSPUUpdater *updater = masterController().updateController.updater;\n\n\tself.checkForUpdatesAutomaticallyDownload.state = updater.automaticallyDownloadsUpdates;\n\tself.checkForUpdatesAutomaticallyCheck.state = updater.automaticallyChecksForUpdates;\n\tself.checkForUpdatesDontCheck.state = (updater.automaticallyDownloadsUpdates == NO &&\n\t\t\t\t\t\t\t\t\t\t   updater.automaticallyChecksForUpdates == NO);\n#endif\n}\n\n- (void)onChangedCheckForUpdates:(id)sender\n{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tSPUUpdater *updater = masterController().updateController.updater;\n\n\tupdater.automaticallyChecksForUpdates = (self.checkForUpdatesAutomaticallyCheck.state == NSControlStateValueOn);\n\tupdater.automaticallyDownloadsUpdates = (self.checkForUpdatesAutomaticallyDownload.state == NSControlStateValueOn);\n#endif\n}\n\n- (void)onChangedCheckForBetaUpdates:(id)sender\n{\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionSparkleFrameworkFeedURL];\n\n\tif ([TPCPreferences receiveBetaUpdates]) {\n\t\t[menuController() checkForUpdates:nil];\n\t}\n#endif\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)onChangedDisableNicknameColorHashing:(id)sender\n{\n\t[self onChangedTheme:nil];\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (void)offRecordMessagingPolicyChanged:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionEncryptionPolicy];\n}\n\n- (void)offRecordMessagingOpenOfficialWebsite:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://otr.cypherpunks.ca/\"];\n}\n\n- (void)offRecordMessagingOpenHelpDocument:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Off-the-Record-Messaging.kb\"];\n}\n#endif\n\n- (void)onChangedHighlightType:(id)sender\n{\n\t[self willChangeValueForKey:@\"highlightCurrentNickname\"];\n\t[self didChangeValueForKey:@\"highlightCurrentNickname\"];\n\n\tif ([TPCPreferences highlightMatchingMethod] == TXNicknameHighlightMatchTypeRegularExpression) {\n\t\tself.highlightNicknameButton.enabled = NO;\n\t} else {\n\t\tself.highlightNicknameButton.enabled = YES;\n\t}\n}\n\n- (void)editTableView:(NSTableView *)tableView\n{\n\tNSInteger rowSelection = (tableView.numberOfRows - 1);\n\n\t[tableView scrollRowToVisible:rowSelection];\n\n\t[tableView editColumn:0 row:rowSelection withEvent:nil select:YES];\n}\n\n- (void)onAddHighlightKeyword:(id)sender\n{\n\t[self.highlightKeywordsArrayController add:nil];\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self editTableView:self.highlightKeywordsTable];\n\t});\n}\n\n- (void)onAddExcludeKeyword:(id)sender\n{\n\t[self.excludeKeywordsArrayController add:nil];\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self editTableView:self.excludeKeywordsTable];\n\t});\n}\n\n+ (void)openProxySettingsInSystemPreferences\n{\n\tAEDesc aeDesc = { typeNull, NULL };\n\n\tOSStatus aeDescStatus = AECreateDesc('ptru', \"Proxies\", 7,  &aeDesc);\n\n\tif (aeDescStatus != noErr) {\n\t\tLogToConsoleError(\"aeDescStatus returned value other than noErr: %{public}i\", aeDescStatus);\n\n\t\treturn;\n\t}\n\n\tNSURL *prefPaneURL = [NSURL fileURLWithPath:@\"/System/Library/PreferencePanes/Network.prefPane\"];\n\n\tLSLaunchURLSpec launchSpec = { 0 };\n\n\tlaunchSpec.appURL = NULL;\n\tlaunchSpec.asyncRefCon = NULL;\n\tlaunchSpec.itemURLs = (__bridge CFArrayRef)@[prefPaneURL];\n\tlaunchSpec.launchFlags = (kLSLaunchAsync | kLSLaunchDontAddToRecents);\n\tlaunchSpec.passThruParams = &aeDesc;\n\n\t(void)LSOpenFromURLSpec(&launchSpec, NULL);\n}\n\n- (void)updateInlineMediaEnabled\n{\n\tif ([TPCPreferences showInlineMedia]) {\n\t\tself.inlineMediaEnabledButton.state = NSControlStateValueOn;\n\t} else {\n\t\tself.inlineMediaEnabledButton.state = NSControlStateValueOff;\n\t}\n}\n\n- (void)onChangedInlineMediaOption:(id)sender\n{\n\tif (self.inlineMediaEnabledButton.state == NSControlStateValueOff) {\n\t\t[TPCPreferences setShowInlineMedia:NO];\n\n\t\t[self onChangedTheme:nil];\n\n\t\treturn;\n\t}\n\n\t[TVCLogControllerInlineMediaService askPermissionToEnableInlineMediaWithCompletionBlock:^(BOOL granted) {\n\t\tif (granted) {\n\t\t\t[TPCPreferences setShowInlineMedia:YES];\n\n\t\t\t[self onChangedTheme:nil];\n\t\t} else {\n\t\t\tself.inlineMediaEnabledButton.state = NSControlStateValueOff;\n\t\t}\n\t}];\n}\n\n- (void)onResetUserListModeColorsToDefaults:(id)sender\n{\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +y\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +q\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +a\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +o\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +h\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> +v\"];\n\t[RZUserDefaults() setObject:nil forKey:@\"User List Mode Badge Colors -> no mode\"];\n\n\t[self onChangedUserListModeColor:nil];\n}\n\n- (void)onResetServerListUnreadBadgeColorsToDefault:(id)sender\n{\n\t[self willChangeValueForKey:@\"serverListUnreadCountBadgeHighlightColor\"];\n\n\t[RZUserDefaults() setObject:nil forKey:@\"Server List Unread Message Count Badge Colors -> Highlight\"];\n\n\t[self didChangeValueForKey:@\"serverListUnreadCountBadgeHighlightColor\"];\n\n\t[self onChangedServerListUnreadBadgeColor:sender];\n}\n\n- (void)onChangedInputHistoryScheme:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionInputHistoryScope];\n}\n\n- (void)onChangedAppearance:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];\n}\n\n- (void)onChangedTheme:(id)sender\n{\n\t[TPCPreferences performReloadAction:(TPCPreferencesReloadActionStyle | TPCPreferencesReloadActionTextDirection)];\n}\n\n- (void)onThemeWillReload:(NSNotification *)notification\n{\n\tself.reloadingTheme = YES;\n}\n\n- (void)onThemeReloadComplete:(NSNotification *)notification\n{\n\tself.reloadingTheme = NO;\n\n\tif (self.reloadingThemeBySelection) {\n\t\tself.reloadingThemeBySelection = NO;\n\n\t\t[self onChangedThemeSelectionReloadComplete:notification];\n\t}\n}\n\n- (void)onChangedChannelViewArrangement:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionChannelViewArrangement];\n}\n\n- (void)onChangedMainWindowSegmentedController:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionTextFieldSegmentedControllerOrigin];\n}\n\n- (void)onChangedUserListModeColor:(id)sender\n{\n\tstatic NSDictionary<NSNumber *, NSString *> *preferenceMap = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tpreferenceMap = @{\n\t\t\t@(10) \t: @\"User List Mode Badge Colors -> +y\",\n\t\t\t@(9) \t: @\"User List Mode Badge Colors -> +q\",\n\t\t\t@(8) \t: @\"User List Mode Badge Colors -> +a\",\n\t\t\t@(7) \t: @\"User List Mode Badge Colors -> +o\",\n\t\t\t@(6) \t: @\"User List Mode Badge Colors -> +h\",\n\t\t\t@(5) \t: @\"User List Mode Badge Colors -> +v\",\n\t\t\t@(4) \t: @\"User List Mode Badge Colors -> no mode\"\n\t\t};\n\t});\n\n\tNSString *preferenceKey = preferenceMap[@([sender tag])];\n\n\t/* -onResetUserListModeColorsToDefaults: passes nil sender */\n\tif (preferenceKey == nil) {\n\t\t[TPCPreferences performReloadAction:(TPCPreferencesReloadActionMemberListUserBadges | TPCPreferencesReloadActionMemberList)];\n\t} else {\n\t\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionMemberListUserBadges forKey:preferenceKey];\n\t}\n}\n\n- (void)onChangedMainInputTextViewFontSize:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionTextFieldFontSize];\n}\n\n- (void)onFileTransferIPAddressDetectionMethodChanged:(id)sender\n{\n\tTXFileTransferIPAddressMethodDetection detectionMethod = [TPCPreferences fileTransferIPAddressDetectionMethod];\n\n\tself.fileTransferManuallyEnteredIPAddressTextField.enabled = (detectionMethod == TXFileTransferIPAddressMethodManual);\n}\n\n- (void)onChangedHighlightLogging:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionHighlightLogging];\n}\n\n- (void)onChangedUserListModeSortOrder:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionMemberListSortOrder];\n}\n\n- (void)onChangedServerListUnreadBadgeColor:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionServerListUnreadBadges];\n}\n\n- (void)onChangedScrollbackSaveLimit:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionScrollbackSaveLimit];\n}\n\n- (void)onChangedScrollbackVisibleLimit:(id)sender\n{\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionScrollbackVisibleLimit];\n}\n\n- (void)onOpenPathToScripts:(id)sender\n{\n\t[RZWorkspace() openURL:[TPCPathInfo groupContainerApplicationSupportURL]];\n}\n\n- (void)openPathToThemesCallback:(TDCAlertResponse)returnCode withOriginalAlert:(NSAlert *)originalAlert\n{\n\tNSParameterAssert(originalAlert != nil);\n\n\tif (returnCode == TDCAlertResponseDefault) {\n\t\t[self openPathToTheme];\n\t}\n\n\tif (returnCode == TDCAlertResponseAlternate) {\n\t\t[self onModifyUserStyleSheetRules:nil];\n\t}\n\n\tif (returnCode == TDCAlertResponseOther) {\n\t\t[originalAlert.window orderOut:nil];\n\n\t\t[themeController() copyActiveThemeToDestinationLocation:TPCThemeStorageLocationCustom reloadOnCopy:YES openOnCopy:YES];\n\t}\n}\n\n- (void)onOpenPathToTheme:(id)sender\n{\n\tif (themeController().bundledTheme) {\n\t\t[TDCAlert alertSheetWithWindow:NSApp.keyWindow\n\t\t\t\t\t\t\t\t  body:TXTLS(@\"TDCPreferencesController[ojj-ap]\")\n\t\t\t\t\t\t\t\t title:TXTLS(@\"TDCPreferencesController[5jv-aw]\")\n\t\t\t\t\t\t defaultButton:TXTLS(@\"TDCPreferencesController[6ws-av]\")\n\t\t\t\t\t   alternateButton:TXTLS(@\"TDCPreferencesController[aib-iy]\")\n\t\t\t\t\t\t   otherButton:TXTLS(@\"TDCPreferencesController[dj8-1t]\")\n\t\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t\t   [self openPathToThemesCallback:buttonClicked withOriginalAlert:underlyingAlert];\n\t\t\t\t\t   }];\n\n\t\treturn;\n\t}\n\n\t[self openPathToTheme];\n}\n\n- (void)openPathToTheme\n{\n\tNSURL *fileURL = themeController().originalURL;\n\n\t[RZWorkspace() openURL:fileURL];\n}\n\n- (void)onThemeListDidChange:(NSNotification *)aNote\n{\n\t[self updateThemeSelection];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\t[self saveWindowFrame];\n\n\tif ([self.delegate respondsToSelector:@selector(preferencesDialogWillClose:)]) {\n\t\t[self.delegate preferencesDialogWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Preferences/TDCPreferencesNotificationConfiguration.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TDCPreferencesNotificationConfigurationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TDCPreferencesNotificationConfiguration\n\n+ (TDCPreferencesNotificationConfiguration *)objectWithEventType:(TXNotificationType)eventType\n{\n\treturn [[self alloc] initWithEventType:eventType];\n}\n\n- (nullable NSString *)alertSound\n{\n\tNSString *sound = [TPCPreferences soundForEvent:self.eventType];\n\n\tif (sound == nil) {\n\t\treturn TXNoAlertSoundPreferenceValue;\n\t}\n\n\treturn sound;\n}\n\n- (void)setAlertSound:(nullable NSString *)alertSound\n{\n\t[TPCPreferences setSound:alertSound forEvent:self.eventType];\n}\n\n- (NSUInteger)pushNotification\n{\n\treturn [TPCPreferences notificationEnabledForEvent:self.eventType];\n}\n\n- (void)setPushNotification:(NSUInteger)pushNotification\n{\n\t[TPCPreferences setNotificationEnabled:pushNotification forEvent:self.eventType];\n}\n\n- (NSUInteger)speakEvent\n{\n\treturn [TPCPreferences speakEvent:self.eventType];\n}\n\n- (void)setSpeakEvent:(NSUInteger)speakEvent\n{\n\t[TPCPreferences setEventIsSpoken:speakEvent forEvent:self.eventType];\n}\n\n- (NSUInteger)disabledWhileAway\n{\n\treturn [TPCPreferences disabledWhileAwayForEvent:self.eventType];\n}\n\n- (void)setDisabledWhileAway:(NSUInteger)disabledWhileAway\n{\n\t[TPCPreferences setDisabledWhileAway:disabledWhileAway forEvent:self.eventType];\n}\n\n- (NSUInteger)bounceDockIcon\n{\n\treturn [TPCPreferences bounceDockIconForEvent:self.eventType];\n}\n\n- (void)setBounceDockIcon:(NSUInteger)bounceDockIcon\n{\n\t[TPCPreferences setBounceDockIcon:bounceDockIcon forEvent:self.eventType];\n}\n\n- (NSUInteger)bounceDockIconRepeatedly\n{\n\treturn [TPCPreferences bounceDockIconRepeatedlyForEvent:self.eventType];\n}\n\n- (void)setBounceDockIconRepeatedly:(NSUInteger)bounceDockIconRepeatedly\n{\n\t[TPCPreferences setBounceDockIconRepeatedly:bounceDockIconRepeatedly forEvent:self.eventType];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Preferences/TDCPreferencesUserStyleSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TDCPreferencesUserStyleSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCPreferencesUserStyleSheet ()\n@property (nonatomic, unsafe_unretained) IBOutlet NSTextView *rulesTextView;\n@property (nonatomic, assign) BOOL rulesChanged;\n@property (nonatomic, copy, readonly) NSString *defaultRules;\n@end\n\n@implementation TDCPreferencesUserStyleSheet\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCPreferencesUserStyleSheet\" owner:self topLevelObjects:nil];\n\n\tself.rulesTextView.font = [NSFont systemFontOfSize:13.0];\n\n\tself.rulesTextView.textContainerInset = NSMakeSize(1, 3);\n\n\t[self loadRules];\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)textDidChange:(NSNotification *)aNotification\n{\n\tif (aNotification.object == self.rulesTextView) {\n\t\tself.rulesChanged = YES;\n\t}\n}\n\n- (void)loadRules\n{\n\tNSString *rules = [TPCPreferences themeUserStyleSheetRules];\n\n\t/* We can define the default rules in the defaults property list\n\t but we don't do that for this preference so that it doesn't append\n\t to the HTML unless the user entered a value. It is easier to do\n\t that here versus making a comparison to the default in higher up. */\n\tif (rules == nil) {\n\t\trules = self.defaultRules;\n\t}\n\n\tself.rulesTextView.string = rules;\n\n\tself.rulesChanged = NO;\n}\n\n- (void)saveRules\n{\n\tNSString *rules = self.rulesTextView.string.trim;\n\n\tif (rules.length == 0 || [rules isEqualToString:self.defaultRules]) {\n\t\trules = nil;\n\t}\n\n\t[TPCPreferences setThemeUserStyleSheetRules:rules];\n\n\tif ([self.delegate respondsToSelector:@selector(userStyleSheetRulesChanged:)]) {\n\t\t[self.delegate userStyleSheetRulesChanged:self];\n\t}\n}\n\n- (void)ok:(id)sender\n{\n\tif (self.rulesChanged) {\n\t\t[self saveRules];\n\t}\n\n\t[super ok:nil];\n}\n\n- (NSString *)defaultRules\n{\n\treturn TXTLS(@\"TDCPreferencesUserStyleSheet[q4s-3m]\");\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(userStyleSheetWillClose:)]) {\n\t\t[self.delegate userStyleSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Server Endpoint/TDCServerEndpointListSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCServer.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TDCServerEndpointListSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _endpointEntryTableDragToken\t\t@\"TDCServerEndpointListSheetEntryTableDragToken\"\n\n@interface TDCServerEndpointListSheet ()\n@property (nonatomic, strong) IBOutlet NSArrayController *entryTableController;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *entryTable;\n@property (nonatomic, weak) IBOutlet NSSegmentedControl *entryActionsSegmentedControl;\n\n- (IBAction)entryActionsSegmentedControlClicked:(id)sender;\n@end\n\n@implementation TDCServerEndpointListSheet\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCServerEndpointListSheet\" owner:self topLevelObjects:nil];\n\n\t[self.entryTable registerForDraggedTypes:@[_endpointEntryTableDragToken]];\n\n\t[self.entryTableController addObserver:self\n\t\t\t\t\t\t\t\tforKeyPath:@\"canRemove\"\n\t\t\t\t\t\t\t\t   options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew)\n\t\t\t\t\t\t\t\t   context:NULL];\n}\n\n- (void)startWithServerList:(NSArray<IRCServer *> *)serverList\n{\n\tNSParameterAssert(serverList != nil);\n\n\tfor (IRCServer *server in serverList) {\n\t\t[self.entryTableController addObject:[server mutableCopy]];\n\t}\n\n\t[self startSheet];\n}\n\n- (void)ok:(id)sender\n{\n\tNSArray *serverListIn = self.entryTableController.arrangedObjects;\n\n\tNSMutableArray<IRCServer *> *serverListOut =\n\t[[NSMutableArray alloc] initWithCapacity:serverListIn.count];\n\n\tfor (IRCServerMutable *server in serverListIn) {\n\t\t/* New entries that are blank do not perform validation\n\t\t because nothing technically has changed. Instead of \n\t\t doing some complex workaround, let's just ditch \n\t\t objects with an empty server address. */\n\t\tif (server.serverAddress.length == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[serverListOut addObject:[server copy]];\n\t}\n\n\tif ([self.delegate respondsToSelector:@selector(serverEndpointListSheet:onOk:)]) {\n\t\t[self.delegate serverEndpointListSheet:self onOk:[serverListOut copy]];\n\t}\n\n\t[super ok:sender];\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"canRemove\"]) {\n\t\t[self updateEntryActionsSegmentedControlEnabledState];\n\t}\n}\n\n#pragma mark -\n#pragma mark Entry Management\n\n- (void)updateEntryActionsSegmentedControlEnabledState\n{\n\t[self.entryActionsSegmentedControl setEnabled:self.entryTableController.canRemove forSegment:1];\n}\n\n- (void)entryActionsSegmentedControlClicked:(id)sender\n{\n\tNSInteger selectedSegment = [sender selectedSegment];\n\n\tif (selectedSegment == 0) {\n\t\t[self addEntry];\n\t} else if (selectedSegment == 1) {\n\t\t[self removeSelectedEntry];\n\t}\n}\n\n- (void)addEntry\n{\n\tIRCServerMutable *newEntry = [IRCServerMutable new];\n\n\t[self.entryTableController addObject:newEntry];\n\n\t/* Edit column next pass on the main thread to allow the\n\t -addObject to register properly. */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\tNSTableView *tableView = self.entryTable;\n\n\t\tNSInteger rowSelection = (tableView.numberOfRows - 1);\n\n\t\t[tableView scrollRowToVisible:rowSelection];\n\n\t\t[tableView editColumn:0 row:rowSelection withEvent:nil select:YES];\n\t});\n}\n\n- (void)removeSelectedEntry\n{\n\tNSIndexSet *selectedRows = self.entryTable.selectedRowIndexes;\n\n\t[self.entryTableController removeObjectsAtArrangedObjectIndexes:selectedRows];\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard\n{\n\tNSData *draggedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];\n\n\t[pasteboard declareTypes:@[_endpointEntryTableDragToken] owner:self];\n\n\t[pasteboard setData:draggedData forType:_endpointEntryTableDragToken];\n\n\treturn YES;\n}\n\n- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation\n{\n\treturn NSDragOperationGeneric;\n}\n\n- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation\n{\n\tNSPasteboard *pasteboard = [info draggingPasteboard];\n\n\tNSData *draggedData = [pasteboard dataForType:_endpointEntryTableDragToken];\n\n\tNSIndexSet *draggedRowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:draggedData];\n\n\tNSUInteger draggedRowIndex = draggedRowIndexes.firstIndex;\n\n\t[self.entryTableController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.entryTableController removeObserver:self forKeyPath:@\"canRemove\"];\n\n\tif ([self.delegate respondsToSelector:@selector(serverEndpointListSheetWillClose:)]) {\n\t\t[self.delegate serverEndpointListSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/Server Endpoint/TDCServerEndpointListSheetTable.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCServer.h\"\n#import \"NSStringHelper.h\"\n#import \"TLOLocalization.h\"\n#import \"TDCServerEndpointListSheetTablePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCServerEndpointListSheetTableCellView ()\n@property (nonatomic, copy) NSString *serverAddress;\n@property (nonatomic, copy) NSString *serverPort;\n@property (nonatomic, copy) NSNumber *prefersSecuredConnection;\n@property (nonatomic, copy) NSString *serverPassword;\n@property (nonatomic, assign) BOOL observersRegistered;\n@end\n\n@implementation TDCServerEndpointListSheetTableCellView\n\n- (BOOL)validateValue:(inout id *)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError\n{\n\tif ([inKeyPath isEqualToString:@\"serverAddress\"]) {\n\t\tif (((NSString *)*ioValue).isValidInternetAddress == NO) {\n\t\t\tif (outError) {\n\t\t\t\t*outError = [NSError errorWithDomain:TXErrorDomain\n\t\t\t\t\t\t\t\t\t\t\t\t code:71013\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{\n\t\t\t\t\tNSLocalizedDescriptionKey : TXTLS(@\"TDCServerEndpointListSheet[iis-gr]\"),\n\t\t\t\t\tNSLocalizedRecoverySuggestionErrorKey : TXTLS(@\"TDCServerEndpointListSheet[k0c-3u]\")}\n\t\t\t\t\t\t\t ];\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t} else if ([inKeyPath isEqualToString:@\"serverPort\"]) {\n\t\tif (((NSString *)*ioValue).isValidInternetPort == NO) {\n\t\t\tif (outError) {\n\t\t\t\t*outError = [NSError errorWithDomain:TXErrorDomain\n\t\t\t\t\t\t\t\t\t\t\t\tcode:71014\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{\n\t\t\t\t\t\tNSLocalizedDescriptionKey : TXTLS(@\"TDCServerEndpointListSheet[qeb-ip]\"),\n\t\t\t\t\t\tNSLocalizedRecoverySuggestionErrorKey : TXTLS(@\"TDCServerEndpointListSheet[ox2-od]\")}\n\t\t\t\t\t\t\t ];\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (NSString *)serverAddress\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn @\"\";\n\t}\n\n\treturn objectValue.serverAddress;\n}\n\n- (void)setServerAddress:(NSString *)serverAddress\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn;\n\t}\n\n\tobjectValue.serverAddress = serverAddress;\n}\n\n- (NSString *)serverPort\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn @\"\";\n\t}\n\n\treturn [NSString stringWithUnsignedShort:objectValue.serverPort];\n}\n\n- (void)setServerPort:(NSString *)serverPort\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn;\n\t}\n\n\tobjectValue.serverPort = (uint16_t)serverPort.integerValue;\n}\n\n- (NSNumber *)prefersSecuredConnection\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn @(NSControlStateValueOff);\n\t}\n\n\tif (objectValue.prefersSecuredConnection) {\n\t\treturn @(NSControlStateValueOn);\n\t} else {\n\t\treturn @(NSControlStateValueOff);\n\t}\n}\n\n- (void)setPrefersSecuredConnection:(NSNumber *)prefersSecuredConnection\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn;\n\t}\n\n\tBOOL l_prefersSecuredConnection =\n\t(prefersSecuredConnection.unsignedIntegerValue == NSControlStateValueOn);\n\n\tif (l_prefersSecuredConnection) {\n\t\tobjectValue.prefersSecuredConnection = YES;\n\n\t\tif (objectValue.serverPort == 6667) {\n\t\t\tobjectValue.serverPort = 6697;\n\t\t}\n\t} else {\n\t\tobjectValue.prefersSecuredConnection = NO;\n\n\t\tif (objectValue.serverPort == 6697) {\n\t\t\tobjectValue.serverPort = 6667;\n\t\t}\n\t}\n}\n\n- (NSString *)serverPassword\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn @\"\";\n\t}\n\n\tNSString *serverPassword = objectValue.serverPassword;\n\n\tif (serverPassword == nil) {\n\t\treturn @\"\";\n\t}\n\n\treturn serverPassword;\n}\n\n- (void)setServerPassword:(NSString *)serverPassword\n{\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn;\n\t}\n\n\tobjectValue.serverPassword = serverPassword;\n}\n\n- (void)setObjectValue:(nullable id)objectValue\n{\n\t[self stopObservingObjectValue];\n\n\tsuper.objectValue = objectValue;\n\n\t[self startObservingObjectValue];\n}\n\n- (void)startObservingObjectValue\n{\n\tNSString *keyPath = self.identifier;\n\n\t[self willChangeValueForKey:keyPath];\n\t[self didChangeValueForKey:keyPath];\n\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\tif (objectValue == nil) {\n\t\treturn;\n\t}\n\n\t[objectValue addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];\n\n\tself.observersRegistered = YES;\n}\n\n- (void)stopObservingObjectValue\n{\n\tif (self.observersRegistered == NO) {\n\t\treturn;\n\t}\n\n\tNSString *keyPath = self.identifier;\n\n\tIRCServerMutable *objectValue = self.objectValue;\n\n\t[objectValue removeObserver:self forKeyPath:keyPath];\n\n\tself.observersRegistered = NO;\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"serverPort\"]) {\n\t\t[self willChangeValueForKey:@\"serverPort\"];\n\t\t[self didChangeValueForKey:@\"serverPort\"];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCAboutDialog.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TDCAboutDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCAboutDialog ()\n@property (nonatomic, weak) IBOutlet NSTextField *versionInfoTextField;\n\n- (IBAction)displayAcknowledgements:(id)sender;\n@end\n\n@implementation TDCAboutDialog\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCAboutDialog\" owner:self topLevelObjects:nil];\n\n\tNSString *bundleVersion = [TPCApplicationInfo applicationVersionShort];\n\n\tself.versionInfoTextField.stringValue = TXTLS(@\"TDCAboutDialog[zjd-al]\", bundleVersion);\n}\n\n- (void)show\n{\n\t[self.window restoreWindowStateForClass:self.class];\n\n\t[super show];\n}\n\n- (void)displayAcknowledgements:(id)sender\n{\n\t[menuController() openAcknowledgements:sender];\n}\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.window saveWindowStateForClass:self.class];\n\n\tif ([self.delegate respondsToSelector:@selector(aboutDialogWillClose:)]) {\n\t\t[self.delegate aboutDialogWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCAddressBookSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCAddressBookSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCAddressBookSheet ()\n@property (nonatomic, strong) IRCAddressBookEntryMutable *config;\n@property (nonatomic, assign) IRCAddressBookEntryType entryType;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreClientToClientProtocolCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreFileTransferRequestsCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreGeneralEventMessagesCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreInlineMediaCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreNoticeMessagesCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignorePrivateMessageHighlightsCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignorePrivateMessagesCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignorePublicMessageHighlightsCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignorePublicMessagesCheck;\n@property (nonatomic, strong) IBOutlet NSButton *trackUserActivityCheck;\n@property (nonatomic, strong) IBOutlet NSButton *ignoreEntrySaveButton;\n@property (nonatomic, strong) IBOutlet NSButton *userTrackingEntrySaveButton;\n@property (nonatomic, strong) IBOutlet TVCValidatedTextField *ignoreEntryHostmaskTextField;\n@property (nonatomic, strong) IBOutlet TVCValidatedTextField *userTrackingEntryNicknameTextField;\n@property (nonatomic, strong) IBOutlet NSWindow *ignoreEntryView;\n@property (nonatomic, strong) IBOutlet NSWindow *userTrackingEntryView;\n@end\n\n@implementation TDCAddressBookSheet\n\n- (instancetype)initWithEntryType:(IRCAddressBookEntryType)entryType\n{\n\tNSParameterAssert(entryType == IRCAddressBookEntryTypeIgnore ||\n\t\t\t\t\t  entryType == IRCAddressBookEntryTypeUserTracking);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tif (entryType == IRCAddressBookEntryTypeIgnore) {\n\t\t\tself.config = [IRCAddressBookEntryMutable newIgnoreEntry];\n\t\t} else if (entryType == IRCAddressBookEntryTypeUserTracking) {\n\t\t\tself.config = [IRCAddressBookEntryMutable newUserTrackingEntry];\n\t\t}\n\n\t\tself.entryType = entryType;\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfig:(IRCAddressBookEntry *)config\n{\n\tNSParameterAssert(config != nil);\n\tNSParameterAssert(config.entryType == IRCAddressBookEntryTypeIgnore ||\n\t\t\t\t\t  config.entryType == IRCAddressBookEntryTypeUserTracking);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.config = [config mutableCopy];\n\n\t\tself.entryType = config.entryType;\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCAddressBookSheet\" owner:self topLevelObjects:nil];\n\n\tself.ignoreEntryHostmaskTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.ignoreEntryHostmaskTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.ignoreEntryHostmaskTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tNSString *valueWithoutWildcard = [currentValue stringByReplacingOccurrencesOfString:@\"*\" withString:@\"-\"];\n\n\t\tif (valueWithoutWildcard.isHostmask == NO) {\n\t\t\treturn TXTLS(@\"TDCAddressBookSheet[csu-bv]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\tself.userTrackingEntryNicknameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.userTrackingEntryNicknameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.userTrackingEntryNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isHostmaskNickname == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[och-j5]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n}\n\n- (void)loadConfig\n{\n\tif (self.entryType == IRCAddressBookEntryTypeIgnore)\n\t{\n\t\tself.ignoreEntryHostmaskTextField.stringValue = self.config.hostmask;\n\n\t\tself.ignoreClientToClientProtocolCheck.state = self.config.ignoreClientToClientProtocol;\n\t\tself.ignoreFileTransferRequestsCheck.state = self.config.ignoreFileTransferRequests;\n\t\tself.ignoreGeneralEventMessagesCheck.state = self.config.ignoreGeneralEventMessages;\n\t\tself.ignoreInlineMediaCheck.state = self.config.ignoreInlineMedia;\n\t\tself.ignoreNoticeMessagesCheck.state = self.config.ignoreNoticeMessages;\n\t\tself.ignorePrivateMessageHighlightsCheck.state = self.config.ignorePrivateMessageHighlights;\n\t\tself.ignorePrivateMessagesCheck.state = self.config.ignorePrivateMessages;\n\t\tself.ignorePublicMessageHighlightsCheck.state = self.config.ignorePublicMessageHighlights;\n\t\tself.ignorePublicMessagesCheck.state = self.config.ignorePublicMessages;\n\t}\n\telse if (self.entryType == IRCAddressBookEntryTypeUserTracking)\n\t{\n\t\tself.userTrackingEntryNicknameTextField.stringValue = self.config.hostmask;\n\n\t\tself.trackUserActivityCheck.state = self.config.trackUserActivity;\n\t}\n}\n\n- (void)start\n{\n\tif (self.entryType == IRCAddressBookEntryTypeIgnore)\n\t{\n\t\tself.sheet = self.ignoreEntryView;\n\n\t\t[self.sheet makeFirstResponder:self.ignoreEntryHostmaskTextField];\n\t}\n\telse if (self.entryType == IRCAddressBookEntryTypeUserTracking)\n\t{\n\t\tself.sheet = self.userTrackingEntryView;\n\n\t\t[self.sheet makeFirstResponder:self.userTrackingEntryNicknameTextField];\n\t}\n\n\t[self startSheet];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tif (self.entryType == IRCAddressBookEntryTypeIgnore)\n\t{\n\t\tself.config.hostmask = self.ignoreEntryHostmaskTextField.value;\n\n\t\tself.config.ignoreClientToClientProtocol = (self.ignoreClientToClientProtocolCheck.state == NSControlStateValueOn);\n\t\tself.config.ignoreFileTransferRequests = (self.ignoreFileTransferRequestsCheck.state == NSControlStateValueOn);\n\t\tself.config.ignoreGeneralEventMessages = (self.ignoreGeneralEventMessagesCheck.state == NSControlStateValueOn);\n\t\tself.config.ignoreInlineMedia = (self.ignoreInlineMediaCheck.state == NSControlStateValueOn);\n\t\tself.config.ignoreNoticeMessages = (self.ignoreNoticeMessagesCheck.state == NSControlStateValueOn);\n\t\tself.config.ignorePrivateMessageHighlights = (self.ignorePrivateMessageHighlightsCheck.state == NSControlStateValueOn);\n\t\tself.config.ignorePrivateMessages = (self.ignorePrivateMessagesCheck.state == NSControlStateValueOn);\n\t\tself.config.ignorePublicMessageHighlights = (self.ignorePublicMessageHighlightsCheck.state == NSControlStateValueOn);\n\t\tself.config.ignorePublicMessages = (self.ignorePublicMessagesCheck.state == NSControlStateValueOn);\n\t}\n\telse if (self.entryType == IRCAddressBookEntryTypeUserTracking)\n\t{\n\t\tself.config.hostmask = self.userTrackingEntryNicknameTextField.value;\n\n\t\tself.config.trackUserActivity = (self.trackUserActivityCheck.state == NSControlStateValueOn);\n\t}\n\n\tif ([self.delegate respondsToSelector:@selector(addressBookSheet:onOk:)]) {\n\t\t[self.delegate addressBookSheet:self onOk:[self.config copy]];\n\t}\n\n\t[super ok:nil];\n}\n\n- (BOOL)okOrError\n{\n\tif (self.entryType == IRCAddressBookEntryTypeIgnore)\n\t{\n\t\treturn [self okOrErrorForTextField:self.ignoreEntryHostmaskTextField];\n\t}\n\telse if (self.entryType == IRCAddressBookEntryTypeUserTracking)\n\t{\n\t\treturn [self okOrErrorForTextField:self.userTrackingEntryNicknameTextField];\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(addressBookSheetWillClose:)]) {\n\t\t[self.delegate addressBookSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCAlert.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TDCAlert.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TDCAlertSuppressionPrefix = @\"Text Input Prompt Suppression -> \";\n\n@interface TDCAlertContext : NSObject\n@property (nonatomic, copy, nullable) NSString *suppressionKey;\n@property (nonatomic, copy, nullable) TDCAlertCompletionBlock completionBlock;\n@end\n\n@implementation TDCAlert\n\n#pragma mark -\n#pragma mark Modal Alerts (Panel)\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n{\n\treturn\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t suppressionKey:nil\n\t\t\t\tsuppressionText:nil\n\t\t\t\t  accessoryView:nil\n\t\t\tsuppressionResponse:NULL];\n}\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n{\n\treturn\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t suppressionKey:suppressKey\n\t\t\t\tsuppressionText:suppressText\n\t\t\t\t  accessoryView:nil\n\t\t\tsuppressionResponse:NULL];\n}\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t title:(NSString *)titleText\n\t\t\t\t defaultButton:(NSString *)buttonDefault\n\t\t\t   alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\tsuppressionKey:(nullable NSString *)suppressKey\n\t\t\t   suppressionText:(nullable NSString *)suppressText\n\t\t\t\t accessoryView:(nullable NSView *)accessoryView\n{\n\treturn\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t suppressionKey:suppressKey\n\t\t\t\tsuppressionText:suppressText\n\t\t\t\t  accessoryView:accessoryView\n\t\t\tsuppressionResponse:NULL];\n}\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse\n{\n\treturn\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t suppressionKey:suppressKey\n\t\t\t\tsuppressionText:suppressText\n\t\t\t\t  accessoryView:nil\n\t\t\tsuppressionResponse:suppressionResponse];\n}\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t\t\taccessoryView:(nullable NSView *)accessoryView\n\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse\n{\n\tTDCAlertResponse response =\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t\totherButton:nil\n\t\t\t\t suppressionKey:suppressKey\n\t\t\t\tsuppressionText:suppressText\n\t\t\t\t  accessoryView:nil\n\t\t\tsuppressionResponse:nil];\n\n\treturn (response == TDCAlertResponseDefault);\n}\n\n+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\t  otherButton:(nullable NSString *)buttonOther\n{\n\treturn\n\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t  title:titleText\n\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t\totherButton:buttonOther\n\t\t\t\t suppressionKey:nil\n\t\t\t\tsuppressionText:nil\n\t\t\t\t  accessoryView:nil\n\t\t\tsuppressionResponse:nil];\n}\n\n+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\t  otherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t\taccessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse\n{\n\tNSParameterAssert(bodyText != nil);\n\tNSParameterAssert(titleText != nil);\n\tNSParameterAssert(buttonDefault != nil);\n\n\t/* Require main thread */\n\tif ([NSThread isMainThread] == NO) {\n\t\t__block TDCAlertResponse result = TDCAlertResponseAlternate;\n\n\t\tXRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{\n\t\t\tresult =\n\t\t\t[self modalAlertWithMessage:bodyText\n\t\t\t\t\t\t\t\t  title:titleText\n\t\t\t\t\t\t  defaultButton:buttonDefault\n\t\t\t\t\t\talternateButton:buttonAlternate\n\t\t\t\t\t\t\totherButton:buttonOther\n\t\t\t\t\t\t suppressionKey:suppressKey\n\t\t\t\t\t\tsuppressionText:suppressText\n\t\t\t\t\t\t  accessoryView:accessoryView\n\t\t\t\t\tsuppressionResponse:suppressionResponse];\n\t\t});\n\n\t\treturn result;\n\t}\n\n\t/* Prepare suppression */\n\tif (suppressKey) {\n\t\tsuppressKey = [self suppressionKeyWithBase:suppressKey];\n\n\t\t/* Exit if suppressed */\n\t\tif ([RZUserDefaults() boolForKey:suppressKey]) {\n\t\t\treturn TDCAlertResponseDefault;\n\t\t}\n\t}\n\n\tif (suppressKey && (suppressText == nil || suppressText.length == 0)) {\n\t\tsuppressText = TXTLS(@\"Prompts[68u-z9]\");\n\t}\n\n\t/* Construct alert */\n\tNSAlert *alert = [NSAlert new];\n\n\talert.messageText = titleText;\n\talert.informativeText = bodyText;\n\n\t[alert addButtonWithTitle:buttonDefault];\n\n\tif (buttonAlternate) {\n\t\t[alert addButtonWithTitle:buttonAlternate];\n\t}\n\n\tif (buttonOther) {\n\t\t[alert addButtonWithTitle:buttonOther];\n\t}\n\n\tif (suppressKey || suppressText) {\n\t\talert.showsSuppressionButton = YES;\n\n\t\talert.suppressionButton.title = suppressText;\n\t}\n\n\tif (accessoryView) {\n\t\talert.accessoryView = accessoryView;\n\t}\n\n\t/* Pop alert */\n\tNSModalResponse returnCode = [alert runModal];\n\n\tTDCAlertResponse response = [self _convertResponseFromNSAlert:returnCode];\n\n\t[self _finalizeAlert:alert\n\t\t\twithResponse:response\n\t\t completionBlock:nil\n\t\t  suppressionKey:suppressKey\n\t suppressionResponse:suppressionResponse];\n\n\treturn response;\n}\n\n#pragma mark -\n#pragma mark Non-blocking Alerts (Panel)\n\n+ (TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t title:(NSString *)titleText\n\t\t\t\t defaultButton:(NSString *)buttonDefault\n\t\t\t   alternateButton:(nullable NSString *)buttonAlternate\n{\n\t/* Will never return nil because no suppression. */\n\treturn (TVCAlert * _Nonnull)\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:nil\n\t\t\tsuppressionKey:nil\n\t\t   suppressionText:nil\n\t\t\t accessoryView:nil\n\t\t   completionBlock:nil];\n}\n\n+ (TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t title:(NSString *)titleText\n\t\t\t\t defaultButton:(NSString *)buttonDefault\n\t\t\t   alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t   otherButton:(nullable NSString *)buttonOther\n{\n\treturn (TVCAlert * _Nonnull)\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:buttonOther\n\t\t\tsuppressionKey:nil\n\t\t   suppressionText:nil\n\t\t\t accessoryView:nil\n\t\t   completionBlock:nil];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:nil\n\t\t\tsuppressionKey:suppressKey\n\t\t   suppressionText:suppressText\n\t\t\t accessoryView:nil\n\t\t   completionBlock:nil];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:nil\n\t\t\tsuppressionKey:nil\n\t\t   suppressionText:nil\n\t\t\t accessoryView:nil\n\t\t   completionBlock:completionBlock];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:buttonOther\n\t\t\tsuppressionKey:nil\n\t\t   suppressionText:nil\n\t\t\t accessoryView:nil\n\t\t   completionBlock:completionBlock];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:nil\n\t\t\tsuppressionKey:suppressKey\n\t\t   suppressionText:suppressText\n\t\t\t accessoryView:nil\n\t\t   completionBlock:completionBlock];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:buttonOther\n\t\t\tsuppressionKey:suppressKey\n\t\t   suppressionText:suppressText\n\t\t\t accessoryView:nil\n\t\t   completionBlock:completionBlock];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t  accessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\treturn\n\t[self alertWithMessage:bodyText\n\t\t\t\t\t title:titleText\n\t\t\t defaultButton:buttonDefault\n\t\t   alternateButton:buttonAlternate\n\t\t\t   otherButton:nil\n\t\t\tsuppressionKey:suppressKey\n\t\t   suppressionText:suppressText\n\t\t\t accessoryView:accessoryView\n\t\t   completionBlock:completionBlock];\n}\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t  accessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\tNSParameterAssert(bodyText != nil);\n\tNSParameterAssert(titleText != nil);\n\tNSParameterAssert(buttonDefault != nil);\n\n\t/* Require main thread */\n\tif ([NSThread isMainThread] == NO) {\n\t\t__block TVCAlert *alert = nil;\n\n\t\tXRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{\n\t\t\talert =\n\t\t\t[self alertWithMessage:bodyText\n\t\t\t\t\t\t\t title:titleText\n\t\t\t\t\t defaultButton:buttonDefault\n\t\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t\tsuppressionKey:suppressKey\n\t\t\t\t   suppressionText:suppressText\n\t\t\t\t\t accessoryView:accessoryView\n\t\t\t\t   completionBlock:completionBlock];\n\t\t});\n\n\t\treturn alert;\n\t}\n\n\t/* Prepare suppression */\n\tif (suppressKey) {\n\t\tsuppressKey = [self suppressionKeyWithBase:suppressKey];\n\n\t\t/* Exit if suppressed */\n\t\tif ([RZUserDefaults() boolForKey:suppressKey]) {\n\t\t\tif (completionBlock) {\n\t\t\t\tcompletionBlock(TDCAlertResponseDefault, YES, nil);\n\t\t\t}\n\n\t\t\treturn nil;\n\t\t}\n\t}\n\n\tif (suppressKey && (suppressText == nil || suppressText.length == 0)) {\n\t\tsuppressText = TXTLS(@\"Prompts[68u-z9]\");\n\t}\n\n\t/* Construct alert */\n\tTVCAlert *alert = [TVCAlert new];\n\n\talert.messageText = titleText;\n\talert.informativeText = bodyText;\n\n\t[alert setTitle:buttonDefault forButton:TVCAlertResponseButtonFirst];\n\n\tif (buttonAlternate) {\n\t\t[alert setTitle:buttonAlternate forButton:TVCAlertResponseButtonSecond];\n\t}\n\n\tif (buttonOther) {\n\t\t[alert setTitle:buttonOther forButton:TVCAlertResponseButtonThird];\n\t}\n\n\tif (suppressKey || suppressText) {\n\t\talert.showsSuppressionButton = YES;\n\n\t\talert.suppressionButton.title = suppressText;\n\t}\n\n\tif (accessoryView) {\n\t\talert.accessoryView = accessoryView;\n\t}\n\n\t/* Pop alert */\n\t[alert showAlertWithCompletionBlock:^(TVCAlert *sender, TVCAlertResponseButton buttonClicked)\n\t {\n\t\t[self _finalizeAlert:alert\n\t\t\t\twithResponse:[self _convertResponseFromTVCAlert:buttonClicked]\n\t\t\t completionBlock:completionBlock\n\t\t\t  suppressionKey:suppressKey\n\t\t suppressionResponse:NULL];\n\t}];\n\n\treturn alert;\n}\n\n#pragma mark -\n#pragma mark Non-blocking Alerts (Sheet)\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n{\n\t[self alertSheetWithWindow:window\n\t\t\t\t\t\t  body:bodyText\n\t\t\t\t\t\t title:titleText\n\t\t\t\t defaultButton:buttonDefault\n\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t   otherButton:buttonOther\n\t\t\t\tsuppressionKey:nil\n\t\t\t   suppressionText:nil\n\t\t\t\t accessoryView:nil\n\t\t\t   completionBlock:nil];\n}\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\t[self alertSheetWithWindow:window\n\t\t\t\t\t\t  body:bodyText\n\t\t\t\t\t\t title:titleText\n\t\t\t\t defaultButton:buttonDefault\n\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t   otherButton:buttonOther\n\t\t\t\tsuppressionKey:nil\n\t\t\t   suppressionText:nil\n\t\t\t\t accessoryView:nil\n\t\t\t   completionBlock:completionBlock];\n}\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t   accessoryView:(nullable NSView *)accessoryView\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\t[self alertSheetWithWindow:window\n\t\t\t\t\t\t  body:bodyText\n\t\t\t\t\t\t title:titleText\n\t\t\t\t defaultButton:buttonDefault\n\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t   otherButton:buttonOther\n\t\t\t\tsuppressionKey:nil\n\t\t\t   suppressionText:nil\n\t\t\t\t accessoryView:accessoryView\n\t\t\t   completionBlock:completionBlock];\n}\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t  suppressionKey:(nullable NSString *)suppressKey\n\t\t\t suppressionText:(nullable NSString *)suppressText\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\t[self alertSheetWithWindow:window\n\t\t\t\t\t\t  body:bodyText\n\t\t\t\t\t\t title:titleText\n\t\t\t\t defaultButton:buttonDefault\n\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t   otherButton:buttonOther\n\t\t\t\tsuppressionKey:suppressKey\n\t\t\t   suppressionText:suppressText\n\t\t\t\t accessoryView:nil\n\t\t\t   completionBlock:completionBlock];\n}\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t  suppressionKey:(nullable NSString *)suppressKey\n\t\t\t suppressionText:(nullable NSString *)suppressText\n\t\t\t   accessoryView:(nullable NSView *)accessoryView\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n{\n\tNSParameterAssert(window != nil);\n\tNSParameterAssert(bodyText != nil);\n\tNSParameterAssert(titleText != nil);\n\tNSParameterAssert(buttonDefault != nil);\n\n\t/* Require main thread */\n\tif ([NSThread isMainThread] == NO) {\n\t\tXRPerformBlockSynchronouslyOnQueue(dispatch_get_main_queue(), ^{\n\t\t\t[self alertSheetWithWindow:window\n\t\t\t\t\t\t\t\t  body:bodyText\n\t\t\t\t\t\t\t\t title:titleText\n\t\t\t\t\t\t defaultButton:buttonDefault\n\t\t\t\t\t   alternateButton:buttonAlternate\n\t\t\t\t\t\t   otherButton:buttonOther\n\t\t\t\t\t\tsuppressionKey:suppressKey\n\t\t\t\t\t   suppressionText:suppressText\n\t\t\t\t\t\t accessoryView:accessoryView\n\t\t\t\t\t   completionBlock:completionBlock];\n\t\t});\n\n\t\treturn;\n\t}\n\n\t/* Prepare suppression */\n\tif (suppressKey) {\n\t\tsuppressKey = [self suppressionKeyWithBase:suppressKey];\n\n\t\t/* Exit if suppressed */\n\t\tif ([RZUserDefaults() boolForKey:suppressKey]) {\n\t\t\tif (completionBlock) {\n\t\t\t\tcompletionBlock(TDCAlertResponseDefault, YES, nil);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (suppressKey && (suppressText == nil || suppressText.length == 0)) {\n\t\tsuppressText = TXTLS(@\"Prompts[68u-z9]\");\n\t}\n\n\t/* Construct alert */\n\tNSAlert *alert = [NSAlert new];\n\n\talert.alertStyle = NSAlertStyleInformational;\n\n\talert.messageText = titleText;\n\talert.informativeText = bodyText;\n\n\t[alert addButtonWithTitle:buttonDefault];\n\n\tif (buttonAlternate) {\n\t\t[alert addButtonWithTitle:buttonAlternate];\n\t}\n\n\tif (buttonOther) {\n\t\t[alert addButtonWithTitle:buttonOther];\n\t}\n\n\tif (suppressKey || suppressText) {\n\t\talert.showsSuppressionButton = YES;\n\n\t\talert.suppressionButton.title = suppressText;\n\t}\n\n\tif (accessoryView) {\n\t\talert.accessoryView = accessoryView;\n\t}\n\n\t/* Construct alert context */\n\tTDCAlertContext *context = [TDCAlertContext new];\n\n\tcontext.suppressionKey = suppressKey;\n\n\tcontext.completionBlock = completionBlock;\n\n\t/* Pop alert */\n\t[alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) {\n\t\t[self _alertSheetResponseCallback:alert returnCode:returnCode contextInfo:context];\n\t}];\n}\n\n+ (void)_alertSheetResponseCallback:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(TDCAlertContext *)context\n{\n\tNSString *suppressionKey = context.suppressionKey;\n\n\tTDCAlertCompletionBlock completionBlock = context.completionBlock;\n\n\t[self _finalizeAlert:alert\n\t\t\twithResponse:[self _convertResponseFromNSAlert:returnCode]\n\t\t completionBlock:completionBlock\n\t\t  suppressionKey:suppressionKey\n\t suppressionResponse:NULL];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (NSString *)suppressionKeyWithBase:(NSString *)base\n{\n\tNSParameterAssert(base != nil);\n\n\tif ([base hasPrefix:TDCAlertSuppressionPrefix]) {\n\t\treturn base;\n\t}\n\n\treturn [TDCAlertSuppressionPrefix stringByAppendingString:base];\n}\n\n+ (void)_finalizeAlert:(nullable id)underlyingAlert\n\t\t  withResponse:(TDCAlertResponse)response\n\t   completionBlock:(nullable TDCAlertCompletionBlock)completionBlock\n\t\tsuppressionKey:(nullable NSString *)suppressionKey\n   suppressionResponse:(nullable BOOL *)suppressionResponse\n{\n\tBOOL suppressed = [self _recordSuppressionForButton:[underlyingAlert suppressionButton] withKey:suppressionKey];\n\n\tif ( suppressionResponse) {\n\t\t*suppressionResponse = suppressed;\n\t}\n\n\tif (completionBlock) {\n\t\tcompletionBlock(response, suppressed, underlyingAlert);\n\t}\n}\n\n+ (BOOL)_recordSuppressionForButton:(nullable NSButton *)suppressionButton withKey:(nullable NSString *)suppressionKey\n{\n\t/* There are some times when we use suppression text field\n\t to give user option that doesn't mean to suppress the\n\t prompt next time. We therefore only return NO for both\n\t arguments missing and not just one. */\n\tif (suppressionButton == nil && suppressionKey == nil) {\n\t\treturn NO;\n\t}\n\n\tBOOL suppressed = (suppressionButton.state == NSControlStateValueOn);\n\n\tif (suppressed && suppressionKey != nil) {\n\t\t[RZUserDefaults() setBool:YES forKey:suppressionKey];\n\t}\n\n\treturn suppressed;\n}\n\n+ (TDCAlertResponse)_convertResponseFromNSAlert:(NSUInteger)response\n{\n\tswitch (response) {\n\t\tcase NSAlertSecondButtonReturn:\n\t\t{\n\t\t\treturn TDCAlertResponseAlternate;\n\t\t}\n\t\tcase NSAlertThirdButtonReturn:\n\t\t{\n\t\t\treturn TDCAlertResponseOther;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn TDCAlertResponseDefault;\n\t\t}\n\t}\n}\n\n+ (TDCAlertResponse)_convertResponseFromTVCAlert:(TVCAlertResponseButton)response\n{\n\tswitch (response) {\n\t\tcase TVCAlertResponseButtonSecond:\n\t\t{\n\t\t\treturn TDCAlertResponseAlternate;\n\t\t}\n\t\tcase TVCAlertResponseButtonThird:\n\t\t{\n\t\t\treturn TDCAlertResponseOther;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn TDCAlertResponseDefault;\n\t\t}\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCAlertContext\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelBanListSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXGlobalModels.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCISupportInfo.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TDCChannelBanListSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelBanListSheetEntry : NSObject\n@property (nonatomic, copy) NSString *entryMask;\n@property (nonatomic, copy) NSString *entryAuthor;\n@property (readonly, copy) NSString *entryCreationDateString;\n@property (nonatomic, copy, nullable) NSDate *entryCreationDate;\n@end\n\n@interface TDCChannelBanListSheet ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, strong, readwrite) IRCChannel *channel;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, readwrite) NSString *channelId;\n@property (nonatomic, assign, readwrite) TDCChannelBanListSheetEntryType entryType;\n@property (nonatomic, copy, readwrite, nullable) NSArray<NSString *> *listOfChanges;\n@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *entryTable;\n@property (nonatomic, strong) IBOutlet NSArrayController *entryTableController;\n\n- (IBAction)onUpdate:(id)sender;\n- (IBAction)onRemoveEntry:(id)sender;\n@end\n\n@implementation TDCChannelBanListSheet\n\n- (nullable instancetype)initWithEntryType:(TDCChannelBanListSheetEntryType)entryType inChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ([self.class channel:channel supportsEntryType:entryType] == NO) {\n\t\treturn nil;\n\t}\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.entryType = entryType;\n\n\t\tself.client = channel.associatedClient;\n\t\tself.clientId = channel.associatedClient.uniqueIdentifier;\n\n\t\tself.channel = channel;\n\t\tself.channelId = channel.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelBanListSheet\" owner:self topLevelObjects:nil];\n\n\tself.entryTable.sortDescriptors = @[\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"entryCreationDate\" ascending:NO selector:@selector(compare:)]\n\t];\n\n\tNSString *headerTitle = nil;\n\n\tif (self.entryType == TDCChannelBanListSheetEntryTypeBan) {\n\t\theaderTitle = TXTLS(@\"TDCChannelBanListSheet[rhc-ke]\", self.channel.name);\n\t} else if (self.entryType == TDCChannelBanListSheetEntryTypeBanException) {\n\t\theaderTitle = TXTLS(@\"TDCChannelBanListSheet[gbi-wn]\", self.channel.name);\n\t} else if (self.entryType == TDCChannelBanListSheetEntryTypeInviteException) {\n\t\theaderTitle = TXTLS(@\"TDCChannelBanListSheet[ylc-6e]\", self.channel.name);\n\t} else if (self.entryType == TDCChannelBanListSheetEntryTypeQuiet) {\n\t\theaderTitle = TXTLS(@\"TDCChannelBanListSheet[g4r-t6]\", self.channel.name);\n\t}\n\n\tself.headerTitleTextField.stringValue = headerTitle;\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)clear\n{\n\tself.entryTableController.content = nil;\n}\n\n- (void)addEntry:(NSString *)entryMask setBy:(nullable NSString *)entryAuthor creationDate:(nullable NSDate *)entryCreationDate\n{\n\tNSParameterAssert(entryMask != nil);\n\n\tif (entryAuthor == nil) {\n\t\tentryAuthor = TXTLS(@\"BasicLanguage[vbl-xi]\"); // \"Unknown\"\n\t}\n\n\tTDCChannelBanListSheetEntry *newEntry = [TDCChannelBanListSheetEntry new];\n\n\tnewEntry.entryMask = entryMask;\n\tnewEntry.entryAuthor = entryAuthor;\n\tnewEntry.entryCreationDate = entryCreationDate;\n\n\t[self willChangeValueForKey:@\"entryCount\"];\n\n\t[self.entryTableController addObject:newEntry];\n\n\t[self didChangeValueForKey:@\"entryCount\"];\n}\n\n- (NSNumber *)entryCount\n{\n\treturn @([self.entryTableController.arrangedObjects count]);\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)onUpdate:(id)sender\n{\n\t[self clear];\n\n\tif ([self.delegate respondsToSelector:@selector(channelBanListSheetOnUpdate:)]) {\n\t\t[self.delegate channelBanListSheetOnUpdate:self];\n\t}\n}\n\n- (void)onRemoveEntry:(id)sender\n{\n\tNSIndexSet *selectedRows = self.entryTable.selectedRowIndexes;\n\n\tNSMutableArray<NSString *> *selectedEntries = [NSMutableArray arrayWithCapacity:selectedRows.count];\n\n\t[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\tTDCChannelBanListSheetEntry *entryItem = self.entryTableController.arrangedObjects[index];\n\n\t\t[selectedEntries addObject:entryItem.entryMask];\n\t}];\n\n\tself.listOfChanges =\n\t[self.client compileListOfModeChangesForModeSymbol:self.modeSymbol\n\t\t\t\t\t\t\t\t\t\t\t modeIsSet:NO\n\t\t\t\t\t\t\t\t\t\tmodeParameters:selectedEntries];\n\n\t[super cancel:nil];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (BOOL)channel:(IRCChannel *)channel supportsEntryType:(TDCChannelBanListSheetEntryType)entryType\n{\n\treturn [channel.associatedClient.supportInfo isListSupported:(IRCISupportInfoListType)entryType];\n}\n\n- (NSString *)modeSymbol\n{\n\t/* -modeSymbolForList: is nullable but because we only allow this class to be\n\t created if the mode is already supported, then we can advertise it here as non-nil */\n\treturn [self.client.supportInfo modeSymbolForList:(IRCISupportInfoListType)self.entryType];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(channelBanListSheetWillClose:)]) {\n\t\t[self.delegate channelBanListSheetWillClose:self];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCChannelBanListSheetEntry\n\n- (NSString *)entryCreationDateString\n{\n\tNSDate *entryCreationDate = self.entryCreationDate;\n\n\tif (entryCreationDate == nil) {\n\t\treturn TXTLS(@\"BasicLanguage[vbl-xi]\"); // \"Unknown\"\n\t}\n\n\treturn TXFormatDateLongStyle(entryCreationDate, YES);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelInviteSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClient.h\"\n#import \"TLOLocalization.h\"\n#import \"TDCChannelInviteSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelInviteSheet ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *nicknames;\n@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *channelListPopup;\n@end\n\n@implementation TDCChannelInviteSheet\n\n- (instancetype)initWithNicknames:(NSArray<NSString *> *)nicknames onClient:(IRCClient *)client\n{\n\tNSParameterAssert(nicknames != nil);\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.nicknames = nicknames;\n\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelInviteSheet\" owner:self topLevelObjects:nil];\n\n\tNSUInteger nicknameCount = self.nicknames.count;\n\n\tNSString *headerTitle = nil;\n\n\tif (nicknameCount == 1) {\n\t\theaderTitle = self.nicknames[0];\n\t} else if (nicknameCount == 2) {\n\t\theaderTitle = TXTLS(@\"TDCChannelInviteSheet[7i1-ds]\", self.nicknames[0], self.nicknames[1]);\n\t} else {\n\t\theaderTitle = TXTLS(@\"TDCChannelInviteSheet[c8p-sb]\", nicknameCount);\n\t}\n\n\tself.headerTitleTextField.stringValue = TXTLS(@\"TDCChannelInviteSheet[0lg-er]\", headerTitle);\n}\n\n- (void)startWithChannels:(NSArray<NSString *> *)channels\n{\n\tNSParameterAssert(channels != nil);\n\n\tfor (NSString *channel in channels) {\n\t\t[self.channelListPopup addItemWithTitle:channel];\n\t}\n\n\t[self startSheet];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self.delegate respondsToSelector:@selector(channelInviteSheet:onSelectChannel:)]) {\n\t\tNSString *channelName = self.channelListPopup.titleOfSelectedItem;\n\n\t\t[self.delegate channelInviteSheet:self onSelectChannel:channelName];\n\t}\n\n\t[super ok:nil];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(channelInviteSheetWillClose:)]) {\n\t\t[self.delegate channelInviteSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelModifyModesSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCChannelMode.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCModeInfo.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelModifyModesSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelModifyModesSheet () <NSControlTextEditingDelegate>\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, strong, readwrite) IRCChannel *channel;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, readwrite) NSString *channelId;\n@property (nonatomic, strong) IRCChannelModeContainer *modes;\n@property (nonatomic, weak) IBOutlet NSButton *sCheck;\n@property (nonatomic, weak) IBOutlet NSButton *pCheck;\n@property (nonatomic, weak) IBOutlet NSButton *nCheck;\n@property (nonatomic, weak) IBOutlet NSButton *tCheck;\n@property (nonatomic, weak) IBOutlet NSButton *iCheck;\n@property (nonatomic, weak) IBOutlet NSButton *mCheck;\n@property (nonatomic, weak) IBOutlet NSButton *kCheck;\n@property (nonatomic, weak) IBOutlet NSButton *lCheck;\n@property (nonatomic, weak) IBOutlet NSTextField *kText;\n@property (nonatomic, weak) IBOutlet NSTextField *lText;\n@property (nonatomic, copy) NSString *channelUserLimitMode;\n@property (nonatomic, assign) BOOL secretKeyLengthAlertDisplayed;\n\n- (IBAction)onChangeCheck:(id)sender;\n@end\n\n@implementation TDCChannelModifyModesSheet\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.clientId = channel.associatedClient.uniqueIdentifier;\n\n\t\tself.channel = channel;\n\t\tself.channelId = channel.uniqueIdentifier;\n\n\t\tself.modes = [channel.modeInfo.modes copy];\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelModifyModesSheet\" owner:self topLevelObjects:nil];\n}\n\n- (void)loadConfig\n{\n\tself.iCheck.state = [self.modes modeInfoFor:@\"i\"].modeIsSet;\n\tself.mCheck.state = [self.modes modeInfoFor:@\"m\"].modeIsSet;\n\tself.nCheck.state = [self.modes modeInfoFor:@\"n\"].modeIsSet;\n\tself.pCheck.state = [self.modes modeInfoFor:@\"p\"].modeIsSet;\n\tself.sCheck.state = [self.modes modeInfoFor:@\"s\"].modeIsSet;\n\tself.tCheck.state = [self.modes modeInfoFor:@\"t\"].modeIsSet;\n\n\tIRCModeInfo *kModeInfo = [self.modes modeInfoFor:@\"k\"];\n\n\tself.kCheck.state = kModeInfo.modeIsSet;\n\n\tif (kModeInfo.modeIsSet) {\n\t\tself.kText.stringValue = kModeInfo.modeParameter;\n\t}\n\n\tIRCModeInfo *lModeInfo = [self.modes modeInfoFor:@\"l\"];\n\n\tself.lCheck.state = lModeInfo.modeIsSet;\n\n\tif (lModeInfo.modeIsSet) {\n\t\tself.channelUserLimitMode = lModeInfo.modeParameter; // Set to local property for validation\n\t}\n\n\t[self updateTextFields];\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (BOOL)validateValue:(inout id *)value forKey:(NSString *)key error:(out NSError **)outError\n{\n\tif ([key isEqualToString:@\"channelUserLimitMode\"]) {\n\t\tNSInteger valueInteger = [*value integerValue];\n\n\t\tif (valueInteger < 0) {\n\t\t\t*value = [NSString stringWithInteger:0];\n\t\t} else if (valueInteger > 99999) {\n\t\t\t*value = [NSString stringWithInteger:99999];\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)updateTextFields\n{\n\tself.kText.enabled = (self.kCheck.state == NSControlStateValueOn);\n\n\tself.lText.enabled = (self.lCheck.state == NSControlStateValueOn);\n}\n\n- (void)onChangeCheck:(id)sender\n{\n\t[self updateTextFields];\n\n\tif (self.sCheck.state == NSControlStateValueOn &&\n\t\tself.pCheck.state == NSControlStateValueOn)\n\t{\n\t\tif (sender == self.sCheck) {\n\t\t\tself.pCheck.state = NSControlStateValueOff;\n\t\t} else {\n\t\t\tself.sCheck.state = NSControlStateValueOff;\n\t\t}\n\t}\n}\n\n- (void)controlTextDidChange:(NSNotification *)aNotification\n{\n\tif (aNotification.object == self.kText) {\n\t\t[self updateSecretKeyLengthAlert];\n\t}\n}\n\n- (void)updateSecretKeyLengthAlert\n{\n\tNSUInteger maximumKeyLength = self.client.supportInfo.maximumKeyLength;\n\n\tif (maximumKeyLength == 0) {\n\t\treturn;\n\t}\n\n\tNSUInteger currentKeyLength = self.kText.stringValue.length;\n\n\tif (currentKeyLength <= maximumKeyLength) {\n\t\treturn;\n\t}\n\n\tif (self.secretKeyLengthAlertDisplayed == NO) {\n\t\tself.secretKeyLengthAlertDisplayed = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\t[TDCAlert alertSheetWithWindow:self.sheet\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCChannelModifyModesSheet[lir-ra]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCChannelModifyModesSheet[7m9-39]\", self.client.networkNameAlt, maximumKeyLength)\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t\tsuppressionKey:@\"maximum_secret_key_length\"\n\t\t\t\t   suppressionText:nil\n\t\t\t\t   completionBlock:nil];\n}\n\n- (void)ok:(id)sender\n{\n\t[self.modes changeMode:@\"i\"\n\t\t\t\t modeIsSet:(self.iCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"m\"\n\t\t\t\t modeIsSet:(self.mCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"n\"\n\t\t\t\t modeIsSet:(self.nCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"p\"\n\t\t\t\t modeIsSet:(self.pCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"s\"\n\t\t\t\t modeIsSet:(self.sCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"t\"\n\t\t\t\t modeIsSet:(self.tCheck.state == NSControlStateValueOn)];\n\n\t[self.modes changeMode:@\"k\"\n\t\t\t\t modeIsSet:(self.kCheck.state == NSControlStateValueOn)\n\t\t\t modeParameter:self.kText.stringValue];\n\n\t[self.modes changeMode:@\"l\"\n\t\t\t\t modeIsSet:(self.lCheck.state == NSControlStateValueOn)\n\t\t\t modeParameter:self.lText.stringValue];\n\n\tif ([self.delegate respondsToSelector:@selector(channelModifyModesSheet:onOk:)]) {\n\t\t[self.delegate channelModifyModesSheet:self onOk:self.modes];\n\t}\n\n\t[super ok:nil];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(channelModifyModesSheetWillClose:)]) {\n\t\t[self.delegate channelModifyModesSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelModifyTopicSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCISupportInfo.h\"\n#import \"TVCTextViewWithIRCFormatterPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelModifyTopicSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelModifyTopicSheet ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, strong, readwrite) IRCChannel *channel;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, readwrite) NSString *channelId;\n@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;\n@property (nonatomic, strong) IBOutlet TVCTextViewWithIRCFormatter *topicValueTextField;\n@property (nonatomic, assign) BOOL topicLengthAlertDisplayed;\n@end\n\n@implementation TDCChannelModifyTopicSheet\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.clientId = channel.associatedClient.uniqueIdentifier;\n\n\t\tself.channel = channel;\n\t\tself.channelId = channel.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelModifyTopicSheet\" owner:self topLevelObjects:nil];\n\n\tNSString *headerTitle = [NSString stringWithFormat:self.headerTitleTextField.stringValue, self.channel.name];\n\n\tself.headerTitleTextField.stringValue = headerTitle;\n\n\tself.topicValueTextField.preferredFont = [NSFont systemFontOfSize:13.0];\n\tself.topicValueTextField.preferredFontColor = [NSColor textColor];\n\n\tNSString *topic = self.channel.topic;\n\n\tif (topic) {\n\t\tself.topicValueTextField.stringValueWithIRCFormatting = topic;\n\t}\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)textDidChange:(NSNotification *)aNotification\n{\n\t[self.topicValueTextField textDidChange:aNotification];\n\n\t[self updateTopicLengthAlert];\n}\n\n- (void)updateTopicLengthAlert\n{\n\tNSUInteger maximumTopicLength = self.client.supportInfo.maximumTopicLength;\n\n\tif (maximumTopicLength == 0) {\n\t\treturn;\n\t}\n\n\tNSUInteger currentTopicLength = self.topicValueTextField.stringLength;\n\n\tif (currentTopicLength <= maximumTopicLength) {\n\t\treturn;\n\t}\n\n\tif (self.topicLengthAlertDisplayed == NO) {\n\t\tself.topicLengthAlertDisplayed = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\t[TDCAlert alertSheetWithWindow:self.sheet\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCChannelModifyTopicSheet[zm4-cr]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCChannelModifyTopicSheet[27l-qx]\", self.client.networkNameAlt, maximumTopicLength)\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t\tsuppressionKey:@\"maximum_topic_length\"\n\t\t\t\t   suppressionText:nil\n\t\t\t\t   completionBlock:nil];\n}\n\n- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector\n{\n\tif (aSelector == @selector(insertNewline:)) {\n\t\t[self ok:nil];\n\n\t\treturn YES;\n\t} else if (aSelector == @selector(insertNewlineIgnoringFieldEditor:) ) {\n\t\t/* Do not allow a new line to be inserted using Option + Enter */\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self.delegate respondsToSelector:@selector(channelModifyTopicSheet:onOk:)]) {\n\t\tNSString *formattedTopic = self.topicValueTextField.stringValueWithIRCFormatting;\n\n\t\tNSString *topicWithoutNewlines = [formattedTopic stringByReplacingOccurrencesOfString:@\"\\n\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   withString:@\" \"];\n\n\t\t[self.delegate channelModifyTopicSheet:self onOk:topicWithoutNewlines];\n\t}\n\n\t[super ok:nil];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(channelModifyTopicSheetWillClose:)]) {\n\t\t[self.delegate channelModifyTopicSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelPropertiesNotificationConfiguration.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelConfig.h\"\n#import \"TDCChannelPropertiesSheetInternal.h\"\n#import \"TDCChannelPropertiesNotificationConfigurationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelPropertiesNotificationConfiguration ()\n@property (nonatomic, weak) TDCChannelPropertiesSheet *sheet;\n@property (readonly) IRCChannelConfigMutable *config;\n@end\n\n@implementation TDCChannelPropertiesNotificationConfiguration\n\n- (instancetype)initWithEventType:(TXNotificationType)aEventType inSheet:(TDCChannelPropertiesSheet *)sheet\n{\n\tNSParameterAssert(sheet != nil);\n\n\tif ((self = [super initWithEventType:aEventType])) {\n\t\tself.sheet = sheet;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (IRCChannelConfigMutable *)config\n{\n\treturn self.sheet.config;\n}\n\n- (nullable NSString *)alertSound\n{\n\treturn [self.config soundForEvent:self.eventType];\n}\n\n- (void)setAlertSound:(nullable NSString *)alertSound\n{\n\t[self.config setSound:alertSound forEvent:self.eventType];\n}\n\n- (NSUInteger)pushNotification\n{\n\treturn [self.config notificationEnabledForEvent:self.eventType];\n}\n\n- (void)setPushNotification:(NSUInteger)pushNotification\n{\n\t[self.config setNotificationEnabled:pushNotification forEvent:self.eventType];\n}\n\n- (NSUInteger)speakEvent\n{\n\treturn [self.config speakEvent:self.eventType];\n}\n\n- (void)setSpeakEvent:(NSUInteger)speakEvent\n{\n\t[self.config setEventIsSpoken:speakEvent forEvent:self.eventType];\n}\n\n- (NSUInteger)disabledWhileAway\n{\n\treturn [self.config disabledWhileAwayForEvent:self.eventType];\n}\n\n- (void)setDisabledWhileAway:(NSUInteger)disabledWhileAway\n{\n\t[self.config setDisabledWhileAway:disabledWhileAway forEvent:self.eventType];\n}\n\n- (NSUInteger)bounceDockIcon\n{\n\treturn [self.config bounceDockIconForEvent:self.eventType];\n}\n\n- (void)setBounceDockIcon:(NSUInteger)bounceDockIcon\n{\n\t[self.config setBounceDockIcon:bounceDockIcon forEvent:self.eventType];\n}\n\n- (NSUInteger)bounceDockIconRepeatedly\n{\n\treturn [self.config bounceDockIconRepeatedlyForEvent:self.eventType];\n}\n\n- (void)setBounceDockIconRepeatedly:(NSUInteger)bounceDockIconRepeatedly\n{\n\t[self.config setBounceDockIconRepeatedly:bounceDockIconRepeatedly forEvent:self.eventType];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCChannelPropertiesSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"NSViewHelper.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCISupportInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.h\"\n#import \"TVCNotificationConfigurationViewControllerPrivate.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelPropertiesNotificationConfigurationPrivate.h\"\n#import \"TDCChannelPropertiesSheetInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TDCChannelPropertiesSheetSelection)\n{\n\tTDCChannelPropertiesSheetSelectionGeneral = 0,\n\tTDCChannelPropertiesSheetSelectionDefaults = 1,\n\tTDCChannelPropertiesSheetSelectionNotifications = 2\n};\n\n@interface TDCChannelPropertiesSheet () <NSControlTextEditingDelegate>\n@property (nonatomic, strong, readwrite, nullable) IRCClient *client;\n@property (nonatomic, strong, readwrite, nullable) IRCChannel *channel;\n@property (nonatomic, copy, readwrite, nullable) NSString *clientId;\n@property (nonatomic, copy, readwrite, nullable) NSString *channelId;\n@property (nonatomic, assign) BOOL isNewConfiguration;\n@property (nonatomic, assign) BOOL secretKeyLengthAlertDisplayed;\n@property (nonatomic, copy) NSArray *navigationTree;\n@property (nonatomic, weak) IBOutlet NSButton *autoJoinCheck;\n@property (nonatomic, weak) IBOutlet NSButton *disableInlineMediaCheck;\n@property (nonatomic, weak) IBOutlet NSButton *enableInlineMediaCheck;\n@property (nonatomic, weak) IBOutlet NSButton *pushNotificationsCheck;\n@property (nonatomic, weak) IBOutlet NSButton *showTreeBadgeCountCheck;\n@property (nonatomic, weak) IBOutlet NSButton *ignoreHighlightsCheck;\n@property (nonatomic, weak) IBOutlet NSButton *ignoreGeneralEventMessagesCheck;\n@property (nonatomic, weak) IBOutlet NSSegmentedControl *contentViewTabView;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *channelNameTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *labelTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *defaultModesTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *defaultTopicTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *secretKeyTextField;\n@property (nonatomic, strong) IBOutlet NSView *contentView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewDefaultsView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewGeneralView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewNotifications;\n@property (nonatomic, strong) IBOutlet NSView *contentViewNotificationsHost;\n@property (nonatomic, strong) IBOutlet TVCNotificationConfigurationViewController *notificationsController;\n\n- (IBAction)onMenuBarItemChanged:(id)sender;\n\n- (IBAction)onInlineMediaCheckChanged:(id)sender;\n- (IBAction)onPushNotificationsCheckChanged:(id)sender;\n@end\n\n@implementation TDCChannelPropertiesSheet\n\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\tself.config = [IRCChannelConfigMutable new];\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_END\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\treturn [self initWithConfig:nil onClient:client];\n}\n\n- (instancetype)initWithClientId:(NSString *)clientId\n{\n\treturn [self initWithConfig:nil onClientWithId:clientId];\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.clientId = channel.associatedClient.uniqueIdentifier;\n\n\t\tself.channel = channel;\n\t\tself.channelId = channel.uniqueIdentifier;\n\n\t\tif (channel) {\n\t\t\tself.config = [channel.config mutableCopy];\n\t\t} else {\n\t\t\tself.config = [IRCChannelConfigMutable new];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config\n{\n\treturn [self initWithConfig:config onClientWithId:nil];\n}\n\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClient:(nullable IRCClient *)client\n{\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\tif (config) {\n\t\t\tself.config = [config mutableCopy];\n\t\t} else {\n\t\t\tself.config = [IRCChannelConfigMutable new];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClientWithId:(nullable NSString *)clientId\n{\n\tif ((self = [self initWithWindow:nil])) {\n\t\tself.clientId = clientId;\n\n\t\tif (config) {\n\t\t\tself.config = [config mutableCopy];\n\t\t} else {\n\t\t\tself.config = [IRCChannelConfigMutable new];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCChannelPropertiesSheet\" owner:self topLevelObjects:nil];\n\n\tself.navigationTree = @[\n\t\t//\t\tview\t\t\t\t\t\t\t\tfirst responder\n\t\t@[self.contentViewGeneralView,\t\t\tself.channelNameTextField],\n\t\t@[self.contentViewDefaultsView,\t\t\tself.defaultTopicTextField],\n\t\t@[self.contentViewNotifications,\t\t[NSNull null]],\n\t];\n\n\tself.channelNameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.channelNameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.channelNameTextField.textDidChangeCallback = self;\n\n\tself.channelNameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isChannelName == NO) {\n\t\t\treturn TXTLS(@\"TDCChannelPropertiesSheet[1nd-7x]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t[self addConfigurationDidChangeObserver];\n\n\t[self setupNotificationsController];\n}\n\n- (void)setupNotificationsController\n{\n\tself.notificationsController.allowsMixedState = YES;\n\n\tNSMutableArray *notifications = [NSMutableArray array];\n\n\t[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeHighlight inSheet:self]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeChannelMessage inSheet:self]];\n\t[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeChannelNotice inSheet:self]];\n\t[notifications addObject:@\" \"];\n\t[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeUserJoined inSheet:self]];\n\t[notifications addObject:[[TDCChannelPropertiesNotificationConfiguration alloc] initWithEventType:TXNotificationTypeUserParted inSheet:self]];\n\n\tself.notificationsController.notifications = notifications;\n\n\t[self.notificationsController attachToView:self.contentViewNotificationsHost];\n}\n\n- (void)reloadNotificationsController\n{\n\t[self.notificationsController reload];\n}\n\n- (void)updateNavigationEnabledState\n{\n\t[self.contentViewTabView setEnabled:(self.pushNotificationsCheck.state == NSControlStateValueOn)\n\t\t\t\t\t\t\t forSegment:TDCChannelPropertiesSheetSelectionNotifications];\n}\n\n- (void)loadConfig\n{\n\tself.channelNameTextField.stringValue = self.config.channelName;\n\tself.channelNameTextField.editable = (self.config.channelName.length == 0);\n\n\tself.labelTextField.stringValue = self.config.label;\n\n\tself.defaultModesTextField.stringValue = self.config.defaultModes;\n\tself.defaultTopicTextField.stringValue = self.config.defaultTopic;\n\n\tself.secretKeyTextField.stringValue = self.config.secretKey;\n\n\tself.autoJoinCheck.state = self.config.autoJoin;\n\tself.pushNotificationsCheck.state = self.config.pushNotifications;\n\tself.showTreeBadgeCountCheck.state = self.config.showTreeBadgeCount;\n\n\tself.ignoreGeneralEventMessagesCheck.state = self.config.ignoreGeneralEventMessages;\n\tself.ignoreHighlightsCheck.state = self.config.ignoreHighlights;\n\n\tself.disableInlineMediaCheck.state = self.config.inlineMediaDisabled;\n\tself.enableInlineMediaCheck.state = self.config.inlineMediaEnabled;\n\n\t[self updateNavigationEnabledState];\n}\n\n- (void)onMenuBarItemChanged:(id)sender\n{\n\t[self _navigateToSelection:[sender indexOfSelectedItem]];\n}\n\n- (void)navigateToSelection:(TDCChannelPropertiesSheetSelection)selection\n{\n\tif (self.contentViewTabView.indexOfSelectedItem == selection) {\n\t\treturn;\n\t}\n\n\t[self.contentViewTabView selectSegmentWithTag:selection];\n\n\t[self _navigateToSelection:selection];\n}\n\n- (void)_navigateToSelection:(TDCChannelPropertiesSheetSelection)selection\n{\n\t[self selectPane:self.navigationTree[selection][0]];\n\n\tid firstResponder = self.navigationTree[selection][1];\n\n\tif ([firstResponder isKindOfClass:[NSControl class]]) {\n\t\t[self.sheet makeFirstResponder:firstResponder];\n\t}\n}\n\n- (void)selectPane:(NSView *)view\n{\n\t[self.contentView replaceFirstSubview:view];\n}\n\n- (void)start\n{\n\t[self startSheet];\n\n\t[self _navigateToSelection:TDCChannelPropertiesSheetSelectionGeneral];\n}\n\n- (void)controlTextDidChange:(NSNotification *)aNotification\n{\n\tif (aNotification.object == self.secretKeyTextField) {\n\t\t[self updateSecretKeyLengthAlert];\n\t}\n}\n\n- (void)updateSecretKeyLengthAlert\n{\n\tNSUInteger maximumKeyLength = self.client.supportInfo.maximumKeyLength;\n\n\tif (maximumKeyLength == 0) {\n\t\treturn;\n\t}\n\n\tNSUInteger currentKeyLength = self.secretKeyTextField.stringValue.length;\n\n\tif (currentKeyLength <= maximumKeyLength) {\n\t\treturn;\n\t}\n\n\tif (self.secretKeyLengthAlertDisplayed == NO) {\n\t\tself.secretKeyLengthAlertDisplayed = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\t[TDCAlert alertSheetWithWindow:self.sheet\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCChannelPropertiesSheet[op4-gg]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCChannelPropertiesSheet[zf2-r7]\", self.client.networkNameAlt, maximumKeyLength)\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t\tsuppressionKey:@\"maximum_secret_key_length\"\n\t\t\t\t   suppressionText:nil\n\t\t\t\t   completionBlock:nil];\n}\n\n- (void)addConfigurationDidChangeObserver\n{\n\tif (self.channel == nil) {\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(underlyingConfigurationChanged:)\n\t\t\t\t\t\t\t\t   name:IRCChannelConfigurationWasUpdatedNotification\n\t\t\t\t\t\t\t\t object:self.channel];\n}\n\n- (void)removeConfigurationDidChangeObserver\n{\n\t[RZNotificationCenter() removeObserver:self];\n}\n\n- (void)underlyingConfigurationChanged:(NSNotification *)notification\n{\n\tIRCChannel *channel = notification.object;\n\n\tNSWindow *window = self.sheet;\n\t\n\t[TDCAlert alertSheetWithWindow:window\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCChannelPropertiesSheet[qby-hi]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCChannelPropertiesSheet[mvl-r5]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t   alternateButton:TXTLS(@\"Prompts[99q-gg]\")\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t   if (buttonClicked != TDCAlertResponseDefault) {\n\t\t\t\t\t\t   return;\n\t\t\t\t\t   }\n\t\t\t\t\t   \n\t\t\t\t\t   [self close];\n\t\t\t\t\t   \n\t\t\t\t\t   self.config = [channel.config copy];\n\t\t\t\t\t   \n\t\t\t\t\t   [self loadConfig];\n\t\t\t\t\t   \n\t\t\t\t\t   [self reloadNotificationsController];\n\t\t\t\t\t   \n\t\t\t\t\t   [self start];\n\t\t\t\t   }];\n}\n\n- (void)onInlineMediaCheckChanged:(id)sender\n{\n\tif (self.enableInlineMediaCheck.state != NSControlStateValueOn) {\n\t\treturn;\n\t}\n\n\t[TVCLogControllerInlineMediaService askPermissionToEnableInlineMediaWithCompletionBlock:^(BOOL granted) {\n\t\tif (granted == NO) {\n\t\t\tself.enableInlineMediaCheck.state = NSControlStateValueOff;\n\t\t}\n\t}];\n}\n\n- (void)onPushNotificationsCheckChanged:(id)sender\n{\n\t[self updateNavigationEnabledState];\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)cancel:(id)sender\n{\n\t[self removeConfigurationDidChangeObserver];\n\n\t[super cancel:sender];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\t[self removeConfigurationDidChangeObserver];\n\n\tself.config.channelName = self.channelNameTextField.value;\n\n\tself.config.label = self.labelTextField.trimmedStringValue;\n\n\tself.config.defaultModes = self.defaultModesTextField.trimmedStringValue;\n\tself.config.defaultTopic = self.defaultTopicTextField.trimmedStringValue;\n\n\tself.config.secretKey = self.secretKeyTextField.trimmedFirstTokenStringValue;\n\n\tself.config.autoJoin = self.autoJoinCheck.state;\n\tself.config.pushNotifications = self.pushNotificationsCheck.state;\n\tself.config.showTreeBadgeCount = self.showTreeBadgeCountCheck.state;\n\n\tself.config.ignoreGeneralEventMessages = self.ignoreGeneralEventMessagesCheck.state;\n\tself.config.ignoreHighlights = self.ignoreHighlightsCheck.state;\n\n\tself.config.inlineMediaDisabled = self.disableInlineMediaCheck.state;\n\tself.config.inlineMediaEnabled = self.enableInlineMediaCheck.state;\n\n\tif ([self.delegate respondsToSelector:@selector(channelPropertiesSheet:onOk:)]) {\n\t\t[self.delegate channelPropertiesSheet:self onOk:[self.config copy]];\n\t}\n\n\t[super ok:nil];\n}\n\n- (BOOL)okOrError\n{\n\treturn [self okOrErrorForTextField:self.channelNameTextField inSelection:TDCChannelPropertiesSheetSelectionGeneral];\n}\n\n- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField inSelection:(TDCChannelPropertiesSheetSelection)selection\n{\n\tif (textField.valueIsValid) {\n\t\treturn YES;\n\t}\n\n\t[self navigateToSelection:selection];\n\n\t/* Give navigation time to settle before trying to attach popover */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[textField showValidationErrorPopover];\n\t});\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.sheet makeFirstResponder:nil];\n\n\tif ([self.delegate respondsToSelector:@selector(channelPropertiesSheetWillClose:)]) {\n\t\t[self.delegate channelPropertiesSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCHighlightEntrySheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCChannelConfig.h\"\n#import \"IRCHighlightMatchCondition.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCHighlightEntrySheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCHighlightEntrySheet ()\n@property (nonatomic, strong) IRCHighlightMatchConditionMutable *config;\n@property (nonatomic, copy) NSArray<IRCChannelConfig *> *channelList;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *matchKeywordTextField;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *matchTypePopupButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *matchChannelPopupButton;\n@end\n\n@implementation TDCHighlightEntrySheet\n\n- (instancetype)initWithConfig:(nullable IRCHighlightMatchCondition *)config\n{\n\tif ((self = [super initWithWindow:nil])) {\n\t\tif (config) {\n\t\t\tself.config = [config mutableCopy];\n\t\t} else {\n\t\t\tself.config = [IRCHighlightMatchConditionMutable new];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCHighlightEntrySheet\" owner:self topLevelObjects:nil];\n\n\tself.matchKeywordTextField.stringValueUsesOnlyFirstToken = NO;\n\tself.matchKeywordTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.matchKeywordTextField.stringValueIsTrimmed = YES;\n\n\tself.matchKeywordTextField.textDidChangeCallback = self;\n}\n\n- (void)loadConfig\n{\n\tself.matchKeywordTextField.stringValue = self.config.matchKeyword;\n\n\tif (self.config.matchIsExcluded == NO) {\n\t\t[self.matchTypePopupButton selectItemWithTag:1];\n\t} else {\n\t\t[self.matchTypePopupButton selectItemWithTag:2];\n\t}\n}\n\n- (void)startWithChannels:(NSArray<IRCChannelConfig *> *)channels\n{\n\tNSParameterAssert(channels != nil);\n\n\tself.channelList = channels;\n\n\tNSString *matchChannelId = self.config.matchChannelId;\n\n\tNSUInteger channelCount = 0;\n\n\tfor (IRCChannelConfig *channel in self.channelList) {\n\t\tNSString *channelName = channel.channelName;\n\n\t\t[self.matchChannelPopupButton addItemWithTitle:channelName];\n\n\t\tif ([channel.uniqueIdentifier isEqualToString:matchChannelId]) {\n\t\t\t[self.matchChannelPopupButton selectItemWithTitle:channelName];\n\t\t}\n\n\t\tchannelCount += 1;\n\t}\n\n\tif (channelCount == 0) {\n\t\t[self.matchChannelPopupButton removeItemAtIndex:1];\n\t}\n\n\t[self startSheet];\n\n\t[self.sheet makeFirstResponder:self.matchKeywordTextField];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tself.config.matchIsExcluded = (self.matchTypePopupButton.selectedTag == 2);\n\n\tself.config.matchKeyword = self.matchKeywordTextField.value;\n\n\tNSInteger selectedChannelIndex = self.matchChannelPopupButton.indexOfSelectedItem;\n\n\tif (selectedChannelIndex > 0) {\n\t\tNSString *selectedChannelName = self.matchChannelPopupButton.titleOfSelectedItem;\n\n\t\tfor (IRCChannelConfig *c in self.channelList) {\n\t\t\tif ([c.channelName isEqualToString:selectedChannelName]) {\n\t\t\t\tself.config.matchChannelId = c.uniqueIdentifier;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t[self.delegate highlightEntrySheet:self onOk:[self.config copy]];\n\n\t[super ok:sender];\n}\n\n- (BOOL)okOrError\n{\n\treturn [self okOrErrorForTextField:self.matchKeywordTextField];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self.delegate highlightEntrySheetWillClose:self];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCInputPrompt.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCInputPrompt.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TDCInputPrompt\n\n+ (TVCAlertResponseButton)promptWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\t  prefillString:(nullable NSString *)prefillString\n\t\t\t\t\t\t\t   resultString:(NSString * _Nonnull * _Nonnull )resultString\n{\n\tNSParameterAssert(bodyText != nil);\n\tNSParameterAssert(titleText != nil);\n\tNSParameterAssert(buttonDefault != nil);\n\n\t/* Create text field */\n\tNSTextField *textField = [NSTextField new];\n\n\ttextField.translatesAutoresizingMaskIntoConstraints = NO;\n\n\t[textField addConstraints:\n\t @[\n\t   [NSLayoutConstraint constraintWithItem:textField\n\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeWidth\n\t\t\t\t\t\t\t\t\trelatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t   toItem:nil\n\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeNotAnAttribute\n\t\t\t\t\t\t\t\t   multiplier:1.0\n\t\t\t\t\t\t\t\t\t constant:295.0],\n\n\t   [NSLayoutConstraint constraintWithItem:textField\n\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeHeight\n\t\t\t\t\t\t\t\t\trelatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t   toItem:nil\n\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeNotAnAttribute\n\t\t\t\t\t\t\t\t   multiplier:1.0\n\t\t\t\t\t\t\t\t\t constant:22.0]\n\t   ]\n\t ];\n\n\ttextField.editable = YES;\n\ttextField.selectable = YES;\n\n\ttextField.drawsBackground = YES;\n\ttextField.bordered = YES;\n\ttextField.bezeled = YES;\n\n\ttextField.cell.lineBreakMode = NSLineBreakByTruncatingTail;\n\n\tif (prefillString) {\n\t\ttextField.stringValue = prefillString;\n\t}\n\n\t/* Create alert */\n\tTVCAlert *alert = [TVCAlert new];\n\n\talert.messageText = titleText;\n\talert.informativeText = bodyText;\n\n\t[alert setTitle:buttonDefault forButton:TVCAlertResponseButtonFirst];\n\t[alert setTitle:buttonAlternate forButton:TVCAlertResponseButtonSecond];\n\n\talert.accessoryView = textField;\n\n\talert.window.initialFirstResponder = textField;\n\n\t/* Run modal */\n\tTVCAlertResponseButton response = [alert runModal];\n\n\t/* Assign result */\n\t*resultString = textField.stringValue;\n\n\t/* Return response */\n\treturn response;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCNicknameColorSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n#import \"TDCNicknameColorSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCNicknameColorSheet ()\n@property (nonatomic, copy) NSString *nickname;\n@property (nonatomic, weak) IBOutlet NSColorWell *nicknameColorWell;\n\n- (IBAction)resetNicknameColor:(id)sender;\n@end\n\n@implementation TDCNicknameColorSheet\n\n- (instancetype)initWithNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.nickname = nickname;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCNicknameColorSheet\" owner:self topLevelObjects:nil];\n\n\tNSColor *nicknameColor =\n\t[IRCUserNicknameColorStyleGenerator nicknameColorStyleOverrideForKey:self.nickname];\n\n\tif (nicknameColor == nil) {\n\t\tnicknameColor = [NSColor whiteColor];\n\t}\n\n\tself.nicknameColorWell.color = nicknameColor;\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)ok:(id)sender\n{\n\tNSColor *nicknameColor = self.nicknameColorWell.color;\n\n\tif ([nicknameColor isEqual:[NSColor whiteColor]]) {\n\t\t nicknameColor = nil;\n\t}\n\n\t[IRCUserNicknameColorStyleGenerator setNicknameColorStyleOverride:nicknameColor forKey:self.nickname];\n\n\tif ([self.delegate respondsToSelector:@selector(nicknameColorSheetOnOk:)]) {\n\t\t[self.delegate nicknameColorSheetOnOk:self];\n\t}\n\n\t[super ok:nil];\n}\n\n- (void)resetNicknameColor:(id)sender\n{\n\tif ([NSColorPanel sharedColorPanelExists]) {\n\t\t[[NSColorPanel sharedColorPanel] close];\n\t}\n\n\tself.nicknameColorWell.color = [NSColor whiteColor];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(nicknameColorSheetWillClose:)]) {\n\t\t[self.delegate nicknameColorSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCProgressIndicatorSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TDCProgressIndicatorSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCProgressIndicatorSheet ()\n@property (nonatomic, weak) IBOutlet NSProgressIndicator *progressIndicator;\n@end\n\n@implementation TDCProgressIndicatorSheet\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tNSParameterAssert(window != nil);\n\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCProgressIndicatorSheet\" owner:self topLevelObjects:nil];\n}\n\n- (void)start\n{\n\t[self.progressIndicator startAnimation:nil];\n\n\t[self startSheet];\n}\n\n- (void)stop\n{\n\t[self.progressIndicator stopAnimation:nil];\n\n\t[self close];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCServerChangeNicknameSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"IRCClient.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCServerChangeNicknameSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCServerChangeNicknameSheet ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *tnewNicknameTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *toldNicknameTextField;\n@end\n\n@implementation TDCServerChangeNicknameSheet\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCServerChangeNicknameSheet\" owner:self topLevelObjects:nil];\n\n\tself.tnewNicknameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.tnewNicknameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.tnewNicknameTextField.textDidChangeCallback = self;\n\n\tself.tnewNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue isHostmaskNicknameOn:self.client] == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[och-j5]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\tNSString *nickname = self.client.userNickname;\n\n\tself.tnewNicknameTextField.stringValue = nickname;\n\n\tself.toldNicknameTextField.stringValue = nickname;\n}\n\n- (void)start\n{\n\t[self startSheet];\n\n\t[self.sheet makeFirstResponder:self.tnewNicknameTextField];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tif ([self.delegate respondsToSelector:@selector(serverChangeNicknameSheet:didInputNickname:)]) {\n\t\tNSString *newNickname = self.tnewNicknameTextField.value;\n\n\t\t[self.delegate serverChangeNicknameSheet:self didInputNickname:newNickname];\n\t}\n\n\t[super ok:sender];\n}\n\n- (BOOL)okOrError\n{\n\treturn [self okOrErrorForTextField:self.tnewNicknameTextField];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tif ([self.delegate respondsToSelector:@selector(serverChangeNicknameSheetWillClose:)]) {\n\t\t[self.delegate serverChangeNicknameSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCServerChannelListDialog.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSColorHelper.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TXGlobalModels.h\"\n#import \"NSTableViewHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClient.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TDCServerChannelListDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCServerChannelListDialogEntry : NSObject\n@property (nonatomic, copy) NSString *channelName;\n@property (nonatomic, copy) NSNumber *channelMemberCount;\n@property (nonatomic, copy) NSString *channelTopicUnformatted;\n@property (nonatomic, copy) NSAttributedString *channelTopicFormatted;\n@end\n\n@interface TDCServerChannelListDialog () <NSControlTextEditingDelegate>\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, assign) BOOL isWaitingForWrites;\n@property (nonatomic, strong) NSMutableArray<TDCServerChannelListDialogEntry *> *queuedWrites;\n@property (nonatomic, weak) IBOutlet NSButton *updateButton;\n@property (nonatomic, weak) IBOutlet NSSearchField *searchTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *networkNameTextField;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelListTable;\n@property (nonatomic, strong) IBOutlet NSArrayController *channelListController;\n\n- (IBAction)onClose:(id)sender;\n\n- (IBAction)onUpdate:(id)sender;\n- (IBAction)onJoinChannels:(id)sender;\n@end\n\n@implementation TDCServerChannelListDialog\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCServerChannelListDialog\" owner:self topLevelObjects:nil];\n\n\tself.queuedWrites = [NSMutableArray array];\n\n\tself.channelListTable.doubleAction = @selector(onJoin:);\n\n\tself.channelListTable.sortDescriptors = @[\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"channelMemberCount\" ascending:NO selector:@selector(compare:)]\n\t];\n\n\tself.networkNameTextField.stringValue = TXTLS(@\"TDCServerChannelListDialog[7qf-r0]\", self.client.networkNameAlt);\n}\n\n- (void)show\n{\n\t[self.window restoreWindowStateForClass:self.class];\n\n\t[super show];\n}\n\n- (void)clear\n{\n\tself.channelListController.content = nil;\n\n\t[self updateDialogTitle];\n}\n\n- (void)addChannel:(NSString *)channel count:(NSUInteger)count topic:(nullable NSString *)topic\n{\n\tNSParameterAssert(channel != nil);\n\n\tTDCServerChannelListDialogEntry *newEntry = [TDCServerChannelListDialogEntry new];\n\n\tnewEntry.channelName = channel;\n\tnewEntry.channelMemberCount = @(count);\n\n\tif (topic == nil) {\n\t\tnewEntry.channelTopicUnformatted = @\"\";\n\n\t\tnewEntry.channelTopicFormatted = [NSAttributedString attributedString];\n\t} else {\n\t\tnewEntry.channelTopicUnformatted = topic;\n\n\t\tNSAttributedString *topicFormatted =\n\t\t[topic attributedStringWithIRCFormatting:[NSTableView preferredGlobalTableViewFont]\n\t\t\t\t\t\t\t  preferredFontColor:[NSColor controlTextColor]];\n\n\t\tnewEntry.channelTopicFormatted = topicFormatted;\n\t}\n\n\t@synchronized(self.queuedWrites) {\n\t\t[self.queuedWrites addObject:newEntry];\n\t}\n\n\tif (self.isWaitingForWrites == NO) {\n\t\tself.isWaitingForWrites = YES;\n\n\t\t[self performSelectorInCommonModes:@selector(queuedWritesTimer) withObject:nil afterDelay:1.0];\n\t}\n}\n\n- (void)queuedWritesTimer\n{\n\tself.isWaitingForWrites = NO;\n\n\t[self writeQueuedWrites];\n}\n\n- (void)writeQueuedWrites\n{\n\t@synchronized(self.queuedWrites) {\n\t\tif (self.queuedWrites.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSPredicate *filterPredicate = self.channelListController.filterPredicate;\n\n\t\tif (filterPredicate) {\n\t\t\tNSMutableArray<TDCServerChannelListDialogEntry *> *queuedWrites = [NSMutableArray array];\n\n\t\t\tfor (TDCServerChannelListDialogEntry *queuedWrite in self.queuedWrites) {\n\t\t\t\tif ([filterPredicate evaluateWithObject:queuedWrite]) {\n\t\t\t\t\t[queuedWrites addObject:queuedWrite];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[self.channelListController addObjects:queuedWrites];\n\n\t\t\t[self.queuedWrites removeObjectsInArray:queuedWrites];\n\t\t} else {\n\t\t\t[self.channelListController addObjects:self.queuedWrites];\n\n\t\t\t[self.queuedWrites removeAllObjects];\n\t\t}\n\t}\n\n\t[self updateDialogTitle];\n}\n\n- (void)controlTextDidChange:(NSNotification *)obj\n{\n\tif (obj.object == self.searchTextField) {\n\t\tNSString *currentSearchValue = self.searchTextField.stringValue;\n\n\t\tif (currentSearchValue.length == 0) {\n\t\t\t[self writeQueuedWrites];\n\t\t}\n\t}\n}\n\n- (void)updateDialogTitle\n{\n\tid arrangedObjects = self.channelListController.arrangedObjects;\n\n\tNSString *arrangedObjectsCount = TXFormattedNumber([arrangedObjects count]);\n\n\tself.window.title = TXTLS(@\"TDCServerChannelListDialog[ct4-wh]\", arrangedObjectsCount);\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)onClose:(id)sender\n{\n\t[self close];\n}\n\n- (void)onUpdate:(id)sender\n{\n\t[self clear];\n\n\tif ([self.delegate respondsToSelector:@selector(serverChannelListDialogOnUpdate:)]) {\n\t\t[self.delegate serverChannelListDialogOnUpdate:self];\n\t}\n}\n\n/* onJoinChannels: handles join for selected items. */\n- (void)onJoinChannels:(id)sender\n{\n\t[self onJoin:sender];\n}\n\n/* onJoin: is a legacy method. It handles join on double click. */\n- (void)onJoin:(id)sender\n{\n\tNSIndexSet *selectedRows = self.channelListTable.selectedRowIndexes;\n\n\tNSMutableArray<NSString *> *channelNames = [NSMutableArray arrayWithCapacity:selectedRows.count];\n\n\t[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\tTDCServerChannelListDialogEntry *channelEntry = self.channelListController.arrangedObjects[index];\n\n\t\t[channelNames addObject:channelEntry.channelName];\n\t}];\n\n\tif ([self.delegate respondsToSelector:@selector(serverChannelListDialog:joinChannels:)]) {\n\t\t[self.delegate serverChannelListDialog:self joinChannels:[channelNames copy]];\n\t}\n\n\t[self.channelListTable deselectAll:nil];\n}\n\n#pragma mark -\n#pragma mark NSTableViewDelegate\n\n- (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes\n{\n#define _maximumSelectedRows\t8\n\n\treturn [tableView selectionIndexesForProposedSelection:proposedSelectionIndexes maximumNumberOfSelections:_maximumSelectedRows];\n\n#undef _maximumSelectedRows\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[self cancelPerformRequests];\n\n\tself.channelListTable.dataSource = nil;\n\tself.channelListTable.delegate = nil;\n\n\t[self.window saveWindowStateForClass:self.class];\n\n\tif ([self.delegate respondsToSelector:@selector(serverChannelDialogWillClose:)]) {\n\t\t[self.delegate serverChannelDialogWillClose:self];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TDCServerChannelListDialogEntry\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCServerHighlightListSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCHighlightLogEntryPrivate.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TVCMainWindow.h\"\n#import \"TDCServerHighlightListSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _renderedMessageTextFieldLeftRightPadding\t\t2.0\n\n@interface TDCServerHighlightListSheet ()\n@property (nonatomic, strong, readwrite) IRCClient *client;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, weak) IBOutlet NSTextField *headerTitleTextField;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *highlightListTable;\n@property (nonatomic, strong) IBOutlet NSArrayController *highlightListController;\n\n- (IBAction)onClearList:(id)sender;\n@end\n\n@implementation TDCServerHighlightListSheet\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super initWithWindow:nil])) {\n\t\tself.client = client;\n\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCServerHighlightListSheet\" owner:self topLevelObjects:nil];\n\n\tself.highlightListTable.doubleAction = @selector(highlightDoubleClicked:);\n\n\tself.highlightListTable.pasteboardDelegate = self;\n\n\tself.highlightListTable.sortDescriptors = @[\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"timeLogged\" ascending:NO selector:@selector(compare:)],\n\t\t[NSSortDescriptor sortDescriptorWithKey:@\"channelName\" ascending:NO selector:@selector(caseInsensitiveCompare:)]\n\t];\n\n\tNSString *headerTitle = [NSString stringWithFormat:self.headerTitleTextField.stringValue, self.client.networkNameAlt];\n\n\tself.headerTitleTextField.stringValue = headerTitle;\n\n\tNSArray *cachedHighlights = self.client.cachedHighlights;\n\n\tif (cachedHighlights) {\n\t\t[self addEntry:cachedHighlights];\n\t}\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)addEntry:(id)newEntry\n{\n\tNSParameterAssert(newEntry != nil);\n\n\tif ([newEntry isKindOfClass:[NSArray class]])\n\t{\n\t\tfor (id entry in newEntry) {\n\t\t\t[self addEntry:entry];\n\t\t}\n\t}\n\telse if ([newEntry isKindOfClass:[IRCHighlightLogEntry class]])\n\t{\n\t\tif ([newEntry isKindOfClass:[IRCHighlightLogEntryMutable class]]) {\n\t\t\tnewEntry = [newEntry copy];\n\t\t}\n\n\t\t[self.highlightListController addObject:newEntry];\n\t}\n}\n\n- (void)onClearList:(id)sender\n{\n\tself.highlightListController.content = nil;\n\n\t[self.client clearCachedHighlights];\n}\n\n- (void)highlightDoubleClicked:(id)sender\n{\n\tNSInteger row = self.highlightListTable.clickedRow;\n\n\tif (row < 0) {\n\t\treturn;\n\t}\n\n\tIRCHighlightLogEntry *entryItem = self.highlightListController.arrangedObjects[row];\n\n\tIRCChannel *channel = entryItem.channel;\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\tTVCLogController *viewController = channel.viewController;\n\n\t[viewController jumpToLine:entryItem.lineNumber completionHandler:^(BOOL result) {\n\t\tif (result) {\n\t\t\t[mainWindow() select:channel];\n\n\t\t\t[self cancel:nil];\n\t\t}\n\t}];\n}\n\n- (void)copy:(id)sender\n{\n\tNSIndexSet *selectedRows = self.highlightListTable.selectedRowIndexes;\n\n\tif (selectedRows.count == 0) {\n\t\treturn;\n\t}\n\n\tNSMutableString *stringToCopy = [NSMutableString string];\n\n\t[selectedRows enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\tIRCHighlightLogEntry *entryItem = self.highlightListController.arrangedObjects[index];\n\n\t\t[stringToCopy appendString:entryItem.description];\n\n\t\tif (index != selectedRows.lastIndex) {\n\t\t\t[stringToCopy appendString:@\"\\n\"];\n\t\t}\n\t}];\n\n\t[RZPasteboard() setStringContent:stringToCopy];\n}\n\n#pragma mark -\n#pragma mark NSTableView Delegate\n\n- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tNSTableCellView *result = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self];\n\n\treturn result;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tself.highlightListTable.dataSource = nil;\n\tself.highlightListTable.delegate = nil;\n\n\tif ([self.delegate respondsToSelector:@selector(serverHighlightListSheetWillClose:)]) {\n\t\t[self.delegate serverHighlightListSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCServerPropertiesSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <SecurityInterface/SFChooseIdentityPanel.h>\n\n#import \"NSStringHelper.h\"\n#import \"IRCClientConfigPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCHighlightMatchCondition.h\"\n#import \"IRCNetworkList.h\"\n#import \"IRCServer.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TVCValidatedComboBox.h\"\n#import \"TVCContentNavigationOutlineViewPrivate.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCAddressBookSheetPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelPropertiesSheetPrivate.h\"\n#import \"TDCHighlightEntrySheetPrivate.h\"\n#import \"TDCPreferencesControllerPrivate.h\"\n#import \"TDCServerEndpointListSheetPrivate.h\"\n#import \"TDCServerPropertiesSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _tableDragToken\t\t@\"TDCServerPropertiesSheetTableDragToken\"\n\n@interface TDCServerPropertiesSheet () <NSControlTextEditingDelegate>\n@property (nonatomic, strong, readwrite, nullable) IRCClient *client;\n@property (nonatomic, copy, readwrite, nullable) NSString *clientId;\n@property (nonatomic, strong) IRCClientConfigMutable *config;\n@property (nonatomic, copy) NSArray *navigationTreeMatrix;\n@property (nonatomic, copy) NSDictionary *encodingList;\n@property (nonatomic, strong) IRCNetworkList *networkList;\n@property (nonatomic, strong) IBOutlet NSMenu *addAddressBookEntryMenu;\n@property (nonatomic, strong) IBOutlet NSView *contentViewAddressBook;\n@property (nonatomic, strong) IBOutlet NSView *contentViewAutojoin;\n@property (nonatomic, strong) IBOutlet NSView *contentViewClientCertificate;\n@property (nonatomic, strong) IBOutlet NSView *contentViewConnectCommands;\n@property (nonatomic, strong) IBOutlet NSView *contentViewDisconnectMessages;\n@property (nonatomic, strong) IBOutlet NSView *contentViewEncoding;\n@property (nonatomic, strong) IBOutlet NSView *contentViewFloodControl;\n@property (nonatomic, strong) IBOutlet NSView *contentViewGeneral;\n@property (nonatomic, strong) IBOutlet NSView *contentViewHighlights;\n@property (nonatomic, strong) IBOutlet NSView *contentViewIdentity;\n@property (nonatomic, strong) IBOutlet NSView *contentViewNetworkSocket;\n@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServer;\n@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerInputView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerSystemSocksView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewProxyServerTorBrowserView;\n@property (nonatomic, strong) IBOutlet NSView *contentViewRedundancy;\n@property (nonatomic, strong) IBOutlet NSView *contentViewZncBouncer;\n@property (nonatomic, strong, nullable) TDCAddressBookSheet *addressBookSheet;\n@property (nonatomic, strong, nullable) TDCHighlightEntrySheet *highlightSheet;\n@property (nonatomic, strong, nullable) TDCChannelPropertiesSheet *channelSheet;\n@property (nonatomic, strong, nullable) TDCServerEndpointListSheet *serverEndpointSheet;\n@property (nonatomic, weak) IBOutlet NSButton *addAddressBookEntryButton;\n@property (nonatomic, weak) IBOutlet NSButton *addChannelButton;\n@property (nonatomic, weak) IBOutlet NSButton *addHighlightButton;\n@property (nonatomic, weak) IBOutlet NSButton *autoConnectCheck;\n@property (nonatomic, weak) IBOutlet NSButton *autoDisconnectOnSleepCheck;\n@property (nonatomic, weak) IBOutlet NSButton *autoReconnectCheck;\n@property (nonatomic, weak) IBOutlet NSButton *autojoinWaitsForNickServCheck;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateChangeCertificateButton;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateResetCertificateButton;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateMD5FingerprintCopyButton;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA1FingerprintCopyButton;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA2FingerprintCopyButton;\n@property (nonatomic, weak) IBOutlet NSButton *clientCertificateSHA512FingerprintCopyButton;\n@property (nonatomic, weak) IBOutlet NSButton *connectionIPv4AddressTypeCheck;\n@property (nonatomic, weak) IBOutlet NSButton *connectionIPv6AddressTypeCheck;\n@property (nonatomic, weak) IBOutlet NSButton *connectionDefaultAddressTypeCheck;\n@property (nonatomic, weak) IBOutlet NSButton *deleteAddressBookEntryButton;\n@property (nonatomic, weak) IBOutlet NSButton *deleteChannelButton;\n@property (nonatomic, weak) IBOutlet NSButton *deleteHighlightButton;\n@property (nonatomic, weak) IBOutlet NSButton *disconnectOnReachabilityChangeCheck;\n@property (nonatomic, weak) IBOutlet NSButton *editAddressBookEntryButton;\n@property (nonatomic, weak) IBOutlet NSButton *editChannelButton;\n@property (nonatomic, weak) IBOutlet NSButton *editHighlightButton;\n@property (nonatomic, weak) IBOutlet NSButton *hideAutojoinDelayedWarningsCheck;\n@property (nonatomic, weak) IBOutlet NSButton *performDisconnectOnPongTimerCheck;\n@property (nonatomic, weak) IBOutlet NSButton *pongTimerCheck;\n@property (nonatomic, weak) IBOutlet NSButton *prefersSecuredConnectionCheck;\n@property (nonatomic, weak) IBOutlet NSButton *setInvisibleModeOnConnectCheck;\n@property (nonatomic, weak) IBOutlet NSButton *validateServerCertificateChainCheck;\n@property (nonatomic, weak) IBOutlet NSButton *viewListOfPreferredCipherSuitesButton;\n@property (nonatomic, weak) IBOutlet NSButton *zncIgnoreConfiguredAutojoinCheck;\n@property (nonatomic, weak) IBOutlet NSButton *zncIgnorePlaybackNotificationsCheck;\n@property (nonatomic, weak) IBOutlet NSButton *zncOnlyPlaybackLatestCheck;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *fallbackEncodingButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *primaryEncodingButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *preferredCipherSuitesButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *proxyTypeButton;\n@property (nonatomic, weak) IBOutlet NSSlider *floodControlDelayTimerSlider;\n@property (nonatomic, weak) IBOutlet NSSlider *floodControlMessageCountSlider;\n@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateCommonNameField;\n@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateMD5FingerprintField;\n@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA1FingerprintField;\n@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA2FingerprintField;\n@property (nonatomic, weak) IBOutlet NSTextField *clientCertificateSHA512FingerprintField;\n@property (nonatomic, weak) IBOutlet NSTextField *nicknamePasswordTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *proxyPasswordTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *proxyUsernameTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *serverPasswordTextField;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *addressBookTable;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelListTable;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *highlightsTable;\n@property (nonatomic, weak) IBOutlet TVCValidatedComboBox *serverAddressComboBox;\n@property (nonatomic, weak) IBOutlet TVCContentNavigationOutlineView *navigationOutlineView;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *alternateNicknamesTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *awayNicknameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *connectionNameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *nicknameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *normalLeavingCommentTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *proxyAddressTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *proxyPortTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *realNameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *serverPortTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *sleepModeQuitMessageTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *usernameTextField;\n@property (nonatomic, unsafe_unretained) IBOutlet NSTextView *connectCommandsField;\n@property (nonatomic, assign) NSUInteger floodControlDelayTimerSliderTempValue;\n@property (nonatomic, assign) NSUInteger floodControlMessageCountSliderTempValue;\n@property (nonatomic, weak) NSPanel *clientCertificateSelectCertificatePanel;\n@property (nonatomic, strong) IBOutlet NSArrayController *addressBookArrayController;\n@property (nonatomic, strong) IBOutlet NSArrayController *channelListArrayController;\n@property (nonatomic, strong) IBOutlet NSArrayController *highlightListArrayController;\n@property (nonatomic, strong) IBOutlet NSArrayController *serverListArrayController;\n@property (readonly, copy) NSArray<IRCAddressBookEntry *> *addressBookList;\n@property (readonly, copy) NSArray<IRCChannelConfig *> *channelList;\n@property (readonly, copy) NSArray<IRCHighlightMatchCondition *> *highlightList;\n@property (readonly, copy) NSArray<IRCServer *> *serverList;\n@property (nonatomic, assign) BOOL populatingPrimaryServer;\n@property (nonatomic, assign) BOOL primaryServerIsPredefined;\n@property (nonatomic, copy, nullable) NSString *lastServerAddressValue;\n@property (nonatomic, copy, nullable) IRCServer *previousPrimaryServer;\n\n- (IBAction)proxyTypeChanged:(id)sender;\n- (IBAction)toggleAdvancedEncodings:(id)sender;\n\n- (IBAction)addChannel:(id)sender;\n- (IBAction)editChannel:(id)sender;\n- (IBAction)deleteChannel:(id)sender;\n\n- (IBAction)addHighlight:(id)sender;\n- (IBAction)editHighlight:(id)sender;\n- (IBAction)deleteHighlight:(id)sender;\n\n- (IBAction)addAddressBookEntry:(id)sender;\n- (IBAction)editAddressBookEntry:(id)sender;\n- (IBAction)deleteAddressBookEntry:(id)sender;\n\n- (IBAction)showAddAddressBookEntryMenu:(id)sender;\n\n- (IBAction)openProxySettingsInSystemPreferences:(id)sender;\n\n- (IBAction)editSeverEndpoints:(id)sender;\n\n- (IBAction)useSSLCheckChanged:(id)sender;\n\n- (IBAction)autojoinWaitsForNickServChanged:(id)sender;\n\n- (IBAction)onClientCertificateResetRequested:(id)sender;\n- (IBAction)onClientCertificateChangeRequested:(id)sender;\n- (IBAction)onClientCertificateFingerprintSHA512CopyRequested:(id)sender;\n- (IBAction)onClientCertificateFingerprintSHA2CopyRequested:(id)sender;\n- (IBAction)onClientCertificateFingerprintSHA1CopyRequested:(id)sender;\n- (IBAction)onClientCertificateFingerprintMD5CopyRequested:(id)sender;\n\n- (IBAction)preferredCipherSuitesChanged:(id)sender;\n- (IBAction)preferredCipherSuitesViewList:(id)sender;\n\n- (IBAction)preferredInternetProtocolChanged:(id)sender;\n@end\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wincomplete-implementation\"\n@implementation TDCServerPropertiesSheet\n\n- (instancetype)initWithClient:(nullable IRCClient *)client\n{\n\tif ((self = [super initWithWindow:nil])) {\n\t\tif (client) {\n\t\t\tself.client = client;\n\t\t\tself.clientId = client.uniqueIdentifier;\n\n\t\t\t[client updateStoredConfiguration];\n\n\t\t\tself.config = [client.config mutableCopy];\n\t\t} else {\n\t\t\tself.config = [IRCClientConfigMutable new];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\t[self loadConfig];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCServerPropertiesSheet\" owner:self topLevelObjects:nil];\n\n\t/* Populate server list combo box */\n\tself.networkList = [IRCNetworkList new];\n\n\tNSArray *listOfNetworks = self.networkList.listOfNetworks;\n\n\tfor (IRCNetwork *network in listOfNetworks) {\n\t\t[self.serverAddressComboBox addItemWithObjectValue:network.networkName];\n\t}\n\n\t/* Connect commands text box better font */\n\tself.connectCommandsField.font = [NSFont systemFontOfSize:13.0];\n\n\tself.connectCommandsField.textContainerInset = NSMakeSize(1, 3);\n\n\t/* Alternate nicknameS */\n\tself.alternateNicknamesTextField.textDidChangeCallback = self;\n\n\tself.alternateNicknamesTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.alternateNicknamesTextField.stringValueIsTrimmed = YES;\n\n\tself.alternateNicknamesTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tNSArray *nicknames = [currentValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\tfor (NSString *nickname in nicknames) {\n\t\t\tif (nickname.isHostmaskNickname == NO) {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[wlz-tb]\", nickname);\n\t\t\t}\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Away nickname */\n\tself.awayNicknameTextField.textDidChangeCallback = self;\n\n\tself.awayNicknameTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.awayNicknameTextField.stringValueIsTrimmed = YES;\n\tself.awayNicknameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.awayNicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isHostmaskNickname == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[och-j5]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Nickname */\n\tself.nicknameTextField.textDidChangeCallback = self;\n\n\tself.nicknameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.nicknameTextField.stringValueIsTrimmed = YES;\n\tself.nicknameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.nicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isHostmaskNickname == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[och-j5]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Username */\n\tself.usernameTextField.textDidChangeCallback = self;\n\n\tself.usernameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.usernameTextField.stringValueIsTrimmed = YES;\n\tself.usernameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.usernameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isHostmaskUsername == NO) {\n\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[8iw-q8]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Real name */\n\tself.realNameTextField.textDidChangeCallback = self;\n\n\tself.realNameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.realNameTextField.stringValueIsTrimmed = YES;\n\tself.realNameTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.realNameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[agy-bp]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Normal leaving comment */\n\tself.normalLeavingCommentTextField.textDidChangeCallback = self;\n\n\tself.normalLeavingCommentTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.normalLeavingCommentTextField.stringValueIsTrimmed = YES;\n\tself.normalLeavingCommentTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.normalLeavingCommentTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\tif (currentValue.length > 390) {\n\t\t\treturn TXTLS(@\"CommonErrors[2cb-af]\", 390);\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Sleep mode leaving comment */\n\tself.sleepModeQuitMessageTextField.textDidChangeCallback = self;\n\n\tself.sleepModeQuitMessageTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.sleepModeQuitMessageTextField.stringValueIsTrimmed = YES;\n\tself.sleepModeQuitMessageTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.sleepModeQuitMessageTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\tif (currentValue.length > 390) {\n\t\t\treturn TXTLS(@\"CommonErrors[2cb-af]\", 390);\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Connection name */\n\tself.connectionNameTextField.textDidChangeCallback = self;\n\n\tself.connectionNameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.connectionNameTextField.stringValueIsTrimmed = YES;\n\tself.connectionNameTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.connectionNameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([currentValue containsCharactersFromCharacterSet:[NSCharacterSet newlineCharacterSet]]) {\n\t\t\treturn TXTLS(@\"CommonErrors[gas-v8]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Server address */\n\tself.serverAddressComboBox.textDidChangeCallback = self;\n\n\tself.serverAddressComboBox.stringValueIsInvalidOnEmpty = YES;\n\tself.serverAddressComboBox.stringValueIsTrimmed = YES;\n\tself.serverAddressComboBox.stringValueUsesOnlyFirstToken = YES;\n\n\tself.serverAddressComboBox.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isValidInternetAddress == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[yyx-l3]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Server port */\n\tself.serverPortTextField.textDidChangeCallback = self;\n\n\tself.serverPortTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.serverPortTextField.stringValueIsTrimmed = YES;\n\tself.serverPortTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.serverPortTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isValidInternetPort == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[l0c-nb]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Proxy address */\n\tself.proxyAddressTextField.textDidChangeCallback = self;\n\n\tself.proxyAddressTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.proxyAddressTextField.stringValueIsTrimmed = YES;\n\tself.proxyAddressTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.proxyAddressTextField.performValidationWhenEmpty = YES;\n\n\tself.proxyAddressTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tNSInteger proxyType = self.proxyTypeButton.selectedTag;\n\n\t\tif (proxyType == IRCConnectionProxyTypeSocks4 ||\n\t\t\tproxyType == IRCConnectionProxyTypeSocks5 ||\n\t\t\tproxyType == IRCConnectionProxyTypeHTTP ||\n\t\t\tproxyType == IRCConnectionProxyTypeHTTPS)\n\t\t{\n\t\t\tif (currentValue.isValidInternetAddress == NO) {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[tlo-b6]\");\n\t\t\t}\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Proxy port */\n\tself.proxyPortTextField.textDidChangeCallback = self;\n\n\tself.proxyPortTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.proxyPortTextField.stringValueIsTrimmed = YES;\n\tself.proxyPortTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.proxyPortTextField.performValidationWhenEmpty = YES;\n\n\tself.proxyPortTextField.defaultValue = [NSString stringWithUnsignedInteger:IRCConnectionDefaultProxyPort];\n\n\tself.proxyPortTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tNSInteger proxyType = self.proxyTypeButton.selectedTag;\n\n\t\tif (proxyType == IRCConnectionProxyTypeSocks4 ||\n\t\t\tproxyType == IRCConnectionProxyTypeSocks5 ||\n\t\t\tproxyType == IRCConnectionProxyTypeHTTP ||\n\t\t\tproxyType == IRCConnectionProxyTypeHTTPS)\n\t\t{\n\t\t\tif (currentValue.isValidInternetPort == NO) {\n\t\t\t\treturn TXTLS(@\"CommonErrors[l0c-nb]\");\n\t\t\t}\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Setup others */\n\t[self addConfigurationDidChangeObserver];\n\n\tself.addressBookTable.doubleAction = @selector(tableViewDoubleClicked:);\n\tself.addressBookTable.target = self;\n\n\t[self.addressBookTable registerForDraggedTypes:@[_tableDragToken]];\n\n\tself.channelListTable.doubleAction = @selector(tableViewDoubleClicked:);\n\tself.channelListTable.target = self;\n\n\t[self.channelListTable registerForDraggedTypes:@[_tableDragToken]];\n\n\tself.highlightsTable.doubleAction = @selector(tableViewDoubleClicked:);\n\tself.highlightsTable.target = self;\n\n\t[self.highlightsTable registerForDraggedTypes:@[_tableDragToken]];\n\n\t[self populateEncodings];\n\n\t[self populateTabViewList];\n}\n\n- (void)dealloc\n{\n\tself.connectCommandsField = nil;\n}\n\n- (void)populateTabViewList\n{\n#define _groupItem(_label_, _children_) \t\\\n\t[[TVCContentNavigationOutlineViewItem alloc] initWithLabel:TXTLS(_label_) identifier:0 view:nil firstResponder:nil children:(_children_)]\n\n#define _childItem(_label_, _identifier_) \t\\\n\t[[TVCContentNavigationOutlineViewItem alloc] initWithLabel:TXTLS(_label_) identifier:TDCServerPropertiesSheetSelection ##_identifier_ view:self.contentView ##_identifier_ firstResponder:nil]\n\n\tNSArray *generalSectionChildren = @[\n\t\t_childItem(@\"TDCServerPropertiesSheet[8zc-6y]\", AddressBook),\n\t\t_childItem(@\"TDCServerPropertiesSheet[5oz-07]\", Autojoin),\n\t\t_childItem(@\"TDCServerPropertiesSheet[hip-13]\", ConnectCommands),\n\t\t_childItem(@\"TDCServerPropertiesSheet[8ug-ka]\", Encoding),\n\t\t_childItem(@\"TDCServerPropertiesSheet[ehx-4d]\", General),\n\t\t_childItem(@\"TDCServerPropertiesSheet[8ik-qo]\", Identity),\n\t\t_childItem(@\"TDCServerPropertiesSheet[jtx-hn]\", Highlights),\n\t\t_childItem(@\"TDCServerPropertiesSheet[j34-yr]\", DisconnectMessages),\n\t];\n\n\tNSArray *vendorSectionChildren = @[\n\t\t_childItem(@\"TDCServerPropertiesSheet[fsj-7f]\", ZncBouncer)\n\t];\n\n\tNSArray *advancedSectionChildren = @[\n\t\t_childItem(@\"TDCServerPropertiesSheet[ce7-kc]\", ClientCertificate),\n\t\t_childItem(@\"TDCServerPropertiesSheet[fcr-w8]\", FloodControl),\n\t\t_childItem(@\"TDCServerPropertiesSheet[ffy-xt]\", NetworkSocket),\n\t\t_childItem(@\"TDCServerPropertiesSheet[t52-7a]\", ProxyServer),\n\t\t_childItem(@\"TDCServerPropertiesSheet[36n-u9]\", Redundancy)\n\t];\n\n\tNSArray *navigationTreeMatrix = @[\n\t\t_groupItem(@\"TDCServerPropertiesSheet[lww-pc]\", generalSectionChildren),\n\t\t_groupItem(@\"TDCServerPropertiesSheet[v27-8w]\", vendorSectionChildren),\n\t\t_groupItem(@\"TDCServerPropertiesSheet[8uw-tz]\", advancedSectionChildren)\n\t];\n\n#undef _groupItem\n#undef _childItem\n\n\tself.navigationOutlineView.navigationTreeMatrix = navigationTreeMatrix;\n\n\t/* Auto layout will grow view beyond these values.\n\t We are just declaring the default which doesn't matter much. */\n\tself.navigationOutlineView.contentViewPreferredWidth = 100;\n\tself.navigationOutlineView.contentViewPreferredHeight = 100;\n\n\tself.navigationOutlineView.expandParentOnDoubleClick = YES;\n\n\t[self.navigationOutlineView expandItem:navigationTreeMatrix[0]];\n}\n\n- (void)populateEncodings\n{\n\t[self.primaryEncodingButton removeAllItems];\n\n\t[self.fallbackEncodingButton removeAllItems];\n\n\t/* Build list of encodings */\n\tself.encodingList = [NSString supportedStringEncodingsWithTitle:NO];\n\n\tNSArray *encodingNames = self.encodingList.sortedDictionaryKeys;\n\n\t/* What we are basically doing now is sorting all the encodings, then removing\n\t UTF-8 from the sorted list and inserting it at the top of the list. */\n\tNSString *utf8title = [NSString localizedNameOfStringEncoding:NSUTF8StringEncoding];\n\n\tNSMutableArray *encodingsToAdd = [encodingNames mutableCopy];\n\n\t[encodingsToAdd removeObject:utf8title];\n\n\t[self.primaryEncodingButton addItemWithTitle:utf8title];\n\n\t[self.fallbackEncodingButton addItemWithTitle:utf8title];\n\n\t/* Add the encodings to the popup list. This for loop will find the first\n\t parentheses opening and compare everything before it to the one found for\n\t the previous encoding. If the prefix has changed, then a separator is\n\t inserted. This groups the encodings.*/\n\t/* We do this two times. The first time setups up preferred encodings at\n\t the top of the list. The next handles everything else. */\n\tNSArray *favoredEncodings = @[@\"Unicode\", @\"Western\", @\"Central European\"];\n\n\t[self populateEncodingPopup:encodingsToAdd preferredEncodings:favoredEncodings ignoreFavored:NO];\n\n\tif ([RZUserDefaults() boolForKey:@\"Server Properties Window Sheet -> Include Advanced Encodings\"]) {\n\t\t[self populateEncodingPopup:encodingsToAdd preferredEncodings:favoredEncodings ignoreFavored:YES];\n\t}\n}\n\n- (void)populateEncodingPopup:(NSArray<NSString *> *)encodingsToAdd preferredEncodings:(NSArray<NSString *> *)favoredEncodings ignoreFavored:(BOOL)ignoreFavored\n{\n\tNSString *encodingPrefixPrevious = nil;\n\n\tfor (NSString *encoding in encodingsToAdd) {\n\t\tNSInteger parenthesisPosition = [encoding stringPosition:@\" (\"];\n\n\t\tif (parenthesisPosition <= 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *encodingPrefix = [encoding substringToIndex:parenthesisPosition];\n\n\t\tif (ignoreFavored && [favoredEncodings containsObject:encodingPrefix]) {\n\t\t\tcontinue;\n\t\t} else if (ignoreFavored == NO && [favoredEncodings containsObject:encodingPrefix] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ([encodingPrefix isEqualToString:encodingPrefixPrevious] == NO) {\n\t\t\tencodingPrefixPrevious = encodingPrefix;\n\n\t\t\t[self.primaryEncodingButton.menu addItem:[NSMenuItem separatorItem]];\n\n\t\t\t[self.fallbackEncodingButton.menu addItem:[NSMenuItem separatorItem]];\n\t\t}\n\n\t\t[self.primaryEncodingButton addItemWithTitle:encoding];\n\n\t\t[self.fallbackEncodingButton addItemWithTitle:encoding];\n\t}\n}\n\n#pragma mark -\n#pragma mark Initialization Handler\n\n- (void)start\n{\n\t[self startWithSelection:TDCServerPropertiesSheetSelectionDefault context:nil];\n}\n\n- (void)startWithSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context\n{\n\t[self startSheet];\n\n\t[self navigateToSelection:selection];\n\n\tswitch (selection) {\n\t\tcase TDCServerPropertiesSheetSelectionNewIgnoreEntry:\n\t\t{\n\t\t\tif ([context isKindOfClass:[NSString class]]) {\n\t\t\t\t[self addIgnoreAddressBookEntryWithHostmask:context];\n\t\t\t} else if ([context isKindOfClass:[IRCAddressBookEntry class]]) {\n\t\t\t\t[self editAddressBookEntryWithObject:context];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n- (void)navigateToSelection:(TDCServerPropertiesSheetSelection)selection\n{\n\tif (selection == TDCServerPropertiesSheetSelectionDefault) {\n\t\tselection = TDCServerPropertiesSheetSelectionGeneral;\n\t} else if (selection == TDCServerPropertiesSheetSelectionNewIgnoreEntry) {\n\t\tselection = TDCServerPropertiesSheetSelectionAddressBook;\n\t}\n\n\t[self.navigationOutlineView navigateToItemWithIdentifier:selection];\n\n\t[self.sheet recalculateKeyViewLoop];\n}\n\n- (void)closeChildSheets\n{\n\tif (self.addressBookSheet) {\n\t\t[self.addressBookSheet close];\n\t} else if (self.channelSheet) {\n\t\t[self.channelSheet close];\n\t} else if (self.highlightSheet) {\n\t\t[self.highlightSheet close];\n\t} else if (self.serverEndpointSheet) {\n\t\t[self.serverEndpointSheet close];\n\t} else if (self.clientCertificateSelectCertificatePanel) {\n\t\t[NSApp stopModalWithCode:NSModalResponseCancel];\n\t}\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\t[self removeConfigurationDidChangeObserver];\n\n\t[self closeChildSheets];\n\n\t[self clearChannelListPredicate];\n\n\t[self saveConfig];\n\n\tif ([self.delegate respondsToSelector:@selector(serverPropertiesSheet:onOk:)]) {\n\t\t[self.delegate serverPropertiesSheet:self onOk:[self.config copy]];\n\t}\n\n\t[super ok:nil];\n}\n\n- (BOOL)okOrError\n{\n\tTDCServerPropertiesSheetSelection selection = self.navigationOutlineView.selectedItem.identifier;\n\n\tif ([self okOrErrorForSelection:selection] == NO) {\n\t\treturn NO;\n\t}\n\n\t/* We want to show the error for the visible view first so that\n\t the user isn't jerked around. To accomplish this, we keep an\n\t array of views in which error occurs. Check error in visible\n\t view, remove that from array, then enumerate the rest. */\n\tNSMutableArray *remainingSelections =\n\t[@[\n\t   @(TDCServerPropertiesSheetSelectionGeneral),\n\t   @(TDCServerPropertiesSheetSelectionIdentity),\n\t   @(TDCServerPropertiesSheetSelectionDisconnectMessages),\n\t   @(TDCServerPropertiesSheetSelectionProxyServer),\n\t   ] mutableCopy];\n\n\t[remainingSelections removeObject:@(selection)];\n\n\tfor (NSNumber *selectionRemaining in remainingSelections) {\n\t\tif ([self okOrErrorForSelection:selectionRemaining.integerValue] == NO) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)okOrErrorForSelection:(TDCServerPropertiesSheetSelection)selection\n{\n\tswitch (selection) {\n\t\tcase TDCServerPropertiesSheetSelectionGeneral:\n\t\t{\n\t\t\tif ([self okOrErrorForTextField:self.connectionNameTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForComboBox:self.serverAddressComboBox inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.serverPortTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\n\t\tcase TDCServerPropertiesSheetSelectionIdentity:\n\t\t{\n\t\t\tif ([self okOrErrorForTextField:self.nicknameTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.awayNicknameTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.alternateNicknamesTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.usernameTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.realNameTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\n\t\tcase TDCServerPropertiesSheetSelectionDisconnectMessages:\n\t\t{\n\t\t\tif ([self okOrErrorForTextField:self.normalLeavingCommentTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.sleepModeQuitMessageTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\n\t\tcase TDCServerPropertiesSheetSelectionProxyServer:\n\t\t{\n\t\t\tif ([self okOrErrorForTextField:self.proxyAddressTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t} else if ([self okOrErrorForTextField:self.proxyPortTextField inSelection:selection] == NO) {\n\t\t\t\treturn NO;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n\n\treturn YES;\n}\n\n- (BOOL)okOrErrorForComboBox:(TVCValidatedComboBox *)comboBox inSelection:(TDCServerPropertiesSheetSelection)selection\n{\n\tif (comboBox.valueIsValid) {\n\t\treturn YES;\n\t}\n\n\t[self navigateToSelection:selection];\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[comboBox showValidationErrorPopover];\n\t});\n\n\treturn NO;\n}\n\n- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField inSelection:(TDCServerPropertiesSheetSelection)selection\n{\n\tif (textField.valueIsValid) {\n\t\treturn YES;\n\t}\n\n\t[self navigateToSelection:selection];\n\n\t/* Give navigation time to settle before trying to attach popover */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[textField showValidationErrorPopover];\n\t});\n\n\treturn NO;\n}\n\n- (void)cancel:(id)sender\n{\n\t[self removeConfigurationDidChangeObserver];\n\n\t[self closeChildSheets];\n\n\t[super cancel:nil];\n}\n\n- (void)addConfigurationDidChangeObserver\n{\n\tif (self.client == nil) {\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(underlyingConfigurationChanged:)\n\t\t\t\t\t\t\t\t   name:IRCClientConfigurationWasUpdatedNotification\n\t\t\t\t\t\t\t\t object:self.client];\n}\n\n- (void)removeConfigurationDidChangeObserver\n{\n\t[RZNotificationCenter() removeObserver:self];\n}\n\n- (void)underlyingConfigurationChanged:(NSNotification *)notification\n{\n\tIRCClient *client = notification.object;\n\n\tNSWindow *window = self.sheet.deepestWindow;\n\t\n\t[TDCAlert alertSheetWithWindow:window\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCServerPropertiesSheet[oz4-kb]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCServerPropertiesSheet[bzh-il]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t   alternateButton:TXTLS(@\"Prompts[99q-gg]\")\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t   if (buttonClicked != TDCAlertResponseDefault) {\n\t\t\t\t\t\t   return;\n\t\t\t\t\t   }\n\t\t\t\t\t   \n\t\t\t\t\t   [self close];\n\t\t\t\t\t   \n\t\t\t\t\t   [client updateStoredConfiguration];\n\t\t\t\t\t   \n\t\t\t\t\t   self.config = [client.config mutableCopy];\n\t\t\t\t\t   \n\t\t\t\t\t   [self loadConfig];\n\t\t\t\t\t   \n\t\t\t\t\t   [self start];\n\t\t\t\t   }];\n}\n\n- (void)loadConfig\n{\n\t/* General */\n\tself.connectionNameTextField.stringValue = self.config.connectionName;\n\n\tself.autoConnectCheck.state = self.config.autoConnect;\n\tself.autoReconnectCheck.state = self.config.autoReconnect;\n\tself.autoDisconnectOnSleepCheck.state = self.config.autoSleepModeDisconnect;\n\n\t/* ZNC Bouncer */\n\tself.zncIgnoreConfiguredAutojoinCheck.state = self.config.zncIgnoreConfiguredAutojoin;\n\tself.zncIgnorePlaybackNotificationsCheck.state = self.config.zncIgnorePlaybackNotifications;\n\tself.zncOnlyPlaybackLatestCheck.state = self.config.zncOnlyPlaybackLatest;\n\n\t/* Network Socket */\n\tIRCConnectionAddressType addressType = self.config.addressType;\n\n\tself.connectionIPv4AddressTypeCheck.state = (addressType == IRCConnectionAddressTypeIPv4);\n\tself.connectionIPv6AddressTypeCheck.state = (addressType == IRCConnectionAddressTypeIPv6);\n\tself.connectionDefaultAddressTypeCheck.state = (addressType == IRCConnectionAddressTypeDefault);\n\n\tself.pongTimerCheck.state = self.config.performPongTimer;\n\tself.performDisconnectOnPongTimerCheck.state = self.config.performDisconnectOnPongTimer;\n\n\tself.disconnectOnReachabilityChangeCheck.state = self.config.performDisconnectOnReachabilityChange;\n\n\tself.validateServerCertificateChainCheck.state = self.config.validateServerCertificateChain;\n\n\t[self.preferredCipherSuitesButton selectItemWithTag:self.config.cipherSuites];\n\n\t/* Identity */\n\tif (self.config.nickname.length > 0) {\n\t\tself.nicknameTextField.stringValue = self.config.nickname;\n\t} else {\n\t\tself.nicknameTextField.stringValue = [TPCPreferences defaultNickname];\n\t}\n\n\tself.awayNicknameTextField.stringValue = self.config.awayNickname;\n\n\tNSString *alternateNicknamesString = [self.config.alternateNicknames componentsJoinedByString:@\" \"];\n\n\tself.alternateNicknamesTextField.stringValue = alternateNicknamesString;\n\n\tif (self.config.username.length > 0) {\n\t\tself.usernameTextField.stringValue = self.config.username;\n\t} else {\n\t\tself.usernameTextField.stringValue = [TPCPreferences defaultUsername];\n\t}\n\n\tif (self.config.realName.length > 0) {\n\t\tself.realNameTextField.stringValue = self.config.realName;\n\t} else {\n\t\tself.realNameTextField.stringValue = [TPCPreferences defaultRealName];\n\t}\n\n\tself.nicknamePasswordTextField.stringValue = self.config.nicknamePassword;\n\n\tself.autojoinWaitsForNickServCheck.state = self.config.autojoinWaitsForNickServ;\n\n\tself.hideAutojoinDelayedWarningsCheck.state = (self.config.hideAutojoinDelayedWarnings == NO);\n\n\t/* Messages */\n\tself.normalLeavingCommentTextField.stringValue = self.config.normalLeavingComment;\n\n\tself.sleepModeQuitMessageTextField.stringValue = self.config.sleepModeLeavingComment;\n\n\t/* Encoding */\n\tNSString *primaryEncodingTitle = [self.encodingList firstKeyForObject:@(self.config.primaryEncoding)];\n\n\t[self.primaryEncodingButton selectItemWithTitle:primaryEncodingTitle];\n\n\tNSString *fallbackEncodingTitle = [self.encodingList firstKeyForObject:@(self.config.fallbackEncoding)];\n\n\t[self.fallbackEncodingButton selectItemWithTitle:fallbackEncodingTitle];\n\n\t/* Proxy Server */\n\t[self.proxyTypeButton selectItemWithTag:self.config.proxyType];\n\n\tself.proxyAddressTextField.stringValue = self.config.proxyAddress;\n\tself.proxyPortTextField.integerValue = self.config.proxyPort;\n\tself.proxyUsernameTextField.stringValue = self.config.proxyUsername;\n\tself.proxyPasswordTextField.stringValue = self.config.proxyPassword;\n\n\t/* Connect Commands */\n\tNSString *loginCommandsString = [self.config.loginCommands componentsJoinedByString:@\"\\n\"];\n\n\tself.connectCommandsField.string = loginCommandsString;\n\n\tself.setInvisibleModeOnConnectCheck.state = self.config.setInvisibleModeOnConnect;\n\n\t/* Flood Control */\n\tself.floodControlDelayTimerSliderTempValue = self.config.floodControlDelayTimerInterval;\n\tself.floodControlMessageCountSliderTempValue = self.config.floodControlMaximumMessages;\n\n\t/* Mutable Stores */\n\t[self.addressBookArrayController addObjects:self.config.ignoreList];\n\t[self.channelListArrayController addObjects:self.config.channelList];\n\t[self.highlightListArrayController addObjects:self.config.highlightList];\n\t[self.serverListArrayController addObjects:self.config.serverList];\n\n\t/* Special loads */\n\t[self loadPrimaryServerEndpoint];\n\n\t[self loadConfigPostflight];\n}\n\n- (void)loadPrimaryServerEndpoint\n{\n\tIRCServer *server = self.serverList.firstObject;\n\n\tif (server == nil) {\n\t\tself.serverAddressComboBox.stringValue = @\"\";\n\n\t\tself.serverPortTextField.integerValue = IRCConnectionDefaultServerPort;\n\n\t\tself.prefersSecuredConnectionCheck.state = NSControlStateValueOff;\n\n\t\tself.serverPasswordTextField.stringValue = @\"\";\n\n\t\treturn;\n\t}\n\n\tself.populatingPrimaryServer = YES;\n\n\tNSString *serverAddress = server.serverAddress;\n\n\tif (serverAddress) {\n\t\tIRCNetwork *serverAddressNetwork = [self.networkList networkWithServerAddress:serverAddress];\n\n\t\tif (serverAddressNetwork) {\n\t\t\tself.serverAddressComboBox.stringValue = serverAddressNetwork.networkName;\n\t\t} else {\n\t\t\tself.serverAddressComboBox.stringValue = serverAddress;\n\t\t}\n\t}\n\n\tself.serverPortTextField.integerValue = server.serverPort;\n\n\tself.prefersSecuredConnectionCheck.state = server.prefersSecuredConnection;\n\n\tself.serverPasswordTextField.stringValue = server.serverPassword;\n\n\tself.populatingPrimaryServer = NO;\n}\n\n- (void)loadConfigPostflight\n{\n\t[self setChannelListPredicate];\n\n\t[self updateAddressBookPage];\n\t[self updateChannelListPage];\n\t[self updateClientCertificatePage];\n\t[self updateHighlightsPage];\n\t[self updateIdentityPage];\n\n\t[self preferredCipherSuitesChanged:nil];\n\n\t[self proxyTypeChanged:nil];\n}\n\n- (void)saveConfig\n{\n\t/* General */\n\tself.config.connectionName = self.connectionNameTextField.value;\n\n\tself.config.autoConnect\t= (self.autoConnectCheck.state == NSControlStateValueOn);\n\tself.config.autoReconnect = (self.autoReconnectCheck.state == NSControlStateValueOn);\n\tself.config.autoSleepModeDisconnect = (self.autoDisconnectOnSleepCheck.state == NSControlStateValueOn);\n\n\t/* ZNC Bouncer */\n\tself.config.zncIgnoreConfiguredAutojoin = (self.zncIgnoreConfiguredAutojoinCheck.state == NSControlStateValueOn);\n\tself.config.zncIgnorePlaybackNotifications = (self.zncIgnorePlaybackNotificationsCheck.state == NSControlStateValueOn);\n\tself.config.zncOnlyPlaybackLatest = (self.zncOnlyPlaybackLatestCheck.state == NSControlStateValueOn);\n\n\t/* Network Socket */\n\tself.config.performPongTimer = (self.pongTimerCheck.state == NSControlStateValueOn);\n\tself.config.performDisconnectOnPongTimer = (self.performDisconnectOnPongTimerCheck.state == NSControlStateValueOn);\n\n\tself.config.performDisconnectOnReachabilityChange = (self.disconnectOnReachabilityChangeCheck.state == NSControlStateValueOn);\n\n\tself.config.validateServerCertificateChain = (self.validateServerCertificateChainCheck.state == NSControlStateValueOn);\n\n\tself.config.cipherSuites = self.preferredCipherSuitesButton.selectedTag;\n\n\t/* Identity */\n\tself.config.nickname = self.nicknameTextField.value;\n\tself.config.username = self.usernameTextField.value;\n\tself.config.realName = self.realNameTextField.value;\n\n\tself.config.awayNickname = self.awayNicknameTextField.value;\n\n\tself.config.nicknamePassword = self.nicknamePasswordTextField.trimmedStringValue;\n\n\tself.config.autojoinWaitsForNickServ = (self.autojoinWaitsForNickServCheck.state == NSControlStateValueOn);\n\n\tself.config.hideAutojoinDelayedWarnings = (self.hideAutojoinDelayedWarningsCheck.state != NSControlStateValueOn);\n\n\t/* Alternate nicknames */\n\tNSString *alternateNicknamesString = self.alternateNicknamesTextField.value;\n\n\tNSArray *alternateNicknames = [alternateNicknamesString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\tself.config.alternateNicknames = [alternateNicknames arrayByRemovingEmptyValuesAndUniquing];\n\n\t/* Messages */\n\tself.config.sleepModeLeavingComment\t= self.sleepModeQuitMessageTextField.value;\n\tself.config.normalLeavingComment = self.normalLeavingCommentTextField.value;\n\n\t/* Encoding */\n\tNSStringEncoding primaryEncoding = [self.encodingList unsignedIntegerForKey:self.primaryEncodingButton.title];\n\n\tself.config.primaryEncoding\t= primaryEncoding;\n\n\tNSStringEncoding fallbackEncoding = [self.encodingList unsignedIntegerForKey:self.fallbackEncodingButton.title];\n\n\tself.config.fallbackEncoding = fallbackEncoding;\n\n\t/* Proxy Server */\n\tself.config.proxyType = self.proxyTypeButton.selectedTag;\n\n\tself.config.proxyAddress = self.proxyAddressTextField.lowercaseValue;\n\tself.config.proxyPort = self.proxyPortTextField.integerValue;\n\tself.config.proxyUsername = self.proxyUsernameTextField.trimmedFirstTokenStringValue;\n\tself.config.proxyPassword = self.proxyPasswordTextField.trimmedStringValue;\n\n\t/* Connect Commands */\n\tNSString *connectCommandsString = self.connectCommandsField.string;\n\n\tNSArray *connectCommands = [connectCommandsString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];\n\n\tself.config.loginCommands = [connectCommands arrayByRemovingEmptyValues:YES trimming:YES uniquing:NO];\n\n\tself.config.setInvisibleModeOnConnect = (self.setInvisibleModeOnConnectCheck.state == NSControlStateValueOn);\n\n\t/* Flood Control */\n\tself.config.floodControlMaximumMessages = self.floodControlMessageCountSlider.integerValue;\n\tself.config.floodControlDelayTimerInterval = self.floodControlDelayTimerSlider.integerValue;\n\n\t/* Mutable stores. */\n\tself.config.channelList = self.channelListArrayController.arrangedObjects;\n\tself.config.highlightList = self.highlightListArrayController.arrangedObjects;\n\tself.config.ignoreList = self.addressBookArrayController.arrangedObjects;\n\tself.config.serverList = self.serverListArrayController.arrangedObjects;\n}\n\n- (void)restorePreviousValuesForPrimaryServer\n{\n\tIRCServer *previousServer = self.previousPrimaryServer;\n\n\tif (previousServer == nil) {\n\t\treturn;\n\t}\n\n\tself.populatingPrimaryServer = YES;\n\n\tself.serverPortTextField.integerValue = previousServer.serverPort;\n\n\tself.prefersSecuredConnectionCheck.state = previousServer.prefersSecuredConnection;\n\n\tself.previousPrimaryServer = nil;\n\n\tself.populatingPrimaryServer = NO;\n}\n\n- (void)saveCurrentValuesForPrimaryServer\n{\n\t/* Do not change the previous primary server between predefined servers. */\n\tif (self.previousPrimaryServer != nil) {\n\t\treturn;\n\t}\n\n\tIRCServer *server = self.serverList.firstObject;\n\n\tif (server) {\n\t\tself.previousPrimaryServer = server;\n\n\t\treturn;\n\t}\n\n\tIRCServerMutable *serverMutable = [IRCServerMutable new];\n\n\tserverMutable.serverPort = self.serverPortTextField.integerValue;\n\n\tserverMutable.prefersSecuredConnection = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);\n\n\tself.previousPrimaryServer = serverMutable;\n}\n\n- (void)populateDefaultsForPreconfiguredNetwork\n{\n\tif (self.populatingPrimaryServer) {\n\t\treturn;\n\t}\n\n\tNSString *serverAddress = self.serverAddressComboBox.value;\n\n\tif ([serverAddress isEqualToString:self.lastServerAddressValue]) {\n\t\treturn;\n\t}\n\n\tself.lastServerAddressValue = serverAddress;\n\n\tIRCNetwork *network = [self.networkList networkNamed:serverAddress];\n\n\tif (network == nil) {\n\t\tnetwork = [self.networkList networkWithServerAddress:serverAddress];\n\t}\n\n\tif (network == nil) {\n\t\t[self restorePreviousValuesForPrimaryServer];\n\n\t\treturn;\n\t}\n\n\tself.populatingPrimaryServer = YES;\n\n\t/* The predefined list in the combo box is only the network name.\n\t IRCNetwork is also capable of matching known server addresses.\n\t If we have a known network but it's not a predefined value,\n\t then it very might be a server address. */\n\t/* Let's replace the given input that matches a network with the\n\t network name itself. */\n\tif (self.serverAddressComboBox.valueIsPredefined == NO) {\n\t\tNSString *networkName = network.networkName;\n\n\t\tself.serverAddressComboBox.stringValue = networkName;\n\n\t\tself.lastServerAddressValue = networkName;\n\t}\n\n\t/* Populate other defaults */\n\t[self saveCurrentValuesForPrimaryServer];\n\n\tself.serverPortTextField.integerValue = network.serverPort;\n\n\tself.prefersSecuredConnectionCheck.state = (network.prefersSecuredConnection == NSControlStateValueOn);\n\n\tself.populatingPrimaryServer = NO;\n}\n\n- (void)updateChannelListPage\n{\n\tNSInteger selectedRow = self.channelListTable.selectedRow;\n\n\tself.deleteChannelButton.enabled = (selectedRow >= 0);\n\tself.editChannelButton.enabled = (selectedRow >= 0);\n}\n\n- (void)clearChannelListPredicate\n{\n\tself.channelListArrayController.filterPredicate = nil;\n}\n\n- (void)setChannelListPredicate\n{\n\tself.channelListArrayController.filterPredicate =\n\t[NSPredicate predicateWithFormat:@\"type == 0\"]; // Is channel type\n}\n\n- (void)updateAddressBookPage\n{\n\tNSInteger selectedRow = self.addressBookTable.selectedRow;\n\n\tself.deleteAddressBookEntryButton.enabled = (selectedRow >= 0);\n\tself.editAddressBookEntryButton.enabled = (selectedRow >= 0);\n}\n\n- (void)updateHighlightsPage\n{\n\tNSInteger selectedRow = self.highlightsTable.selectedRow;\n\n\tself.deleteHighlightButton.enabled = (selectedRow >= 0);\n\tself.editHighlightButton.enabled = (selectedRow >= 0);\n}\n\n- (void)useSSLCheckChanged:(id)sender\n{\n\tNSInteger serverPort = self.serverPortTextField.integerValue;\n\n\tBOOL useSSL = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);\n\n\tif (useSSL) {\n\t\tif (serverPort == 6667) {\n\t\t\tself.serverPortTextField.stringValue = TXLocalizationNotNeeded(@\"6697\");\n\t\t}\n\t} else {\n\t\tif (serverPort == 6697) {\n\t\t\tself.serverPortTextField.stringValue = TXLocalizationNotNeeded(@\"6667\");\n\t\t}\n\t}\n\n\t[self rebuildMutableServerEndpointListIfNeeded:sender];\n}\n\n- (void)updateIdentityPage\n{\n\tself.hideAutojoinDelayedWarningsCheck.hidden =\n\t(self.autojoinWaitsForNickServCheck.state == NSControlStateValueOff);\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (NSArray<IRCAddressBookEntry *> *)addressBookList\n{\n\treturn self.addressBookArrayController.arrangedObjects;\n}\n\n- (NSArray<IRCChannelConfig *> *)channelList\n{\n\treturn self.channelListArrayController.arrangedObjects;\n}\n\n- (NSArray<IRCHighlightMatchCondition *> *)highlightList\n{\n\treturn self.highlightListArrayController.arrangedObjects;\n}\n\n- (NSArray<IRCServer *> *)serverList\n{\n\treturn self.serverListArrayController.arrangedObjects;\n}\n\n#pragma mark -\n#pragma mark Delegates\n\n- (void)controlTextDidChange:(NSNotification *)notification\n{\n\tNSControl *sender = notification.object;\n\n\tif (sender == self.serverPasswordTextField) {\n\t\t[self rebuildMutableServerEndpointListIfNeeded:sender];\n\t}\n}\n\n- (void)validatedTextFieldTextDidChange:(id)sender\n{\n\tif (sender == self.serverAddressComboBox) {\n\t\t[self populateDefaultsForPreconfiguredNetwork];\n\n\t\t[self rebuildMutableServerEndpointListIfNeeded:sender];\n\t} else if (sender == self.serverPortTextField) {\n\t\t[self rebuildMutableServerEndpointListIfNeeded:sender];\n\t}\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)autojoinWaitsForNickServChanged:(id)sender\n{\n\t[self updateIdentityPage];\n\n\tif (self.autojoinWaitsForNickServCheck.state != NSControlStateValueOn) {\n\t\treturn;\n\t}\n\n\tif (self.nicknamePasswordTextField.stringValue.length > 0 ||\n\t\tself.clientCertificateResetCertificateButton.enabled)\n\t{\n\t\treturn;\n\t}\n\t\n\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TDCServerPropertiesSheet[26u-j8]\")\n\t\t\t\t\t\t\t  title:TXTLS(@\"TDCServerPropertiesSheet[94r-eq]\")\n\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\talternateButton:nil];\n}\n\n- (void)preferredCipherSuitesChanged:(id)sender\n{\n\tNSInteger cipherSuites = self.preferredCipherSuitesButton.selectedTag;\n\n\tself.viewListOfPreferredCipherSuitesButton.enabled =\n\t(cipherSuites != RCMCipherSuiteCollectionNone);\n}\n\n- (void)preferredCipherSuitesViewList:(id)sender\n{\n\tNSInteger cipherSuites = self.preferredCipherSuitesButton.selectedTag;\n\n\tNSArray *cipherSuitesDescriptions = [RCMSecureTransport descriptionsForCipherListCollection:cipherSuites withProtocol:YES];\n\n\tNSString *cipherSuitesDescription = [cipherSuitesDescriptions componentsJoinedByString:@\"\\n\"];\n\n\tNSString *cipherSuitesTitle = self.preferredCipherSuitesButton.titleOfSelectedItem;\n\n\t[TDCAlert alertSheetWithWindow:self.sheet\n\t\t\t\t\t\t\t  body:TXTLS(@\"TDCServerPropertiesSheet[k50-8n]\", cipherSuitesDescription)\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCServerPropertiesSheet[yko-5g]\", cipherSuitesTitle)\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil];\n}\n\n- (void)proxyTypeChanged:(id)sender\n{\n\tNSInteger proxyType = self.proxyTypeButton.selectedTag;\n\n\tBOOL isSystemSocksProxyEnabled = (proxyType == IRCConnectionProxyTypeAutomatic);\n\tBOOL isTorBrowserProxyEnabled = (proxyType == IRCConnectionProxyTypeTor);\n\n\tBOOL supportsAuthentication = (proxyType == IRCConnectionProxyTypeSocks5);\n\n\tBOOL httpsEnabled = (proxyType == IRCConnectionProxyTypeHTTP || proxyType == IRCConnectionProxyTypeHTTPS);\n\tBOOL socksEnabled = (proxyType == IRCConnectionProxyTypeSocks4 || proxyType == IRCConnectionProxyTypeSocks5);\n\n\tBOOL enabled = (httpsEnabled || socksEnabled);\n\n\tself.contentViewProxyServerInputView.hidden = (httpsEnabled == NO && socksEnabled == NO);\n\tself.contentViewProxyServerTorBrowserView.hidden = (isTorBrowserProxyEnabled == NO);\n\tself.contentViewProxyServerSystemSocksView.hidden = (isSystemSocksProxyEnabled == NO);\n\n\tself.proxyAddressTextField.enabled = enabled;\n\tself.proxyPortTextField.enabled = enabled;\n\n\tself.proxyUsernameTextField.enabled = (socksEnabled && supportsAuthentication);\n\tself.proxyPasswordTextField.enabled = (socksEnabled && supportsAuthentication);\n\n\t[self.proxyAddressTextField performValidation];\n\t[self.proxyPortTextField performValidation];\n}\n\n- (void)openProxySettingsInSystemPreferences:(id)sender\n{\n\t[TDCPreferencesController openProxySettingsInSystemPreferences];\n}\n\n- (void)toggleAdvancedEncodings:(id)sender\n{\n\tNSString *primaryEncoding = self.primaryEncodingButton.titleOfSelectedItem;\n\n\tNSString *fallbackEncoding = self.fallbackEncodingButton.titleOfSelectedItem;\n\n\t[self populateEncodings];\n\n\tNSMenuItem *primaryEncodingItem = nil;\n\n\tif (primaryEncoding) {\n\t\tprimaryEncodingItem = [self.primaryEncodingButton itemWithTitle:primaryEncoding];\n\t}\n\n\tif (primaryEncodingItem == nil) {\n\t\tprimaryEncoding = [NSString localizedNameOfStringEncoding:TXDefaultPrimaryStringEncoding];\n\t}\n\n\tNSMenuItem *fallbackEncodingItem = nil;\n\n\tif (fallbackEncoding) {\n\t\tfallbackEncodingItem = [self.fallbackEncodingButton itemWithTitle:fallbackEncoding];\n\t}\n\n\tif (fallbackEncodingItem == nil) {\n\t\tfallbackEncoding = [NSString localizedNameOfStringEncoding:TXDefaultFallbackStringEncoding];\n\t}\n\n\t[self.primaryEncodingButton selectItemWithTitle:primaryEncoding];\n\n\t[self.fallbackEncodingButton selectItemWithTitle:fallbackEncoding];\n}\n\n- (void)preferredInternetProtocolChanged:(id)sender\n{\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t/* Changing the property triggers a deprecation log to console\n\t which is just unnecessary output when each time we change it. */\n\tif (self.config.connectionPrefersIPv4) {\n\t\tself.config.connectionPrefersIPv4 = NO;\n\t}\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\tself.config.addressType = [sender tag];\n}\n\n#pragma mark -\n#pragma mark SSL Certificate\n\n- (void)onClientCertificateFingerprintSHA512CopyRequested:(id)sender\n{\n    NSString *fingerprint = self.clientCertificateSHA512FingerprintField.stringValue;\n\n    NSString *command = [NSString stringWithFormat:@\"/msg NickServ cert add %@\", fingerprint];\n\n    RZPasteboard().stringContent = command;\n}\n\n- (void)onClientCertificateFingerprintSHA2CopyRequested:(id)sender\n{\n\tNSString *fingerprint = self.clientCertificateSHA2FingerprintField.stringValue;\n\n\tNSString *command = [NSString stringWithFormat:@\"/msg NickServ cert add %@\", fingerprint];\n\n\tRZPasteboard().stringContent = command;\n}\n\n- (void)onClientCertificateFingerprintSHA1CopyRequested:(id)sender\n{\n\tNSString *fingerprint = self.clientCertificateSHA1FingerprintField.stringValue;\n\n\tNSString *command = [NSString stringWithFormat:@\"/msg NickServ cert add %@\", fingerprint];\n\n\tRZPasteboard().stringContent = command;\n}\n\n- (void)onClientCertificateFingerprintMD5CopyRequested:(id)sender\n{\n\tNSString *fingerprint = self.clientCertificateMD5FingerprintField.stringValue;\n\n\tNSString *command = [NSString stringWithFormat:@\"/msg NickServ cert add %@\", fingerprint];\n\n\tRZPasteboard().stringContent = command;\n}\n\n- (void)readClientCertificateCommonName:(NSString **)commonNameOut\n\t\t\t\t\t  sha512Fingerprint:(NSString **)sha512FingerprintOut\n\t\t\t\t\t\tsha2Fingerprint:(NSString **)sha2FingerprintOut\n\t\t\t\t\t\tsha1Fingerprint:(NSString **)sha1FingerprintOut\n\t\t\t\t\t\t md5Fingerprint:(NSString **)md5FingerprintOut\n{\n\tNSData *certificateDataIn = self.config.identityClientSideCertificate;\n\n\tif (certificateDataIn == nil) {\n\t\treturn;\n\t}\n\n\t/* ====================================== */\n\n\tSecKeychainItemRef certificateRef;\n\n\tCFDataRef certificateDataInRef = (__bridge CFDataRef)certificateDataIn;\n\n\tOSStatus status = SecKeychainItemCopyFromPersistentReference(certificateDataInRef, &certificateRef);\n\n\tif (status != noErr) {\n\t\treturn;\n\t}\n\n\t/* ====================================== */\n\n\tCFStringRef commonNameRef;\n\n\tstatus = SecCertificateCopyCommonName((SecCertificateRef)certificateRef, &commonNameRef);\n\n\tif (status != noErr) {\n\t\tCFRelease(certificateRef);\n\n\t\treturn;\n\t}\n\n\t*commonNameOut = (__bridge NSString *)(commonNameRef);\n\n\tCFRelease(commonNameRef);\n\n\t/* ====================================== */\n\n\tCFDataRef certificateDataRef = SecCertificateCopyData((SecCertificateRef)certificateRef);\n\n\tif (certificateDataRef) {\n\t\tNSData *certificateData = (__bridge NSData *)certificateDataRef;\n\n\t\t*sha512FingerprintOut = certificateData.sha512;\n\t\t*sha2FingerprintOut = certificateData.sha256;\n\t\t*sha1FingerprintOut = certificateData.sha1;\n\t\t*md5FingerprintOut = certificateData.md5;\n\n\t\tCFRelease(certificateDataRef);\n\t}\n\n\t/* ====================================== */\n\n\tCFRelease(certificateRef);\n}\n\n- (void)saveClientCertificateWithIdentity:(SecIdentityRef)identityInRef\n{\n\tif (identityInRef == NULL) {\n\t\treturn;\n\t}\n\n\t/* ====================================== */\n\n\tSecCertificateRef certificateRef;\n\n\tOSStatus status = SecIdentityCopyCertificate(identityInRef, &certificateRef);\n\n\tif (status != noErr) {\n\t\tLogToConsoleError(\"Operation Failed (2): %{public}i\", status);\n\n\t\treturn;\n\t}\n\n\t/* ====================================== */\n\n\tCFDataRef certificateDataRef;\n\n\tstatus = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)certificateRef, &certificateDataRef);\n\n\tif (status != noErr) {\n\t\tCFRelease(certificateRef);\n\n\t\tLogToConsoleError(\"Operation Failed (3): %{public}i\", status);\n\n\t\treturn;\n\t}\n\n\t/* ====================================== */\n\n\tself.config.identityClientSideCertificate = (__bridge NSData *)certificateDataRef;\n\n\tif (self.prefersSecuredConnectionCheck.state == NSControlStateValueOff) {\n\t\tself.prefersSecuredConnectionCheck.state = NSControlStateValueOn;\n\n\t\t[self useSSLCheckChanged:nil];\n\t}\n\n\t/* ====================================== */\n\n\tCFRelease(certificateRef);\n\tCFRelease(certificateDataRef);\n}\n\n- (void)updateClientCertificatePage\n{\n\tNSString *commonName = nil;\n\n\tNSString *sha512Fingerprint = nil;\n\tNSString *sha2Fingerprint = nil;\n\tNSString *sha1Fingerprint = nil;\n\tNSString *md5Fingerprint = nil;\n\n\t[self readClientCertificateCommonName:&commonName\n\t\t\t\t\t\tsha512Fingerprint:&sha512Fingerprint\n\t\t\t\t\t\t  sha2Fingerprint:&sha2Fingerprint\n\t\t\t\t\t\t  sha1Fingerprint:&sha1Fingerprint\n\t\t\t\t\t\t   md5Fingerprint:&md5Fingerprint];\n\n\tBOOL hasNoCertificate = (commonName.length == 0);\n\n\tif (hasNoCertificate) {\n\t\tself.clientCertificateCommonNameField.stringValue = TXTLS(@\"TDCServerPropertiesSheet[6xz-ec]\");\n\t\t\n\t\tself.clientCertificateSHA512FingerprintField.stringValue = TXTLS(@\"TDCServerPropertiesSheet[6xz-ec]\");\n\t\tself.clientCertificateSHA2FingerprintField.stringValue = TXTLS(@\"TDCServerPropertiesSheet[6xz-ec]\");\n\t\tself.clientCertificateSHA1FingerprintField.stringValue = TXTLS(@\"TDCServerPropertiesSheet[6xz-ec]\");\n\t\tself.clientCertificateMD5FingerprintField.stringValue = TXTLS(@\"TDCServerPropertiesSheet[6xz-ec]\");\n\t} else {\n\t\tself.clientCertificateCommonNameField.stringValue = commonName;\n\n\t\tself.clientCertificateSHA512FingerprintField.stringValue = sha512Fingerprint.uppercaseString;\n\t\tself.clientCertificateSHA2FingerprintField.stringValue = sha2Fingerprint.uppercaseString;\n\t\tself.clientCertificateSHA1FingerprintField.stringValue = sha1Fingerprint.uppercaseString;\n\t\tself.clientCertificateMD5FingerprintField.stringValue = md5Fingerprint.uppercaseString;\n\t}\n\n\tself.clientCertificateResetCertificateButton.enabled = (hasNoCertificate == NO);\n\n\tself.clientCertificateSHA512FingerprintCopyButton.enabled = (hasNoCertificate == NO);\n\tself.clientCertificateSHA2FingerprintCopyButton.enabled = (hasNoCertificate == NO);\n\tself.clientCertificateSHA1FingerprintCopyButton.enabled = (hasNoCertificate == NO);\n\tself.clientCertificateMD5FingerprintCopyButton.enabled = (hasNoCertificate == NO);\n}\n\n- (void)onClientCertificateResetRequested:(id)sender\n{\n\tself.config.identityClientSideCertificate = nil;\n\n\t[self updateClientCertificatePage];\n}\n\n- (void)onClientCertificateChangeRequested:(id)sender\n{\n\tCFArrayRef identities = NULL;\n\n\tNSDictionary *queryFlags = @{\n\t\t(id)kSecClass\t\t: (id)kSecClassIdentity,\n\t\t(id)kSecMatchLimit\t: (id)kSecMatchLimitAll,\n\t\t(id)kSecReturnRef\t: (id)kCFBooleanTrue\n\t};\n\n\tOSStatus queryStatus = SecItemCopyMatching((__bridge CFDictionaryRef)queryFlags, (CFTypeRef *)&identities);\n\n\tif (queryStatus != noErr) {\n\t\tLogToConsoleError(\"Operation Failed (1): %{public}i\", queryStatus);\n\t}\n\n\tif (identities == NULL || CFArrayGetCount(identities) == 0) {\n\t\t[TDCAlert alertWithMessage:TXTLS(@\"TDCServerPropertiesSheet[489-hG]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"TDCServerPropertiesSheet[pmk-os]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:TXTLS(@\"TDCServerPropertiesSheet[3ju-lo]\")\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\tif (buttonClicked == TDCAlertResponseOther) {\n\t\t\t\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Using-CertFP.kb\" inBackground:NO];\n\t\t\t}\n\t\t}];\n\n\t\treturn;\n\t}\n\n\tSFChooseIdentityPanel *panel = [SFChooseIdentityPanel sharedChooseIdentityPanel];\n\n\tself.clientCertificateSelectCertificatePanel = panel;\n\n\t[panel setInformativeText:TXTLS(@\"TDCServerPropertiesSheet[mi4-fd]\")];\n\n\t[panel setAlternateButtonTitle:TXTLS(@\"Prompts[qso-2g]\")];\n\n\tNSInteger panelResponse =\n\t[panel runModalForIdentities:(__bridge NSArray *)(identities)\n\t\t\t\t\t\t message:TXTLS(@\"TDCServerPropertiesSheet[6wq-i4]\")];\n\n\tCFRelease(identities);\n\n\tif (panelResponse == NSModalResponseOK) {\n\t\tSecIdentityRef identity = [panel identity];\n\n\t\t[self saveClientCertificateWithIdentity:identity];\n\n\t\t[self updateClientCertificatePage];\n\t}\n\n\tself.clientCertificateSelectCertificatePanel = nil;\n}\n\n#pragma mark -\n#pragma mark Redundancy\n\n- (void)editSeverEndpoints:(id)sender\n{\n\tTDCServerEndpointListSheet *sheet = [[TDCServerEndpointListSheet alloc] initWithWindow:self.sheet];\n\n\tsheet.delegate = self;\n\n\t[sheet startWithServerList:self.serverList];\n\n\tself.serverEndpointSheet = sheet;\n}\n\n- (void)serverEndpointListSheet:(TDCServerEndpointListSheet *)ender onOk:(NSArray<IRCServer *> *)serverList\n{\n\t[self.serverListArrayController removeAllArrangedObjects];\n\n\t[self.serverListArrayController addObjects:serverList];\n\n\t[self loadPrimaryServerEndpoint];\n}\n\n- (void)serverEndpointListSheetWillClose:(TDCServerEndpointListSheet *)sender\n{\n\tself.serverEndpointSheet = nil;\n}\n\n- (void)rebuildMutableServerEndpointList:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tif (self.populatingPrimaryServer) {\n\t\treturn;\n\t}\n\n\tIRCServer *server = self.serverList.firstObject;\n\n\tIRCServerMutable *serverMutable = nil;\n\n\tif (server == nil) {\n\t\tserverMutable = [IRCServerMutable new];\n\t} else {\n\t\tserverMutable = [server mutableCopy];\n\t}\n\n\t{\n\t\tNSString *serverAddress = self.serverAddressComboBox.value;\n\n\t\tIRCNetwork *serverAddressNetwork = [self.networkList networkNamed:serverAddress];\n\n\t\tif (serverAddressNetwork) {\n\t\t\tserverMutable.serverAddress = serverAddressNetwork.serverAddress;\n\t\t} else {\n\t\t\tserverMutable.serverAddress = serverAddress.lowercaseString;\n\t\t}\n\t}\n\n\tserverMutable.serverPort = self.serverPortTextField.integerValue;\n\n\tserverMutable.prefersSecuredConnection = (self.prefersSecuredConnectionCheck.state == NSControlStateValueOn);\n\n\tserverMutable.serverPassword = self.serverPasswordTextField.trimmedStringValue;\n\n\tserver = [serverMutable copy];\n\n\tif (self.serverList.count == 0) {\n\t\t[self.serverListArrayController addObject:server];\n\t} else {\n\t\t[self.serverListArrayController replaceObjectAtArrangedObjectIndex:0 withObject:server];\n\t}\n}\n\n- (void)rebuildMutableServerEndpointListIfNeeded:(id)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\t/* We only want to rebuild the IRCServer at index 0 when the\n\t user changes it. This method is invoked whenever something\n\t changes related to that server. If it was not changed while\n\t the server endpoint sheet was open, then we must update the\n\t mutable server list to include the change. */\n\tif (self.serverEndpointSheet != nil) {\n\t\treturn;\n\t}\n\n\t[self rebuildMutableServerEndpointList:sender];\n}\n\n#pragma mark -\n#pragma mark Highlight Actions\n\n- (void)addHighlight:(id)sender\n{\n\tTDCHighlightEntrySheet *sheet =\n\t[[TDCHighlightEntrySheet alloc] initWithConfig:nil];\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet startWithChannels:self.channelList];\n\n\tself.highlightSheet = sheet;\n}\n\n- (void)editHighlight:(id)sender\n{\n\tNSInteger selectedRow = self.highlightsTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\tIRCHighlightMatchCondition *config = self.highlightList[selectedRow];\n\n\tTDCHighlightEntrySheet *sheet =\n\t[[TDCHighlightEntrySheet alloc] initWithConfig:config];\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet startWithChannels:self.channelList];\n\n\tself.highlightSheet = sheet;\n}\n\n- (void)highlightEntrySheet:(TDCHighlightEntrySheet *)sender onOk:(IRCHighlightMatchCondition *)config\n{\n\tNSUInteger entryIndex =\n\t[self.highlightList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {\n\t\tif ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {\n\t\t\treturn YES;\n\t\t} else {\n\t\t\treturn NO;\n\t\t}\n\t}];\n\n\tif (entryIndex == NSNotFound) {\n\t\t[self.highlightListArrayController addObject:config];\n\t} else {\n\t\t[self.highlightListArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];\n\t}\n}\n\n- (void)highlightEntrySheetWillClose:(TDCHighlightEntrySheet *)sender\n{\n\tself.highlightSheet = nil;\n}\n\n- (void)deleteHighlight:(id)sender\n{\n\tNSInteger selectedRow = self.highlightsTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\t[self.highlightListArrayController removeObjectAtArrangedObjectIndex:selectedRow];\n\n\tNSUInteger listCount = self.highlightList.count;\n\n\tif (listCount > 0) {\n\t\tif (listCount <= selectedRow) {\n\t\t\t[self.highlightsTable selectItemAtIndex:(listCount - 1)];\n\t\t} else {\n\t\t\t[self.highlightsTable selectItemAtIndex:selectedRow];\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Channel Actions\n\n- (void)addChannel:(id)sender\n{\n\tTDCChannelPropertiesSheet *sheet =\n\t[[TDCChannelPropertiesSheet alloc] initWithWindow:self.sheet];\n\n\tsheet.delegate = self;\n\n\t[sheet start];\n\n\tself.channelSheet = sheet;\n}\n\n- (void)editChannel:(id)sender\n{\n\tNSInteger selectedRow = self.channelListTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\tIRCChannelConfig *config = self.channelList[selectedRow];\n\n\tTDCChannelPropertiesSheet *sheet =\n\t[[TDCChannelPropertiesSheet alloc] initWithConfig:config];\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet start];\n\n\tself.channelSheet = sheet;\n}\n\n- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config\n{\n\tNSUInteger entryIndex =\n\t[self.channelList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {\n\t\tif ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {\n\t\t\treturn YES;\n\t\t} else {\n\t\t\treturn NO;\n\t\t}\n\t}];\n\n\t[self clearChannelListPredicate];\n\n\tif (entryIndex == NSNotFound) {\n\t\t[self.channelListArrayController addObject:config];\n\t} else {\n\t\t[self.channelListArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];\n\t}\n\n\t[self setChannelListPredicate];\n}\n\n- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender\n{\n\tself.channelSheet = nil;\n}\n\n- (void)deleteChannel:(id)sender\n{\n\tNSInteger selectedRow = self.channelListTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\t[self clearChannelListPredicate];\n\n\t[self.channelListArrayController removeObjectAtArrangedObjectIndex:selectedRow];\n\n\t[self setChannelListPredicate];\n\n\tNSUInteger listCount = self.channelList.count;\n\n\tif (listCount > 0) {\n\t\tif (listCount <= selectedRow) {\n\t\t\t[self.channelListTable selectItemAtIndex:(listCount - 1)];\n\t\t} else {\n\t\t\t[self.channelListTable selectItemAtIndex:selectedRow];\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Address Book Actions\n\n- (void)showAddAddressBookEntryMenu:(id)sender\n{\n\t[self.addAddressBookEntryMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(0, 0) inView:sender];\n}\n\n- (void)addIgnoreAddressBookEntry\n{\n\t[self addIgnoreAddressBookEntryWithHostmask:nil];\n}\n\n- (void)addIgnoreAddressBookEntryWithHostmask:(nullable NSString *)hostmask\n{\n\tTDCAddressBookSheet *sheet = nil;\n\n\tif (hostmask) {\n\t\tIRCAddressBookEntry *config =\n\t\t[IRCAddressBookEntry newIgnoreEntryForHostmask:hostmask];\n\n\t\tsheet = [[TDCAddressBookSheet alloc] initWithConfig:config];\n\t} else {\n\t\tsheet = [[TDCAddressBookSheet alloc] initWithEntryType:IRCAddressBookEntryTypeIgnore];\n\t}\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet start];\n\n\tself.addressBookSheet = sheet;\n}\n\n- (void)addUserTrackingAddressBookEntry\n{\n\tTDCAddressBookSheet *sheet =\n\t[[TDCAddressBookSheet alloc] initWithEntryType:IRCAddressBookEntryTypeUserTracking];\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet start];\n\n\tself.addressBookSheet = sheet;\n}\n\n- (void)addAddressBookEntry:(id)sender\n{\n\tif ([sender tag] == 3) {\n\t\t[self addIgnoreAddressBookEntry];\n\t} else if ([sender tag] == 4) {\n\t\t[self addUserTrackingAddressBookEntry];\n\t}\n}\n\n- (void)editAddressBookEntryWithObject:(IRCAddressBookEntry *)entryObject\n{\n\tNSInteger tableIndex = [self.addressBookList indexOfObject:entryObject];\n\n\tif (tableIndex == NSNotFound) {\n\t\treturn;\n\t}\n\n\t[self.addressBookTable selectItemAtIndex:tableIndex];\n\n\t[self editAddressBookEntry:nil];\n}\n\n- (void)editAddressBookEntry:(id)sender\n{\n\tNSInteger selectedRow = self.addressBookTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\tIRCAddressBookEntry *config = self.addressBookList[selectedRow];\n\n\tTDCAddressBookSheet *sheet =\n\t[[TDCAddressBookSheet alloc] initWithConfig:config];\n\n\tsheet.delegate = self;\n\n\tsheet.window = self.sheet;\n\n\t[sheet start];\n\n\tself.addressBookSheet = sheet;\n}\n\n- (void)addressBookSheet:(TDCAddressBookSheet *)sender onOk:(IRCAddressBookEntry *)config\n{\n\tNSUInteger entryIndex =\n\t[self.addressBookList indexOfObjectPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {\n\t\tif ([[object uniqueIdentifier] isEqualToString:config.uniqueIdentifier]) {\n\t\t\treturn YES;\n\t\t} else {\n\t\t\treturn NO;\n\t\t}\n\t}];\n\n\tif (entryIndex == NSNotFound) {\n\t\t[self.addressBookArrayController addObject:config];\n\t} else {\n\t\t[self.addressBookArrayController replaceObjectAtArrangedObjectIndex:entryIndex withObject:config];\n\t}\n}\n\n- (void)addressBookSheetWillClose:(TDCAddressBookSheet *)sender\n{\n\tself.addressBookSheet = nil;\n}\n\n- (void)deleteAddressBookEntry:(id)sender\n{\n\tNSInteger selectedRow = self.addressBookTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\t[self.addressBookArrayController removeObjectAtArrangedObjectIndex:selectedRow];\n\n\tNSUInteger listCount = self.addressBookList.count;\n\n\tif (listCount > 0) {\n\t\tif (listCount <= selectedRow) {\n\t\t\t[self.addressBookTable selectItemAtIndex:(listCount - 1)];\n\t\t} else {\n\t\t\t[self.addressBookTable selectItemAtIndex:selectedRow];\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark NSTableView Delegate\n\n- (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tNSString *columnId = tableColumn.identifier;\n\n\tif (tableView == self.channelListTable)\n\t{\n\t\tIRCChannelConfig *config = self.channelList[row];\n\n\t\tif ([columnId isEqualToString:@\"name\"])\n\t\t{\n\t\t\treturn config.channelName;\n\t\t}\n\t\telse if ([columnId isEqualToString:@\"pass\"])\n\t\t{\n\t\t\tNSString *secretKeyValue = config.secretKey;\n\n\t\t\tif (secretKeyValue) {\n\t\t\t\treturn secretKeyValue;\n\t\t\t}\n\n\t\t\treturn @\"\";\n\t\t}\n\t\telse if ([columnId isEqualToString:@\"join\"])\n\t\t{\n\t\t\treturn @(config.autoJoin);\n\t\t}\n\t}\n\telse if (tableView == self.highlightsTable)\n\t{\n\t\tIRCHighlightMatchCondition *config = self.highlightList[row];\n\n\t\tif ([columnId isEqualToString:@\"keyword\"])\n\t\t{\n\t\t\treturn config.matchKeyword;\n\t\t}\n\t\telse if ([columnId isEqualToString:@\"channel\"])\n\t\t{\n\t\t\tNSString *matchChannelId = config.matchChannelId;\n\n\t\t\tif (matchChannelId) {\n\t\t\t\tfor (IRCChannelConfig *channel in self.channelList) {\n\t\t\t\t\tif ([channel.uniqueIdentifier isEqualToString:matchChannelId] == NO) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn channel.channelName;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[61f-6b]\");\n\t\t}\n\t\telse if ([columnId isEqualToString:@\"type\"])\n\t\t{\n\t\t\tif (config.matchIsExcluded) {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[qcc-b4]\");\n\t\t\t} else {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[tet-dk]\");\n\t\t\t}\n\t\t}\n\t}\n\telse if (tableView == self.addressBookTable)\n\t{\n\t\tIRCAddressBookEntry *config = self.addressBookList[row];\n\n\t\tif ([columnId isEqualToString:@\"hostmask\"])\n\t\t{\n\t\t\treturn config.hostmask;\n\t\t}\n\t\telse if ([columnId isEqualToString:@\"type\"])\n\t\t{\n\t\t\tif (config.entryType == IRCAddressBookEntryTypeIgnore) {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[f7o-x4]\");\n\t\t\t} else {\n\t\t\t\treturn TXTLS(@\"TDCServerPropertiesSheet[b0g-0x]\");\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row\n{\n\treturn YES;\n}\n\n- (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tNSString *columnId = tableColumn.identifier;\n\n\tif (tableView == self.channelListTable)\n\t{\n\t\tIRCChannelConfigMutable *config = [self.channelList[row] mutableCopy];\n\n\t\tif ([columnId isEqualToString:@\"join\"]) {\n\t\t\tconfig.autoJoin = [object boolValue];\n\t\t}\n\n\t\t[self.channelListArrayController replaceObjectAtArrangedObjectIndex:row withObject:[config copy]];\n\t}\n}\n\n- (void)tableViewSelectionDidChange:(NSNotification *)aNote\n{\n\tNSTableView *tableView = aNote.object;\n\n\tif (tableView == self.channelListTable) {\n\t\t[self updateChannelListPage];\n\t} else if (tableView == self.highlightsTable) {\n\t\t[self updateHighlightsPage];\n\t} else if (tableView == self.addressBookTable) {\n\t\t[self updateAddressBookPage];\n\t}\n}\n\n- (void)tableViewDoubleClicked:(id)sender\n{\n\tif (sender == self.channelListTable) {\n\t\t[self editChannel:sender];\n\t} else if (sender == self.highlightsTable) {\n\t\t[self editHighlight:sender];\n\t} else if (sender == self.addressBookTable) {\n\t\t[self editAddressBookEntry:sender];\n\t}\n}\n\n- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard\n{\n\tNSData *draggedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];\n\n\t[pasteboard declareTypes:@[_tableDragToken] owner:self];\n\n\t[pasteboard setData:draggedData forType:_tableDragToken];\n\n\treturn YES;\n}\n\n- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation\n{\n\treturn NSDragOperationGeneric;\n}\n\n- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation\n{\n\tNSPasteboard *pasteboard = [info draggingPasteboard];\n\n\tNSData *draggedData = [pasteboard dataForType:_tableDragToken];\n\n\tNSIndexSet *draggedRowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:draggedData];\n\n\tNSUInteger draggedRowIndex = draggedRowIndexes.firstIndex;\n\n\tif (tableView == self.channelListTable) {\n\t\t[self clearChannelListPredicate];\n\n\t\t[self.channelListArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];\n\n\t\t[self setChannelListPredicate];\n\t} else if (tableView == self.highlightsTable) {\n\t\t[self.highlightListArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];\n\t} else if (tableView == self.addressBookTable) {\n\t\t[self.addressBookArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];\n\t}\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tself.addressBookTable.delegate = nil;\n\tself.channelListTable.delegate = nil;\n\tself.highlightsTable.delegate = nil;\n\n\tself.addressBookTable.dataSource = nil;\n\tself.channelListTable.dataSource = nil;\n\tself.highlightsTable.dataSource = nil;\n\n\t[self.addressBookTable unregisterDraggedTypes];\n\t[self.channelListTable unregisterDraggedTypes];\n\t[self.highlightsTable unregisterDraggedTypes];\n\n\t[self.sheet makeFirstResponder:nil];\n\n\tif ([self.delegate respondsToSelector:@selector(serverPropertiesSheetWillClose:)]) {\n\t\t[self.delegate serverPropertiesSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCSheetBase.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCValidatedComboBox.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TDCSheetBase\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super init])) {\n\t\tself.window = window;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)startSheet\n{\n\t[self startSheetWithWindow:self.window];\n}\n\n- (void)startSheetWithWindow:(NSWindow *)window\n{\n\t[window beginSheet:self.sheet\n\t completionHandler:^(NSModalResponse returnCode) {\n\t\t[self sheetDidEndWithReturnCode:returnCode];\n\t}];\n}\n\n- (void)endSheet\n{\n\t[self.window endSheet:self.sheet];\n}\n\n- (void)sheetDidEndWithReturnCode:(NSInteger)returnCode\n{\n\t[self.sheet close];\n}\n\n- (void)ok:(id)sender\n{\n\t[self endSheet];\n}\n\n- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField\n{\n\tNSParameterAssert(textField != nil);\n\n\treturn ([textField showValidationErrorPopover] == NO);\n}\n\n- (BOOL)okOrErrorForComboBox:(TVCValidatedComboBox *)comboBox\n{\n\tNSParameterAssert(comboBox != nil);\n\n\treturn ([comboBox showValidationErrorPopover] == NO);\n}\n\n- (void)cancel:(id)sender\n{\n\t[self endSheet];\n}\n\n- (void)close\n{\n\t[self cancel:nil];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCWelcomeSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"IRCChannelConfig.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCNetworkList.h\"\n#import \"IRCServer.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCBasicTableView.h\"\n#import \"TVCValidatedComboBox.h\"\n#import \"TVCValidatedTextField.h\"\n#import \"TDCWelcomeSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCWelcomeSheet ()\n@property (nonatomic, weak) IBOutlet NSButton *autoConnectCheck;\n@property (nonatomic, weak) IBOutlet NSButton *addChannelButton;\n@property (nonatomic, weak) IBOutlet NSButton *deleteChannelButton;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *nicknameTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedComboBox *serverAddressComboBox;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *channelTable;\n@property (nonatomic, strong) NSMutableArray<NSString *> *channelList;\n@property (nonatomic, strong) IRCNetworkList *networkList;\n\n- (IBAction)onAddChannel:(id)sender;\n- (IBAction)onDeleteChannel:(id)sender;\n@end\n\n@implementation TDCWelcomeSheet\n\n#pragma mark -\n#pragma mark Init.\n\n- (instancetype)initWithWindow:(nullable NSWindow *)window\n{\n\tif ((self = [super initWithWindow:window])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TDCWelcomeSheet\" owner:self topLevelObjects:nil];\n\n\t/* Populate server list combo box */\n\tself.networkList = [IRCNetworkList new];\n\n\tNSArray *listOfNetworks = self.networkList.listOfNetworks;\n\n\tfor (IRCNetwork *network in listOfNetworks) {\n\t\t[self.serverAddressComboBox addItemWithObjectValue:network.networkName];\n\t}\n\n\t/* Nickname */\n\tself.nicknameTextField.textDidChangeCallback = self;\n\n\tself.nicknameTextField.stringValueIsInvalidOnEmpty = YES;\n\tself.nicknameTextField.stringValueIsTrimmed = YES;\n\tself.nicknameTextField.stringValueUsesOnlyFirstToken = YES;\n\n\tself.nicknameTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isHostmaskNickname == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[och-j5]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Server address */\n\tself.serverAddressComboBox.textDidChangeCallback = self;\n\n\tself.serverAddressComboBox.stringValueIsInvalidOnEmpty = YES;\n\tself.serverAddressComboBox.stringValueIsTrimmed = YES;\n\tself.serverAddressComboBox.stringValueUsesOnlyFirstToken = YES;\n\n\tself.serverAddressComboBox.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.isValidInternetAddress == NO) {\n\t\t\treturn TXTLS(@\"CommonErrors[yyx-l3]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* Setup others */\n\tself.channelList = [NSMutableArray new];\n\n\tself.channelTable.textEditingDelegate = self;\n\n\t[self updateDeleteChannelButton];\n\n\tself.nicknameTextField.stringValue = [TPCPreferences defaultNickname];\n}\n\n#pragma mark -\n#pragma mark Controls\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)close\n{\n\t[super cancel:nil];\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\tIRCClientConfigMutable *config = nil;\n\n\tNSString *serverAddress = self.serverAddressComboBox.value;\n\n\tIRCNetwork *serverAddressNetwork = [self.networkList networkNamed:serverAddress];\n\n\tif (serverAddressNetwork == nil) {\n\t\tserverAddressNetwork = [self.networkList networkWithServerAddress:serverAddress];\n\t}\n\n\tif (serverAddressNetwork) {\n\t\tconfig = [IRCClientConfigMutable newConfigWithNetwork:serverAddressNetwork];\n\t} else {\n\t\tserverAddress = serverAddress.lowercaseString;\n\n\t\tconfig = [IRCClientConfigMutable new];\n\n\t\tconfig.connectionName = serverAddress;\n\n\t\tIRCServerMutable *server = [IRCServerMutable new];\n\n\t\tserver.serverAddress = serverAddress;\n\n\t\tconfig.serverList = @[[server copy]];\n\t}\n\n\tconfig.autoConnect = (self.autoConnectCheck.state == NSControlStateValueOn);\n\n\tconfig.nickname = self.nicknameTextField.value;\n\n\tNSMutableArray<IRCChannelConfig *> *channelList = [NSMutableArray array];\n\n\tNSMutableArray<NSString *> *channelsAdded = [NSMutableArray array];\n\n\tfor (NSString *channel in self.channelList) {\n\t\tNSString *channelName = channel.trim;\n\n\t\tif (channelName.length == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ([channelsAdded containsObjectIgnoringCase:channelName] == NO) {\n\t\t\t[channelsAdded addObject:channelName];\n\t\t} else {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (channelName.isChannelName == NO) {\n\t\t\tchannelName = [@\"#\" stringByAppendingString:channelName];\n\t\t}\n\n\t\tIRCChannelConfig *channelConfig = [IRCChannelConfig seedWithName:channelName];\n\n\t\t[channelList addObject:channelConfig];\n\t}\n\n\tconfig.channelList = channelList;\n\n\tif ([self.delegate respondsToSelector:@selector(welcomeSheet:onOk:)]) {\n\t\t[self.delegate welcomeSheet:self onOk:[config copy]];\n\t}\n\n\t[super ok:nil];\n}\n\n- (BOOL)okOrError\n{\n\tif ([self okOrErrorForComboBox:self.serverAddressComboBox] == NO) {\n\t\treturn NO;\n\t}\n\n\tif ([self okOrErrorForTextField:self.nicknameTextField] == NO) {\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n- (void)onAddChannel:(id)sender\n{\n\t[self.channelList addObject:@\"\"];\n\n\t[self.channelTable reloadData];\n\n\tNSInteger rowToEdit = (self.channelList.count - 1);\n\n\t[self.channelTable selectItemAtIndex:rowToEdit];\n\n\t[self.channelTable editColumn:0 row:rowToEdit withEvent:nil select:YES];\n}\n\n- (void)onDeleteChannel:(id)sender\n{\n\tNSInteger selectedRow = self.channelTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\t[self.channelList removeObjectAtIndex:selectedRow];\n\n\t[self.channelTable reloadData];\n\n\tNSInteger channelListCount = self.channelList.count;\n\n\tif (selectedRow > channelListCount) {\n\t\tselectedRow = (channelListCount - 1);\n\t}\n\n\tif (channelListCount >= 0) {\n\t\t[self.channelTable selectItemAtIndex:selectedRow];\n\t}\n\n\t[self updateDeleteChannelButton];\n}\n\n- (void)updateDeleteChannelButton\n{\n\tself.deleteChannelButton.enabled = (self.channelTable.numberOfSelectedRows > 0);\n}\n\n#pragma mark -\n#pragma mark NSTableView Delegate\n\n- (void)textDidEndEditing:(NSNotification *)note\n{\n\tNSInteger editedRow = self.channelTable.editedRow;\n\n\tif (editedRow < 0) {\n\t\treturn;\n\t}\n\n\tNSString *editedString = [note.object textStorage].string;\n\n\tself.channelList[editedRow] = [editedString copy];\n\n\t[self.channelTable reloadData];\n\n\t[self.channelTable selectItemAtIndex:editedRow];\n\n\t[self updateDeleteChannelButton];\n}\n\n- (NSInteger)numberOfRowsInTableView:(NSTableView *)sender\n{\n\treturn self.channelList.count;\n}\n\n- (id)tableView:(NSTableView *)sender objectValueForTableColumn:(NSTableColumn *)column row:(NSInteger)row\n{\n\treturn self.channelList[row];\n}\n\n- (void)tableViewSelectionIsChanging:(NSNotification *)note\n{\n\t[self updateDeleteChannelButton];\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\tself.channelTable.dataSource = nil;\n\tself.channelTable.delegate = nil;\n\n\tif ([self.delegate respondsToSelector:@selector(welcomeSheetWillClose:)]) {\n\t\t[self.delegate welcomeSheetWillClose:self];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Dialogs/TDCWindowBase.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TDCWindowBase\n\n- (void)show\n{\n\t[self.window makeKeyAndOrderFront:nil];\n}\n\n- (void)close\n{\n\t[self.window close];\n}\n\n- (void)ok:(id)sender\n{\n\t[self close];\n}\n\n- (void)cancel:(id)sender\n{\n\t[self close];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/External Libraries/GTMEncodeHTML.h",
    "content": "//\n//  GTMNSString+HTML.h\n//  Dealing with NSStrings that contain HTML\n//\n//  Copyright 2006-2008 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n//  use this file except in compliance with the License.  You may obtain a copy\n//  of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\n//  License for the specific language governing permissions and limitations under\n//  the License.\n//\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n/// Utilities for NSStrings containing HTML\n@interface NSString (GTMNSStringHTMLAdditions)\n\n/// Get a string where internal characters that need escaping for HTML are escaped\n///\n///  For example, '&' become '&amp;'. This will only cover characters from table\n///  A.2.2 of http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters\n///  which is what you want for a unicode encoded webpage. If you have a ascii\n///  or non-encoded webpage, please use stringByEscapingAsciiHTML which will\n///  encode all characters.\n///\n/// For obvious reasons this call is only safe once.\n///\n///  Returns:\n///    Autoreleased NSString\n///\n@property (readonly, copy, nullable) NSString *gtm_stringByEscapingForHTML;\n\n/// Get a string where internal characters that need escaping for HTML are escaped\n///\n///  For example, '&' become '&amp;'\n///  All non-mapped characters (unicode that don't have a &keyword; mapping)\n///  will be converted to the appropriate &#xxx; value. If your webpage is\n///  unicode encoded (UTF16 or UTF8) use stringByEscapingHTML instead as it is\n///  faster, and produces less bloated and more readable HTML (as long as you\n///  are using a unicode compliant HTML reader).\n///\n/// For obvious reasons this call is only safe once.\n///\n///  Returns:\n///    Autoreleased NSString\n///\n@property (readonly, copy) NSString *gtm_stringByEscapingForAsciiHTML;\n\n/// Get a string where internal characters that are escaped for HTML are unescaped\n///\n///  For example, '&amp;' becomes '&'\n///  Handles &#32; and &#x32; cases as well\n///\n///  Returns:\n///    Autoreleased NSString\n///\n@property (readonly, copy) NSString *gtm_stringByUnescapingFromHTML;\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/External Libraries/OELReachability.h",
    "content": "/*\n Copyright (c) 2011, Tony Million.\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE. \n */\n\n#import <Foundation/Foundation.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class OELReachability;\n\ntypedef void (^OELReachabilityNetworkReachableBlock)(OELReachability *reachability);\ntypedef void (^OELReachabilityNetworkUnreachableBlock)(OELReachability *reachability);\n\n@interface OELReachability : NSObject\n@property (nonatomic, copy, nullable) OELReachabilityNetworkReachableBlock reachableBlock;\n@property (nonatomic, copy, nullable) OELReachabilityNetworkUnreachableBlock unreachableBlock;\n\n+ (nullable OELReachability *)reachabilityForInternetConnection;\n\n@property (getter=isReachable, readonly) BOOL reachable;\n\n- (BOOL)startNotifier;\n- (void)stopNotifier;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRC.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Hard limits */\n#define TXMaximumIRCBodyLength\t\t\t\t\t\t510\n#define TXMaximumIRCNicknameLength\t\t\t\t\t50\n#define TXMaximumIRCUsernameLength\t\t\t\t\t40\n\n#define TXMaximumTCPPort\t\t\t\t\t\t\t65535\n\n#define TXMaximumNodesPerModeCommand\t\t\t\t4\n\n#define IRCProtocolDefaultNicknameMaximumLength\t\t\t31\n\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCAddressBook.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, IRCAddressBookEntryType) {\n\tIRCAddressBookEntryTypeIgnore = 0,\n\tIRCAddressBookEntryTypeUserTracking,\n\t\n\t/* Entry type used when multiple instances of IRCAddressBookEntry\n\t are combined into a single object which represents all. */\n\tIRCAddressBookEntryTypeMixed\n};\n\ntypedef NS_ENUM(NSUInteger, IRCAddressBookUserTrackingStatus) {\n\tIRCAddressBookUserTrackingStatusUnknown = 0,\n\tIRCAddressBookUserTrackingStatusSignedOff,\n\tIRCAddressBookUserTrackingStatusSignedOn,\n\tIRCAddressBookUserTrackingStatusAvailable,\n\tIRCAddressBookUserTrackingStatusNotAvailable,\n\tIRCAddressBookUserTrackingStatusAway,\n\tIRCAddressBookUserTrackingStatusNotAway\n};\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCAddressBookEntry : XRPortablePropertyDict\n@property (readonly) IRCAddressBookEntryType entryType;\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly, copy) NSString *hostmask;\n@property (readonly, copy) NSString *hostmaskRegularExpression;\n@property (readonly, copy, nullable) NSString *trackingNickname;\n@property (readonly) BOOL ignoreClientToClientProtocol;\n@property (readonly) BOOL ignoreGeneralEventMessages;\n@property (readonly) BOOL ignoreNoticeMessages;\n@property (readonly) BOOL ignorePrivateMessageHighlights;\n@property (readonly) BOOL ignorePrivateMessages;\n@property (readonly) BOOL ignorePublicMessageHighlights;\n@property (readonly) BOOL ignorePublicMessages;\n@property (readonly) BOOL ignoreFileTransferRequests;\n@property (readonly) BOOL ignoreInlineMedia;\n@property (readonly) BOOL ignoreMessagesContainingMatch;\n@property (readonly) BOOL trackUserActivity;\n\n/* When IRCAddressBookEntryTypeMixed is mixed, this array holds\n a reference to each entry that is mixed into the current object. */\n@property (readonly, copy, nullable) NSArray<IRCAddressBookEntry *> *parentEntries;\n\n+ (instancetype)newIgnoreEntry;\n+ (instancetype)newIgnoreEntryForHostmask:(nullable NSString *)hostmask;\n\n+ (instancetype)newUserTrackingEntry;\n\n- (BOOL)checkMatch:(NSString *)hostmask;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCAddressBookEntryMutable : IRCAddressBookEntry\n@property (nonatomic, assign, readwrite) IRCAddressBookEntryType entryType;\n@property (nonatomic, copy, readwrite) NSString *hostmask;\n@property (nonatomic, assign, readwrite) BOOL ignoreClientToClientProtocol;\n@property (nonatomic, assign, readwrite) BOOL ignoreGeneralEventMessages;\n@property (nonatomic, assign, readwrite) BOOL ignoreNoticeMessages;\n@property (nonatomic, assign, readwrite) BOOL ignorePrivateMessageHighlights;\n@property (nonatomic, assign, readwrite) BOOL ignorePrivateMessages;\n@property (nonatomic, assign, readwrite) BOOL ignorePublicMessageHighlights;\n@property (nonatomic, assign, readwrite) BOOL ignorePublicMessages;\n@property (nonatomic, assign, readwrite) BOOL ignoreFileTransferRequests;\n@property (nonatomic, assign, readwrite) BOOL ignoreInlineMedia;\n@property (nonatomic, assign, readwrite) BOOL trackUserActivity;\n@property (nonatomic, copy, readwrite, nullable) NSArray<IRCAddressBookEntry *> *parentEntries;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCAddressBookUserTracking.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCAddressBook.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\nTEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingStatusChangedNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingAddedTrackedUserNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingRemovedTrackedUserNotification;\nTEXTUAL_EXTERN NSNotificationName const IRCAddressBookUserTrackingRemovedAllTrackedUsersNotification;\n\n@interface IRCAddressBookUserTrackingContainer : NSObject\n@property (readonly, weak) IRCClient *client;\n\n// value is boolean, whether tracked user is online\n@property (readonly, copy) NSDictionary<NSString *, NSNumber *> *trackedUsers;\n\n- (IRCAddressBookUserTrackingStatus)statusOfUser:(NSString *)nickname;\n- (IRCAddressBookUserTrackingStatus)statusOfEntry:(IRCAddressBookEntry *)addressBookEntry;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCChannel.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelConfig.h\"\n#import \"IRCChannelMemberList.h\"\n#import \"IRCTreeItem.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelMode, IRCChannelUser, IRCUser;\n@class TVCLogLine;\n\ntypedef NS_ENUM(NSUInteger, IRCChannelStatus) {\n\tIRCChannelStatusParted = 0,\n\tIRCChannelStatusJoining,\n\tIRCChannelStatusJoined,\n\tIRCChannelStatusTerminated,\n};\n\nTEXTUAL_EXTERN NSNotificationName const IRCChannelConfigurationWasUpdatedNotification;\n\n@interface IRCChannel : IRCTreeItem <IRCChannelMemberListPrototype>\n@property (readonly, copy) IRCChannelConfig *config;\n@property (nonatomic, copy) NSString *name; // -setName: will do nothing if type != IRCChannelTypePrivateMessage\n@property (nonatomic, copy, nullable) NSString *topic;\n@property (nonatomic, assign) BOOL autoJoin;\n@property (readonly) IRCChannelType type;\n@property (getter=isChannel, readonly) BOOL channel;\n@property (getter=isPrivateMessage, readonly) BOOL privateMessage;\n@property (getter=isPrivateMessageForZNCUser, readonly) BOOL privateMessageForZNCUser; // For example: *status, *nickserv, etc.\n@property (getter=isUtility, readonly) BOOL utility; // See IRCChannelTypeUtility in IRCChannelConfig.h\n@property (readonly) IRCChannelStatus status;\n@property (readonly) BOOL errorOnLastJoinAttempt;\n@property (readonly) NSTimeInterval channelJoinTime;\n@property (readonly, copy) NSString *channelTypeString;\n@property (readonly, strong, nullable) IRCChannelMode *modeInfo;\n@property (readonly, strong, nullable) IRCChannelMemberList *memberInfo;\n@property (readonly, copy, nullable) NSString *secretKey;\n@property (readonly, copy, nullable) NSURL *logFilePath;\n@property (readonly) NSUInteger logFileSessionCount; // Number of lines sent to channel log file for session (from connect to disconnect)\n@property (readonly, weak) TVCLogLine *lastLine; // Last line in the channel. There is no guarantee it's visible to the user when accessed.\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@property (readonly) BOOL encryptionStateIsEncrypted;\n#endif\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (void)activate;\n- (void)deactivate;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCChannelConfig.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, IRCChannelType) {\n\tIRCChannelTypeChannel = 0,\n\tIRCChannelTypePrivateMessage,\n\tIRCChannelTypeUtility,\n};\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCChannelConfig : XRPortablePropertyDict\n@property (readonly) BOOL autoJoin;\n@property (readonly) BOOL ignoreGeneralEventMessages;\n@property (readonly) BOOL ignoreHighlights;\n@property (readonly) BOOL inlineMediaDisabled;\n@property (readonly) BOOL inlineMediaEnabled;\n@property (readonly) BOOL pushNotifications;\n@property (readonly) BOOL showTreeBadgeCount;\n@property (readonly) IRCChannelType type;\n@property (readonly, copy) NSString *channelName;\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly, copy, nullable) NSString *label;\n@property (readonly, copy, nullable) NSString *defaultModes;\n@property (readonly, copy, nullable) NSString *defaultTopic;\n@property (readonly, copy, nullable) NSString *secretKey;\n@property (readonly, copy, nullable) NSString *secretKeyFromKeychain;\n\n+ (IRCChannelConfig *)seedWithName:(NSString *)channelName;\n\n/* Notifications */\n- (nullable NSString *)soundForEvent:(TXNotificationType)event;\n\n// These methods return an integer because there are more than\n// two possible values. When there is no channel defined value\n// for the given event, NSControlStateValueMixed is returned \n// which indicates that the global value should be used.\n// NSControlStateValueOn and NSControlStateValueOff\n// are returned when a channel defined value is available.\n- (NSControlStateValue)notificationEnabledForEvent:(TXNotificationType)event;\n- (NSControlStateValue)disabledWhileAwayForEvent:(TXNotificationType)event;\n- (NSControlStateValue)bounceDockIconForEvent:(TXNotificationType)event;\n- (NSControlStateValue)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event;\n- (NSControlStateValue)speakEvent:(TXNotificationType)event;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCChannelConfigMutable : IRCChannelConfig\n@property (nonatomic, assign, readwrite) IRCChannelType type;\n@property (nonatomic, assign, readwrite) BOOL autoJoin;\n@property (nonatomic, assign, readwrite) BOOL ignoreGeneralEventMessages;\n@property (nonatomic, assign, readwrite) BOOL ignoreHighlights;\n@property (nonatomic, assign, readwrite) BOOL inlineMediaDisabled;\n@property (nonatomic, assign, readwrite) BOOL inlineMediaEnabled;\n@property (nonatomic, assign, readwrite) BOOL pushNotifications;\n@property (nonatomic, assign, readwrite) BOOL showTreeBadgeCount;\n@property (nonatomic, copy, readwrite) NSString *channelName;\n@property (nonatomic, copy, readwrite, nullable) NSString *label;\n@property (nonatomic, copy, readwrite, nullable) NSString *defaultModes;\n@property (nonatomic, copy, readwrite, nullable) NSString *defaultTopic;\n@property (nonatomic, copy, readwrite, nullable) NSString *secretKey;\n\n- (void)setSound:(nullable NSString *)value forEvent:(TXNotificationType)event;\n\n// NSControlStateValueOn = YES\n// NSControlStateValueOff = NO\n// NSControlStateValueMixed = Reset, use default\n- (void)setNotificationEnabled:(NSControlStateValue)value forEvent:(TXNotificationType)event;\n- (void)setDisabledWhileAway:(NSControlStateValue)value forEvent:(TXNotificationType)event;\n- (void)setBounceDockIcon:(NSControlStateValue)value forEvent:(TXNotificationType)event;\n- (void)setBounceDockIconRepeatedly:(NSControlStateValue)value forEvent:(TXNotificationType)event;\n- (void)setEventIsSpoken:(NSControlStateValue)value forEvent:(TXNotificationType)event;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCChannelMemberList.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelUser, IRCUser;\n\n#pragma mark -\n#pragma mark Prototype\n\n/* IRCChannel proxies many methods declared by IRCChannelMemberList\n for backwards compatibility and convenience through the use of\n IRCChannelMemberListPrototype protocol. It's atypical to access\n IRCChannelMemberList directly. The declaration for it is only\n public to allow KVO binding to -memberList and -numberOfMembers. */\n\n/* In context of IRCChannel proxied methods:\n\n An instance of IRCChannel will only have a member list when in\n active state. This includes regular channels and private messages.\n Utility channels will never have a member list.\n\n All proxied methods will do nothing when there is no member list.\n */\n@protocol IRCChannelMemberListPrototype <NSObject>\n/* Member changes (adding, removing, modifying) are done so asynchronously.\n This means that changes wont be immediately reflected by -memberList. */\n/* It is safe to call -memberExists: and -findMember: immediately after\n changing a member because those methods do not require the member to\n be present in the member list to produce a result. */\n- (void)addUser:(IRCUser *)user;\n\n- (void)addMember:(IRCChannelUser *)member;\n\n- (void)removeMember:(IRCChannelUser *)member;\n- (void)removeMemberWithNickname:(NSString *)nickname;\n\n- (BOOL)memberExists:(NSString *)nickname;\n\n- (nullable IRCChannelUser *)findMember:(NSString *)nickname;\n\n/* -memberList and -numberOfMembers are KVO compliant when\n bound directly to an instance of IRCChannelMemberList.\n The methods that IRCChannel proxy will not post KVO changes. */\n@property (readonly) NSUInteger numberOfMembers;\n\n@property (readonly, copy, nullable) NSArray<IRCChannelUser *> *memberList; // Automatically sorted by channel rank\n\n/* Resort the entire member list using all known conditions. */\n/* This can be an expensive task for large channels. */\n- (void)sortMembers;\n@end\n\n#pragma mark -\n#pragma mark Interface\n\n@interface IRCChannelMemberList : NSObject <IRCChannelMemberListPrototype>\n- (instancetype)init NS_UNAVAILABLE;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCChannelMode.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelModeContainer, IRCModeInfo;\n\n@interface IRCChannelMode : NSObject\n- (BOOL)modeIsDefined:(NSString *)modeSymbol;\n\n- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol;\n\n@property (readonly, copy) IRCChannelModeContainer *modes;\n\n@property (readonly, copy) NSString *string;\n@property (readonly, copy) NSString *stringWithMaskedPassword;\n\n- (NSString *)getChangeCommand:(IRCChannelModeContainer *)modes;\n\n- (instancetype)init NS_UNAVAILABLE;\n@end\n\n#pragma mark -\n\n@interface IRCChannelModeContainer : NSObject <NSCopying>\n@property (readonly, copy) NSDictionary<NSString *, IRCModeInfo *> *modes;\n\n- (BOOL)modeIsDefined:(NSString *)modeSymbol;\n\n- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol;\n\n- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet;\n- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCChannelUser.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCUser, IRCUserMutable;\n\ntypedef NS_OPTIONS(NSUInteger, IRCUserRank) {\n\tIRCUserRankNone\t\t\t\t= 1 << 0,\t// nothing\n\tIRCUserRankIRCopByMode\t\t= 1 << 1,\t// +y/+Y\n\tIRCUserRankChannelOwner\t\t= 1 << 2,\t// +q\n\tIRCUserRankSuperOperator\t= 1 << 3,\t// +a\n\tIRCUserRankNormalOperator\t= 1 << 4,\t// +o\n\tIRCUserRankHalfOperator\t\t= 1 << 5,\t// +h\n\tIRCUserRankVoiced\t\t\t= 1 << 6\t// +v\n};\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCChannelUser : XRPortablePropertyObject\n@property (readonly, strong) IRCUser *user;\n\n@property (getter=isOp, readonly) BOOL op;\n@property (getter=isHalfOp, readonly) BOOL halfOp;\n\n// -rank(s) returns IRCUserRankIRCopByMode if the +Y/+y modes defined\n// by InspIRCd-2.0 for IRC operators are in use by this user. It does not\n// return this if the user is an IRC operator, but lacks these modes.\n// Use -isCop for the status of the user regardless of these modes.\n@property (readonly) IRCUserRank rank; // Highest rank user has\n@property (readonly) IRCUserRank ranks; // All ranks user as a bitmask\n\n@property (readonly, copy) NSString *modes; // List of all user modes, ranked highest to lowest\n@property (readonly, copy) NSString *mark; // Returns mode symbol for highest rank (-modes)\n\n/* Weight used when completing nicknames. */\n/* Accessing totalWeight decays the weight. */\n/* Accessing other weight properties does not. */\n@property (readonly) double totalWeight; // (incoming + outgoing) with decay\n@property (readonly) double incomingWeight;\n@property (readonly) double outgoingWeight;\n\n/* Timestamp instance of IRCChannelUser was created. */\n@property (readonly) NSTimeInterval creationTime;\n\n- (instancetype)init NS_UNAVAILABLE;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCChannelUserMutable : IRCChannelUser\n@property (nonatomic, copy, readwrite) NSString *modes;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCClient.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n#import \"IRCConnection.h\"\n#import \"IRCTreeItem.h\"\n#import \"TLOEncryptionManager.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel, IRCClientConfig, IRCHighlightLogEntry, IRCISupportInfo;\n@class IRCAddressBookEntry, IRCMessage, IRCServer, IRCUser;\n\ntypedef NS_ENUM(NSUInteger, IRCClientConnectMode) {\n\tIRCClientConnectModeNormal = 0,\n\tIRCClientConnectModeRetry,\n\tIRCClientConnectModeReconnect,\n};\n\ntypedef NS_ENUM(NSUInteger, IRCClientDisconnectMode) {\n\tIRCClientDisconnectModeNormal = 0,\n\tIRCClientDisconnectModeComputerSleep,\n\tIRCClientDisconnectModeBadCertificate,\n\tIRCClientDisconnectModeReachabilityChange,\n\tIRCClientDisconnectModeServerRedirect\n};\n\ntypedef NS_OPTIONS(NSUInteger, ClientIRCv3SupportedCapability) {\n\tClientIRCv3SupportedCapabilityAwayNotify\t\t\t= 1 << 0, // YES if away-notify CAP supported\n\tClientIRCv3SupportedCapabilityBatch\t\t\t\t\t= 1 << 1, // YES if batch CAP supported\n\tClientIRCv3SupportedCapabilityEchoMessage\t\t\t= 1 << 2, // YES if echo-message CAP supported\n\tClientIRCv3SupportedCapabilityIdentifyCTCP\t\t\t= 1 << 3, // YES if identify-ctcp CAP supported\n\tClientIRCv3SupportedCapabilityIdentifyMsg\t\t\t= 1 << 4, // YES if identify-msg CAP supported\n\tClientIRCv3SupportedCapabilityIsIdentifiedWithSASL\t= 1 << 5, // YES if SASL authentication was successful\n\tClientIRCv3SupportedCapabilityIsInSASLNegotiation\t= 1 << 6, // YES if in SASL CAP authentication request\n\tClientIRCv3SupportedCapabilityMonitorCommand\t\t= 1 << 7, // YES if the MONITOR command is supported\n\tClientIRCv3SupportedCapabilityMultiPrefix\t\t\t= 1 << 8, // YES if multi-prefix CAP supported\n\tClientIRCv3SupportedCapabilityPlayback\t\t\t\t= 1 << 9, // Special CAP which is subject to change\n\tClientIRCv3SupportedCapabilityServerTime\t\t\t= 1 << 10, // YES if server-time CAP supported\n\tClientIRCv3SupportedCapabilityUserhostInNames\t\t= 1 << 11, // YES if userhost-in-names CAP supported\n\tClientIRCv3SupportedCapabilityWatchCommand\t\t\t= 1 << 12, // YES if the WATCH command is supported\n\tClientIRCv3SupportedCapabilityZNCCertInfoModule\t\t= 1 << 13, // YES if the ZNC vendor specific CAP supported\n\tClientIRCv3SupportedCapabilityZNCSelfMessage\t\t= 1 << 14, // YES if the ZNC vendor specific CAP supported\n\tClientIRCv3SupportedCapabilityChangeHost\t\t\t= 1 << 15  // YES if the CHGHOST CAP supported\n};\n\nTEXTUAL_EXTERN NSNotificationName const IRCClientConfigurationWasUpdatedNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCClientChannelListWasModifiedNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCClientWillConnectNotification;\nTEXTUAL_EXTERN NSNotificationName const IRCClientDidConnectNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCClientWillSendQuitNotification;\nTEXTUAL_EXTERN NSNotificationName const IRCClientWillDisconnectNotification;\nTEXTUAL_EXTERN NSNotificationName const IRCClientDidDisconnectNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCClientUserNicknameChangedNotification;\n\n@interface IRCClient : IRCTreeItem <IRCConnectionDelegate>\n@property (readonly, copy) IRCClientConfig *config;\n@property (readonly, copy, nullable) IRCServer *server; // Where is being connected to. Use -serverAddress for server address connected to.\n@property (readonly) IRCISupportInfo *supportInfo;\n@property (readonly) IRCClientConnectMode connectType;\n@property (readonly) IRCClientDisconnectMode disconnectType;\n@property (readonly) BOOL isAutojoined;\t\t\t\t\t// YES if autojoin has completed\n@property (readonly) BOOL isAutojoining;\t\t\t\t// YES if autojoin is in progress\n@property (readonly) BOOL isConnecting;\t\t\t\t\t// YES if socket is connecting. Set to NO on raw numeric 001.\n@property (readonly) BOOL isConnected;\t\t\t\t\t// YES if socket is connected\n@property (readonly) BOOL isConnectedToZNC;\t\t\t\t// YES if Textual detected that this connection is ZNC\n@property (readonly) BOOL isLoggedIn;\t\t\t\t\t// YES if logged into server. Set to YES on raw numeric 001.\n@property (readonly) BOOL isQuitting;\t\t\t\t\t// YES if socket is disconnecting\n@property (readonly) BOOL isReconnecting;\t\t\t\t// YES if reconnect is pending\n@property (readonly) BOOL isSecured;\t\t\t\t\t// YES if socket is connected using SSL/TLS\n@property (readonly) BOOL userIsAway;\t\t\t\t\t// YES if local user is away\n@property (readonly) BOOL userIsIRCop;\t\t\t\t\t// YES if local user is IRCop\n@property (readonly) BOOL userIsIdentifiedWithNickServ; // YES if NickServ identification was successful\n@property (readonly) BOOL isWaitingForNickServ;\t\t\t// YES if NickServ identification is pending\n@property (readonly) BOOL serverHasNickServ;\t\t\t// YES if NickServ service was found on server\n@property (readonly) NSTimeInterval lastMessageReceived;\t\t\t// The time at which the last of any incoming data was received\n@property (readonly) NSTimeInterval lastMessageServerTime;\t\t\t// The time of the last message received that contained a server-time CAP\n@property (readonly) NSUInteger channelCount;\n@property (readonly, weak) IRCChannel *lastSelectedChannel; // If this is the selected client, then the value of this property is the current selection. If the current client is not selected, then this value is either its previous selection or nil.\n@property (readonly, weak) TVCLogLine *lastLine; // Last line in the server console. There is no guarantee it's visible to the user when accessed.\n@property (readonly, copy) NSArray<IRCChannel *> *channelList;\n@property (readonly, copy) NSArray<IRCHighlightLogEntry *> *cachedHighlights;\n@property (readonly, copy, nullable) NSString *userHostmask; // The hostmask of the local user\n@property (readonly, copy) NSString *userNickname; // The nickname of the local user\n@property (readonly, copy, nullable) NSString *serverAddress; // The address of the server connected to or nil\n@property (readonly, copy, nullable) NSString *networkName; // The name of the network connected to or nil\n@property (readonly, copy) NSString *networkNameAlt; // The name of the network connected to or the configured Connection Name\n@property (readonly, copy, nullable) NSString *preAwayUserNickname; // Nickname before away was set or nil\n@property (readonly, copy, nullable) NSData *zncBouncerCertificateChainData;\n@property (readonly) NSUInteger logFileSessionCount; // Number of lines sent to server console log file for session (from connect to disconnect)\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (void)connect;\n- (void)connect:(IRCClientConnectMode)connectMode;\n- (void)connect:(IRCClientConnectMode)connectMode bypassProxy:(BOOL)bypassProxy;\n\n- (void)quit;\n- (void)quitWithComment:(NSString *)comment;\n\n- (void)cancelReconnect;\n\n@property (readonly) ClientIRCv3SupportedCapability capacities;\n@property (readonly, copy) NSString *enabledCapacitiesStringValue;\n\n- (BOOL)isCapabilitySupported:(NSString *)capabilityString;\n\n- (BOOL)isCapabilityEnabled:(ClientIRCv3SupportedCapability)capability;\n\n- (void)joinChannel:(IRCChannel *)channel;\n- (void)joinChannel:(IRCChannel *)channel password:(nullable NSString *)password;\n- (void)joinChannels:(NSArray<IRCChannel *> *)channels;\n- (void)joinUnlistedChannel:(NSString *)channel;\n- (void)joinUnlistedChannel:(NSString *)channel password:(nullable NSString *)password;\n- (void)forceJoinChannel:(NSString *)channel password:(nullable NSString *)password;\n\n- (void)partChannel:(IRCChannel *)channel;\n- (void)partChannel:(IRCChannel *)channel withComment:(nullable NSString *)comment;\n- (void)partUnlistedChannel:(NSString *)channel;\n- (void)partUnlistedChannel:(NSString *)channel withComment:(nullable NSString *)comment;\n\n- (void)changeNickname:(NSString *)newNickname;\n\n- (void)kick:(NSString *)nickname inChannel:(IRCChannel *)channel;\n\n- (void)sendCTCPQuery:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text;\n- (void)sendCTCPReply:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text;\n- (void)sendCTCPPing:(NSString *)nickname;\n\n- (void)sendWhois:(NSString *)nickname;\n\n- (void)sendWhoToChannel:(IRCChannel *)channel;\n- (void)sendWhoToChannelNamed:(NSString *)channel;\n\n- (void)toggleAwayStatus:(BOOL)setAway;\n- (void)toggleAwayStatus:(BOOL)setAway withComment:(nullable NSString *)comment;\n\n- (void)requestModesForChannel:(IRCChannel *)channel;\n- (void)requestModesForChannelNamed:(NSString *)channel;\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray<NSString *> *)parameters inChannel:(IRCChannel *)channel;\n- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannel:(IRCChannel *)channel;\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray<NSString *> *)parameters inChannelNamed:(NSString *)channel;\n- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannelNamed:(NSString *)channel;\n\n- (void)sendPing:(NSString *)tokenString;\n- (void)sendPong:(NSString *)tokenString;\n\n- (void)sendInviteTo:(NSString *)nickname toJoinChannel:(IRCChannel *)channel;\n- (void)sendInviteTo:(NSString *)nickname toJoinChannelNamed:(NSString *)channel;\n\n- (void)requestTopicForChannel:(IRCChannel *)channel;\n- (void)requestTopicForChannelNamed:(NSString *)channel;\n\n- (void)sendTopicTo:(nullable NSString *)topic inChannel:(IRCChannel *)channel;\n- (void)sendTopicTo:(nullable NSString *)topic inChannelNamed:(NSString *)channel;\n\n- (void)sendCapability:(NSString *)subcommand data:(nullable NSString *)data;\n\n- (void)sendIsonForNicknames:(NSArray<NSString *> *)nicknames;\n\n- (void)modifyWatchListBy:(BOOL)adding nicknames:(NSArray<NSString *> *)nicknames;\n\n- (void)requestChannelList;\n\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString;\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString characterSet:(NSCharacterSet *)characterList;\n\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameters:(NSArray<NSString *> *)modeParameters;\n\n- (void)createChannelListDialog;\n- (void)createChannelInviteExceptionListSheet;\n- (void)createChannelBanExceptionListSheet;\n- (void)createChannelBanListSheet;\n- (void)createChannelQuietListSheet;\n\n- (void)presentCertificateTrustInformation;\n\n- (void)closeDialogs;\n\n#pragma mark -\n\n- (BOOL)userExists:(NSString *)nickname;\n\n- (nullable IRCUser *)findUser:(NSString *)nickname;\n- (IRCUser *)findUserOrCreate:(NSString *)nickname;\n\n@property (readonly) NSUInteger numberOfUsers;\n\n@property (readonly, copy) NSArray<IRCUser *> *userList;\n\n- (void)addUser:(IRCUser *)user;\n\n- (void)removeUser:(IRCUser *)user;\n- (void)removeUserWithNickname:(NSString *)nickname;\n\n@property (readonly, nullable) IRCUser *myself;\n\n- (NSArray<IRCAddressBookEntry *> *)findIgnoresForHostmask:(NSString *)hostmask;\n\n#pragma mark -\n\n- (nullable IRCChannel *)findChannel:(NSString *)withName;\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName;\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isPrivateMessage:(BOOL)isPrivateMessage;\n\n- (nullable NSData *)convertToCommonEncoding:(NSString *)string;\n- (nullable NSString *)convertFromCommonEncoding:(NSData *)data;\n\n- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel;\n- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel withFormat:(nullable NSString *)format;\n\n- (BOOL)nicknameIsZNCUser:(NSString *)nickname;\n- (BOOL)nickname:(NSString *)nickname isZNCUser:(NSString *)zncNickname;\n- (nullable NSString *)nicknameAsZNCUser:(NSString *)nickname; // Returns nil if not connected to ZNC\n\n- (BOOL)nicknameIsMyself:(NSString *)nickname;\n\n- (BOOL)stringIsNickname:(NSString *)string;\n- (BOOL)stringIsChannelName:(NSString *)string;\n\n- (BOOL)outputRuleMatchedInMessage:(NSString *)message inChannel:(nullable IRCChannel *)channel;\n\n#pragma mark -\n\n- (void)setUnreadStateForChannel:(IRCChannel *)channel;\n- (void)setUnreadStateForChannel:(IRCChannel *)channel isHighlight:(BOOL)isHighlight;\n\n- (void)setHighlightStateForChannel:(IRCChannel *)channel;\n\n#pragma mark -\n\n- (void)sendCommand:(id)string;\n- (void)sendCommand:(id)string completeTarget:(BOOL)completeTarget target:(nullable NSString *)targetChannelName;\n\n- (void)sendCommand:(NSString *)command toZNCModuleNamed:(NSString *)module;\n\n- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel;\n- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel withEncryption:(BOOL)encryptText;\n\n- (void)sendLine:(NSString *)string;\n- (void)send:(NSString *)string, ...;\n\n- (void)sendPrivmsg:(NSString *)message toChannel:(IRCChannel *)channel; // Invoke -sendText: with proper values\n- (void)sendAction:(NSString *)message toChannel:(IRCChannel *)channel;\n- (void)sendNotice:(NSString *)message toChannel:(IRCChannel *)channel;\n\n#pragma mark -\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (NSUInteger)lengthOfEncryptedMessageDirectedAt:(NSString *)messageTo thatFitsWithinBounds:(NSUInteger)maximumLength;\n\n- (BOOL)encryptionAllowedForTarget:(NSString *)target;\n\n- (void)encryptMessage:(NSString *)messageBody directedAt:(NSString *)messageTo encodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback injectionCallback:(TLOEncryptionManagerInjectCallbackBlock)injectionCallback;\n- (void)decryptMessage:(NSString *)messageBody from:(NSString *)messageFrom target:(NSString *)target decodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback;\n\n@property (nonatomic, readonly, copy) NSString * _Nonnull encryptionAccountNameForLocalUser;\n- (NSString *)encryptionAccountNameForUser:(NSString *)nickname;\n\n- (void)encryptionAuthenticateUser:(NSString *)nickname;\n#endif\n\n#pragma mark -\n\n// nil channel prints the message to the server console\n// referenceMessage.command is used if command == nil\n// referenceMessage and command cannot be nil together (this throws exceptions)\n- (void)\t\tprint:(NSString *)messageBody\n\t\t\t\t   by:(nullable NSString *)nickname\n\t\t\tinChannel:(nullable IRCChannel *)channel\n\t\t\t   asType:(TVCLogLineType)lineType\n\t\t\t  command:(nullable NSString *)command\n\t\t   receivedAt:(NSDate *)receivedAt\n\t\t  isEncrypted:(BOOL)isEncrypted\n\t\tescapeMessage:(BOOL)escapeMessage\n\t referenceMessage:(nullable IRCMessage *)referenceMessage\n\t  completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command;\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt;\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted;\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage;\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;\n\n- (void)printDebugInformationToConsole:(NSString *)message;\n- (void)printDebugInformationToConsole:(NSString *)message asCommand:(NSString *)command;\n\n- (void)printDebugInformation:(NSString *)message;\n- (void)printDebugInformation:(NSString *)message asCommand:(NSString *)command;\n\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel;\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel asCommand:(NSString *)command;\n\n#pragma mark -\n\n- (void)clearCachedHighlights;\n\n/* -config may not always reflect the current state of the client.\n * This is because its too costly to mutate it for stuff that changes\n * many times a second. The client instead saves a copy of its\n * configuration periodically. This method will force it to perform\n * a save if you need to rely on most recent version. */\n- (void)updateStoredConfiguration;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCClientConfig.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCConnectionConfig.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCAddressBookEntry, IRCChannelConfig, IRCHighlightMatchCondition;\n@class IRCNetwork, IRCServer;\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCClientConfig : XRPortablePropertyDict\n@property (readonly) BOOL autoConnect;\n@property (readonly) BOOL autoReconnect;\n@property (readonly) BOOL autoSleepModeDisconnect;\n@property (readonly) BOOL autojoinWaitsForNickServ;\n@property (readonly) BOOL hideAutojoinDelayedWarnings;\n@property (readonly) BOOL hideNetworkUnavailabilityNotices;\n@property (readonly) BOOL performDisconnectOnPongTimer;\n@property (readonly) BOOL performDisconnectOnReachabilityChange;\n@property (readonly) BOOL performPongTimer;\n@property (readonly) BOOL saslAuthenticationDisableExternalMechanism;\n@property (readonly) BOOL sendAuthenticationRequestsToUserServ;\n@property (readonly) BOOL sendWhoCommandRequestsToChannels;\n@property (readonly) BOOL setInvisibleModeOnConnect;\n@property (readonly) BOOL sidebarItemExpanded;\n@property (readonly) BOOL validateServerCertificateChain;\n@property (readonly) BOOL zncIgnoreConfiguredAutojoin;\n@property (readonly) BOOL zncIgnorePlaybackNotifications;\n@property (readonly) BOOL zncIgnoreUserNotifications;\n@property (readonly) BOOL zncOnlyPlaybackLatest;\n@property (readonly) IRCConnectionAddressType addressType;\n@property (readonly) IRCConnectionProxyType proxyType;\n@property (readonly) NSStringEncoding fallbackEncoding;\n@property (readonly) NSStringEncoding primaryEncoding;\n@property (readonly) NSTimeInterval lastMessageServerTime;\n@property (readonly) NSUInteger floodControlDelayTimerInterval;\n@property (readonly) NSUInteger floodControlMaximumMessages;\n@property (readonly) uint16_t proxyPort;\n@property (readonly, copy) NSArray<IRCChannelConfig *> *channelList;\n@property (readonly, copy) NSArray<IRCHighlightMatchCondition *> *highlightList;\n@property (readonly, copy) NSArray<IRCAddressBookEntry *> *ignoreList;\n@property (readonly, copy) NSArray<NSString *> *alternateNicknames;\n@property (readonly, copy) NSArray<NSString *> *loginCommands;\n@property (readonly, copy) NSArray<IRCServer *> *serverList;\n@property (readonly, copy) NSString *connectionName;\n@property (readonly, copy) NSString *nickname;\n@property (readonly, copy) NSString *normalLeavingComment;\n@property (readonly, copy) NSString *realName;\n@property (readonly, copy) NSString *sleepModeLeavingComment;\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly, copy) NSString *username;\n@property (readonly, copy, nullable) NSData *identityClientSideCertificate;\n@property (readonly, copy, nullable) NSString *awayNickname;\n@property (readonly, copy, nullable) NSString *nicknamePassword;\n@property (readonly, copy, nullable) NSString *nicknamePasswordFromKeychain;\n@property (readonly, copy, nullable) NSString *proxyAddress;\n@property (readonly, copy, nullable) NSString *proxyPassword;\n@property (readonly, copy, nullable) NSString *proxyPasswordFromKeychain;\n@property (readonly, copy, nullable) NSString *proxyUsername;\n@property (readonly) RCMCipherSuiteCollection cipherSuites;\n\n- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dic ignorePrivateMessages:(BOOL)ignorePrivateMessages NS_DESIGNATED_INITIALIZER;\n\n+ (instancetype)newConfigByMerging:(IRCClientConfig *)config1 with:(IRCClientConfig *)config2;\n\n+ (instancetype)newConfigWithNetwork:(IRCNetwork *)network;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCClientConfigMutable : IRCClientConfig\n@property (nonatomic, assign, readwrite) BOOL autoConnect;\n@property (nonatomic, assign, readwrite) BOOL autoReconnect;\n@property (nonatomic, assign, readwrite) BOOL autoSleepModeDisconnect;\n@property (nonatomic, assign, readwrite) BOOL autojoinWaitsForNickServ;\n@property (nonatomic, assign, readwrite) BOOL hideAutojoinDelayedWarnings;\n@property (nonatomic, assign, readwrite) BOOL hideNetworkUnavailabilityNotices;\n@property (nonatomic, assign, readwrite) BOOL performDisconnectOnPongTimer;\n@property (nonatomic, assign, readwrite) BOOL performDisconnectOnReachabilityChange;\n@property (nonatomic, assign, readwrite) BOOL performPongTimer;\n@property (nonatomic, assign, readwrite) BOOL saslAuthenticationDisableExternalMechanism;\n@property (nonatomic, assign, readwrite) BOOL sendAuthenticationRequestsToUserServ;\n@property (nonatomic, assign, readwrite) BOOL sendWhoCommandRequestsToChannels;\n@property (nonatomic, assign, readwrite) BOOL setInvisibleModeOnConnect;\n@property (nonatomic, assign, readwrite) BOOL sidebarItemExpanded;\n@property (nonatomic, assign, readwrite) BOOL validateServerCertificateChain;\n@property (nonatomic, assign, readwrite) BOOL zncIgnoreConfiguredAutojoin;\n@property (nonatomic, assign, readwrite) BOOL zncIgnorePlaybackNotifications;\n@property (nonatomic, assign, readwrite) BOOL zncIgnoreUserNotifications;\n@property (nonatomic, assign, readwrite) BOOL zncOnlyPlaybackLatest;\n@property (nonatomic, assign, readwrite) IRCConnectionAddressType addressType;\n@property (nonatomic, assign, readwrite) IRCConnectionProxyType proxyType;\n@property (nonatomic, assign, readwrite) NSStringEncoding fallbackEncoding;\n@property (nonatomic, assign, readwrite) NSStringEncoding primaryEncoding;\n@property (nonatomic, assign, readwrite) NSTimeInterval lastMessageServerTime;\n@property (nonatomic, assign, readwrite) NSUInteger floodControlDelayTimerInterval;\n@property (nonatomic, assign, readwrite) NSUInteger floodControlMaximumMessages;\n@property (nonatomic, assign, readwrite) uint16_t proxyPort;\n@property (nonatomic, copy, readwrite) NSArray<IRCChannelConfig *> *channelList;\n@property (nonatomic, copy, readwrite) NSArray<IRCHighlightMatchCondition *> *highlightList;\n@property (nonatomic, copy, readwrite) NSArray<IRCAddressBookEntry *> *ignoreList;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *alternateNicknames;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *loginCommands;\n@property (nonatomic, copy, readwrite) NSArray<IRCServer *> *serverList;\n@property (nonatomic, copy, readwrite) NSString *connectionName;\n@property (nonatomic, copy, readwrite) NSString *nickname;\n@property (nonatomic, copy, readwrite) NSString *normalLeavingComment;\n@property (nonatomic, copy, readwrite) NSString *realName;\n@property (nonatomic, copy, readwrite) NSString *sleepModeLeavingComment;\n@property (nonatomic, copy, readwrite) NSString *username;\n@property (nonatomic, copy, readwrite, nullable) NSData *identityClientSideCertificate;\n@property (nonatomic, copy, readwrite, nullable) NSString *awayNickname;\n@property (nonatomic, copy, readwrite, nullable) NSString *nicknamePassword;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyPassword;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyUsername;\n@property (nonatomic, assign, readwrite) RCMCipherSuiteCollection cipherSuites;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCColorFormat.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, IRCTextFormatterEffectType) {\n\tIRCTextFormatterEffectNone = 0,\n\tIRCTextFormatterEffectBold,\n\tIRCTextFormatterEffectItalic,\n\tIRCTextFormatterEffectMonospace,\n\tIRCTextFormatterEffectStrikethrough,\n\tIRCTextFormatterEffectUnderline,\n\tIRCTextFormatterEffectForegroundColor,\n\tIRCTextFormatterEffectBackgroundColor,\n\tIRCTextFormatterEffectSpoiler,\n};\n\ntypedef NSString *IRCTextFormatterAttributeName NS_EXTENSIBLE_STRING_ENUM;\n\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterBoldAttributeName; // BOOL\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterItalicAttributeName; // BOOL\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterMonospaceAttributeName; // BOOL\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterStrikethroughAttributeName; // BOOL\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterUnderlineAttributeName; // BOOL\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterForegroundColorAttributeName; // NSNumber, 0-15 - or, NSColor\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterBackgroundColorAttributeName; // NSNumber, 0-15 - or, NSColor\nTEXTUAL_EXTERN IRCTextFormatterAttributeName const IRCTextFormatterSpoilerAttributeName; // BOOL\n\n#define IRCTextFormatterEffectColorAsDigitCharacter\t\t0x03\n#define IRCTextFormatterEffectColorAsHexCharacter\t\t0x04\n#define IRCTextFormatterEffectBoldCharacter\t\t\t\t0x02\n#define IRCTextFormatterEffectItalicCharacter\t\t\t0x1d\n#define IRCTextFormatterEffectItalicCharacterOld\t\t0x16\n#define IRCTextFormatterEffectMonospaceCharacter\t\t0x11\n#define IRCTextFormatterEffectStrikethroughCharacter\t0x1e\n#define IRCTextFormatterEffectUnderlineCharacter\t\t0x1F\n#define IRCTextFormatterTerminatingCharacter\t\t\t0x0F\n\n#define IRCTextFormatterEffectColorHighestDigit\t\t\t98\n\n@class IRCTextFormatterEffects;\n\n@interface IRCTextFormatterEffect : NSObject\n@property (readonly) IRCTextFormatterEffectType type;\n@property (readonly, copy, nullable) NSString *value;\n@property (readonly) UniChar controlCharacter;\n\n/* Number of bytes needed to support this effect.\n Open control character + value + close control character.\n For background color, only the comma and color value is counted. */\n@property (readonly) NSUInteger length;\n\n+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type;\n+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type withValue:(nullable id)value;\n\n- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type;\n- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type withValue:(nullable id)value NS_DESIGNATED_INITIALIZER;\n\n/* Appends control character and value for the effect.\n For background color, appends comma and color value instead. */\n- (void)appendToStartOf:(NSMutableString *)string;\n\n/* Appends control character for the effect.\n For background color, does nothing. */\n- (void)appendToEndOf:(NSMutableString *)string;\n@end\n\n@interface IRCTextFormatterEffects : NSObject\n@property (readonly, copy) NSArray<IRCTextFormatterEffect *> *effects;\n\n/* Number of bytes needed to support all effects. */\n@property (readonly) NSUInteger maximumLength;\n\n+ (instancetype)effectsInAttributes:(NSDictionary<NSString *, id> *)attributes;\n\n- (instancetype)initWithAttributes:(NSDictionary<NSString *, id> *)attributes NS_DESIGNATED_INITIALIZER;\n\n- (void)appendToStartOf:(NSMutableString *)string;\n- (void)appendToEndOf:(NSMutableString *)string;\n@end\n\n#pragma mark -\n\n@interface NSAttributedString (IRCTextFormatter)\n- (BOOL)IRCFormatterAttributeSetInRange:(IRCTextFormatterEffectType)effect\n\t\t\t\t\t\t\t\t  range:(NSRange)limitRange;\n\n/* Returns an NSString with appropriate formatting characters. */\n@property (readonly, copy) NSString *stringFormattedForIRC;\n@end\n\n#pragma mark -\n\n@interface NSMutableAttributedString (IRCTextFormatter)\n- (void)setIRCFormatterAttribute:(IRCTextFormatterEffectType)effect \n\t\t\t\t\t\t   value:(id)value \n\t\t\t\t\t\t   range:(NSRange)limitRange;\n\n- (void)removeIRCFormatterAttribute:(IRCTextFormatterEffectType)effect \n\t\t\t\t\t\t\t  range:(NSRange)limitRange;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCCommandIndex.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Local commands are client-local commands */\ntypedef NS_ENUM(NSUInteger, IRCLocalCommand) {\n\tIRCLocalCommandAdchat = 5001,\n\tIRCLocalCommandAme = 5002,\n\tIRCLocalCommandAmsg = 5003,\n\tIRCLocalCommandAquote = 5095,\n\tIRCLocalCommandAraw = 5096,\n\tIRCLocalCommandAutojoin = 5101,\n\tIRCLocalCommandAway = 5004,\n\tIRCLocalCommandBack = 5105,\n\tIRCLocalCommandBan = 5005,\n\tIRCLocalCommandCap = 5006,\n\tIRCLocalCommandCaps = 5007,\n\tIRCLocalCommandChatops = 5009,\n\tIRCLocalCommandClear = 5010,\n\tIRCLocalCommandClearall = 5011,\n\tIRCLocalCommandClose = 5012,\n\tIRCLocalCommandConn = 5013,\n\tIRCLocalCommandCtcp = 5014,\n\tIRCLocalCommandCtcpreply = 5015,\n\tIRCLocalCommandCycle = 5016,\n\tIRCLocalCommandDcc = 5017,\n\tIRCLocalCommandDebug = 5018,\n\tIRCLocalCommandDefaults = 5092,\n\tIRCLocalCommandDehalfop = 5019,\n\tIRCLocalCommandDeop = 5020,\n\tIRCLocalCommandDevoice = 5021,\n\tIRCLocalCommandEcho = 5022,\n\tIRCLocalCommandGetscripts = 5098,\n\tIRCLocalCommandGline = 5023,\n\tIRCLocalCommandGlobops = 5024,\n\tIRCLocalCommandGoto = 5099,\n\tIRCLocalCommandGzline = 5025,\n\tIRCLocalCommandHalfop = 5026,\n\tIRCLocalCommandHop = 5027,\n\tIRCLocalCommandIgnore = 5029,\n\tIRCLocalCommandInvite = 5030,\n\tIRCLocalCommandIson = 5100,\n\tIRCLocalCommandJ = 5031,\n\tIRCLocalCommandJoin = 5032,\n\tIRCLocalCommandJoinRandom = 5109,\n\tIRCLocalCommandKb = 5083,\n\tIRCLocalCommandKick = 5033,\n\tIRCLocalCommandKickban = 5034,\n\tIRCLocalCommandKill = 5035,\n\tIRCLocalCommandLagcheck = 5084,\n\tIRCLocalCommandLeave = 5036,\n\tIRCLocalCommandList = 5037,\n\tIRCLocalCommandLocops = 5039,\n\tIRCLocalCommandM = 5040,\n\tIRCLocalCommandMe = 5041,\n\tIRCLocalCommandMode = 5042,\n\tIRCLocalCommandMonitor = 5106,\n\tIRCLocalCommandMsg = 5043,\n\tIRCLocalCommandMute = 5044,\n\tIRCLocalCommandMylag = 5045,\n\tIRCLocalCommandMyversion = 5046,\n\tIRCLocalCommandNachat = 5047,\n\tIRCLocalCommandNames = 5094,\n\tIRCLocalCommandNick = 5048,\n\tIRCLocalCommandNotice = 5050,\n\tIRCLocalCommandNotifybubble = 5112,\n\tIRCLocalCommandNotifysound = 5113,\n\tIRCLocalCommandNotifyspeak = 5114,\n\tIRCLocalCommandOmsg = 5051,\n\tIRCLocalCommandOnotice = 5052,\n\tIRCLocalCommandOp = 5053,\n\tIRCLocalCommandPart = 5054,\n\tIRCLocalCommandPass = 5055,\n\tIRCLocalCommandQuery = 5056,\n\tIRCLocalCommandQuiet = 5107,\n\tIRCLocalCommandQuit = 5057,\n\tIRCLocalCommandQuote = 5058,\n\tIRCLocalCommandRaw = 5059,\n\tIRCLocalCommandRecv = 5087,\n\tIRCLocalCommandRejoin = 5060,\n\tIRCLocalCommandRemove = 5061,\n\tIRCLocalCommandServer = 5062,\n\tIRCLocalCommandSetcolor = 5103,\n\tIRCLocalCommandSetqueryname = 5117,\n\tIRCLocalCommandShun = 5063,\n\tIRCLocalCommandSme = 5064,\n\tIRCLocalCommandSmsg = 5065,\n\tIRCLocalCommandSslcontext = 5066,\n\tIRCLocalCommandT = 5067,\n\tIRCLocalCommandTage = 5093,\n\tIRCLocalCommandTempshun = 5068,\n\tIRCLocalCommandTimer = 5069,\n\tIRCLocalCommandTopic = 5070,\n\tIRCLocalCommandUme = 5089,\n\tIRCLocalCommandUmode = 5071,\n\tIRCLocalCommandUmsg = 5088,\n\tIRCLocalCommandUnban = 5072,\n\tIRCLocalCommandUnignore = 5073,\n\tIRCLocalCommandUnmute = 5075,\n\tIRCLocalCommandUnotice = 5090,\n\tIRCLocalCommandUnquiet = 5108,\n\tIRCLocalCommandVoice = 5076,\n\tIRCLocalCommandWallops = 5077,\n\tIRCLocalCommandWatch = 5097,\n\tIRCLocalCommandWeights = 5118,\n\tIRCLocalCommandWho = 5079,\n\tIRCLocalCommandWhois = 5080,\n\tIRCLocalCommandWhowas = 5081,\n\tIRCLocalCommandZline = 5082\n};\n\n/* Remote commands are server-side commands */\ntypedef NS_ENUM(NSUInteger, IRCRemoteCommand) {\n\tIRCRemoteCommandAdchat = 1003,\n\tIRCRemoteCommandAuthenticate = 1005,\n\tIRCRemoteCommandAway = 1050,\n\tIRCRemoteCommandBatch = 1054,\n\tIRCRemoteCommandCap = 1004,\n\tIRCRemoteCommandCertinfo = 1055,\n\tIRCRemoteCommandChatops = 1006,\n\tIRCRemoteCommandChghost = 1057,\n\tIRCRemoteCommandError = 1016,\n\tIRCRemoteCommandGline = 1047,\n\tIRCRemoteCommandGlobops = 1017,\n\tIRCRemoteCommandGzline = 1048,\n\tIRCRemoteCommandInvite = 1018,\n\tIRCRemoteCommandIson = 1019,\n\tIRCRemoteCommandJoin = 1020,\n\tIRCRemoteCommandKick = 1021,\n\tIRCRemoteCommandKill = 1022,\n\tIRCRemoteCommandList = 1023,\n\tIRCRemoteCommandLocops = 1024,\n\tIRCRemoteCommandMode = 1026,\n\tIRCRemoteCommandMonitor = 1056,\n\tIRCRemoteCommandNachat = 1027,\n\tIRCRemoteCommandNames = 1028,\n\tIRCRemoteCommandNick = 1029,\n\tIRCRemoteCommandNotice = 1030,\n\tIRCRemoteCommandPart = 1031,\n\tIRCRemoteCommandPass = 1032,\n\tIRCRemoteCommandPing = 1033,\n\tIRCRemoteCommandPong = 1034,\n\tIRCRemoteCommandPrivmsg = 1035,\n\tIRCRemoteCommandPrivmsgAction = 1002,\n\tIRCRemoteCommandQuit = 1036,\n\tIRCRemoteCommandShun = 1045,\n\tIRCRemoteCommandTempshun = 1046,\n\tIRCRemoteCommandTime = 1012,\n\tIRCRemoteCommandTopic = 1039,\n\tIRCRemoteCommandUser = 1037,\n\tIRCRemoteCommandWallops = 1038,\n\tIRCRemoteCommandWatch = 1053,\n\tIRCRemoteCommandWho = 1040,\n\tIRCRemoteCommandWhois = 1042,\n\tIRCRemoteCommandWhowas = 1041,\n\tIRCRemoteCommandZline = 1049\n};\n\n/* Controlling class */\n@interface IRCCommandIndex : NSObject\n+ (NSArray<NSString *> *)localCommandList;\n\n+ (NSUInteger)indexOfRemoteCommand:(NSString *)command;\n+ (NSUInteger)indexOfLocalCommand:(NSString *)command;\n\n+ (NSUInteger)colonPositionForRemoteCommand:(NSString *)command;\n\n+ (nullable NSString *)syntaxForLocalCommand:(NSString *)command;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCConnection.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCConnectionConfig;\n\n@interface IRCConnection : NSObject\n@property (readonly, weak) IRCClient *client;\n@property (readonly, copy) IRCConnectionConfig *config;\n@property (readonly) BOOL isConnected;\n@property (readonly) BOOL isConnectedWithClientSideCertificate;\n@property (readonly) BOOL isConnecting;\n@property (readonly) BOOL isDisconnecting;\n@property (readonly) BOOL isSecured;\n@property (readonly) BOOL isSending;\n@property (readonly) BOOL EOFReceived;\n@property (readonly, nullable) NSString *connectedAddress; // nil if connected to a proxy\n@property (readonly, copy) NSString *uniqueIdentifier;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithConfig:(IRCConnectionConfig *)config onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)open;\n- (void)close;\n\n- (void)sendLine:(NSString *)line;\n\n- (void)clearSendQueue;\n@end\n\n@protocol IRCConnectionDelegate <NSObject>\n@required\n\n- (void)ircConnection:(IRCConnection *)sender\n   willConnectToProxy:(NSString *)proxyHost\n\t\t\t\t port:(uint16_t)proxyPort;\n- (void)ircConnectionDidConnect:(IRCConnection *)sender;\n- (void)ircConnectionDidSecureConnection:(IRCConnection *)sender\n\t\t\t\t\t\twithProtocolType:(tls_protocol_version_t)protocolType\n\t\t\t\t\t\t\t cipherSuite:(tls_ciphersuite_t)cipherSuite;\n- (void)ircConnectionDidCloseReadStream:(IRCConnection *)sender;\n- (void)ircConnection:(IRCConnection *)sender didDisconnectWithError:(nullable NSError *)disconnectError;\n- (void)ircConnection:(IRCConnection *)sender didReceiveData:(NSString *)data;\n- (void)ircConnection:(IRCConnection *)sender willSendData:(NSString *)data;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCHighlightLogEntry.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogLine;\n\n@interface IRCHighlightLogEntry : XRPortablePropertyObject\n@property (readonly, copy) TVCLogLine *lineLogged;\n@property (readonly, copy) NSDate *timeLogged;\n@property (readonly, copy) NSString *clientId;\n@property (readonly, copy) NSString *channelId;\n@property (readonly, copy) NSString *lineNumber;\n@property (readonly, copy) NSAttributedString *renderedMessage;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCHighlightMatchCondition.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCHighlightMatchCondition : XRPortablePropertyDict\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly, copy) NSString *matchKeyword;\n@property (readonly, copy, nullable) NSString *matchChannelId;\n@property (readonly) BOOL matchIsExcluded;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCHighlightMatchConditionMutable : IRCHighlightMatchCondition\n@property (nonatomic, copy, readwrite) NSString *matchKeyword;\n@property (nonatomic, copy, readwrite, nullable) NSString *matchChannelId;\n@property (nonatomic, assign, readwrite) BOOL matchIsExcluded;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCISupportInfo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCModeInfo;\n\ntypedef NS_ENUM(NSUInteger, IRCISupportInfoListType)\n{\n\tIRCISupportInfoListTypeBan,\n\tIRCISupportInfoListTypeBanException,\n\tIRCISupportInfoListTypeInviteException,\n\tIRCISupportInfoListTypeQuiet\n};\n\n#define IRCISupportInfoHighestUserPrefixRank\t\t\t100\n\n#define IRCISupportUserModeSymbolsSymbolsKey\t\t\t@\"modeSymbols\"\n#define IRCISupportUserModeSymbolsCharactersKey\t\t\t@\"characters\"\n\n@interface IRCISupportInfo : NSObject\n@property (readonly) BOOL configurationReceived;\n@property (readonly) NSUInteger maximumAwayLength; // 0 = no limit\n@property (readonly) NSUInteger maximumChannelNameLength; // 0 = no limit - unused\n@property (readonly) NSUInteger maximumKeyLength; // 0 = no limit\n@property (readonly) NSUInteger maximumKickLength; // 0 = no limit\n@property (readonly) NSUInteger maximumNicknameLength;\n@property (readonly) NSUInteger maximumTopicLength; // 0 = no limit\n@property (readonly) NSUInteger maximumModeCount;\n@property (readonly, copy) NSArray<NSString *> *channelNamePrefixes;\n@property (readonly, copy) NSArray<NSString *> *statusMessageModeSymbols;\n@property (readonly, copy) NSDictionary<NSString *, NSNumber *> *channelModes;\n@property (readonly, copy) NSDictionary<NSString *, NSArray *> *userModeSymbols;\n@property (readonly, copy, nullable) NSString *banExceptionModeSymbol;\n@property (readonly, copy, nullable) NSString *inviteExceptionModeSymbol;\n@property (readonly, copy, nullable) NSString *serverAddress;\n@property (readonly, copy, nullable) NSString *networkName;\n@property (readonly, copy, nullable) NSString *networkNameFormatted;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (nullable NSString *)modeSymbolForUserPrefix:(NSString *)character;\n- (nullable NSString *)userPrefixForModeSymbol:(NSString *)modeSymbol;\n\n- (BOOL)characterIsUserPrefix:(NSString *)character;\n- (BOOL)modeSymbolIsUserPrefix:(NSString *)modeSymbol;\n\n- (nullable NSString *)statusMessagePrefixForModeSymbol:(NSString *)modeSymbol;\n- (NSString *)extractStatusMessagePrefixFromChannelNamed:(NSString *)channel;\n\n- (NSUInteger)rankForUserPrefixWithMode:(NSString *)modeSymbol; // Starts at 100; 100 = highest rank\n\n- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol;\n- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter;\n\n- (BOOL)isListSupported:(IRCISupportInfoListType)listType;\n\n- (nullable NSString *)modeSymbolForList:(IRCISupportInfoListType)listType;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCMessage.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCPrefix;\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCMessage : XRPortablePropertyObject\n@property (readonly, copy) IRCPrefix *sender;\n@property (readonly, copy) NSString *command;\n@property (readonly) NSUInteger commandNumeric;\n@property (readonly, copy) NSArray<NSString *> *params;\n@property (readonly, copy) NSDate *receivedAt;\n@property (readonly) BOOL isHistoric; // Whether a custom @time= was supplied during parsing.\n@property (readonly) BOOL isEventOnlyMessage; /* The message should be parsed and special actions performed such as adding/removing user but the result is never passed to print: */\n@property (readonly) BOOL isPrintOnlyMessage; /* The message should be parsed and passed to print: but special actions such as adding/removing user from member list should be ignored. (currently unused) */\n@property (readonly, copy, nullable) NSString *batchToken;\n@property (readonly, copy, nullable) NSDictionary<NSString *, NSString *> *messageTags; /* IRCv3 message tags. See ircv3.net for more information regarding extensions in the IRC protocol. */\n\n- (nullable instancetype)initWithLine:(NSString *)line;\n- (nullable instancetype)initWithLine:(NSString *)line onClient:(nullable IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n@property (readonly, copy, nullable) NSString *senderNickname;\n@property (readonly, copy, nullable) NSString *senderUsername;\n@property (readonly, copy, nullable) NSString *senderAddress;\n@property (readonly, copy, nullable) NSString *senderHostmask;\n\n@property (readonly) BOOL senderIsServer;\n\n@property (readonly) NSUInteger paramsCount;\n\n- (NSString *)paramAt:(NSUInteger)index;\n\n@property (readonly, copy) NSString *sequence;\n- (NSString *)sequence:(NSUInteger)index;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCMessageMutable : IRCMessage\n@property (nonatomic, copy, readwrite) IRCPrefix *sender;\n@property (nonatomic, copy, readwrite) NSString *command;\n@property (nonatomic, assign, readwrite) NSUInteger commandNumeric;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *params;\n@property (nonatomic, copy, readwrite) NSDate *receivedAt;\n@property (nonatomic, assign, readwrite) BOOL isHistoric;\n@property (nonatomic, assign, readwrite) BOOL isEventOnlyMessage;\n@property (nonatomic, assign, readwrite) BOOL isPrintOnlyMessage;\n@property (nonatomic, copy, readwrite, nullable) NSString *batchToken;\n@property (nonatomic, copy, readwrite, nullable) NSDictionary<NSString *, NSString *> *messageTags;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCModeInfo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCModeInfo : XRPortablePropertyObject\n@property (readonly) BOOL modeIsSet;\n@property (readonly, copy) NSString *modeSymbol;\n@property (readonly, copy, nullable) NSString *modeParameter;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol;\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet;\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter NS_DESIGNATED_INITIALIZER;\n\n- (BOOL)isModeForChangingMemberModeOn:(IRCClient *)client;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCModeInfoMutable : IRCModeInfo\n@property (nonatomic, assign, readwrite) BOOL modeIsSet;\n@property (nonatomic, copy, readwrite) NSString *modeSymbol;\n@property (nonatomic, copy, readwrite, nullable) NSString *modeParameter;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCNetworkList.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCNetwork;\n\n@interface IRCNetworkList : NSObject\n@property (readonly, copy) NSArray<IRCNetwork *> *listOfNetworks;\n\n- (nullable IRCNetwork *)networkNamed:(NSString *)networkName;\n\n- (nullable IRCNetwork *)networkWithServerAddress:(NSString *)serverAddress;\n@end\n\n#pragma mark -\n\n@interface IRCNetwork : NSObject\n@property (readonly, copy) NSString *networkName;\n@property (readonly, copy) NSString *networkDescription NS_UNAVAILABLE; // unused\n@property (readonly, copy) NSString *serverAddress;\n@property (readonly) uint16_t serverPort;\n@property (readonly) BOOL prefersSecuredConnection;\n\n- (instancetype)init NS_UNAVAILABLE;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCNumerics.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nenum {\n\t/* Replies */\n\tRPL_WELCOME = 1,\n\tRPL_YOURHOST = 2,\n\tRPL_CREATED = 3,\n\tRPL_MYINFO = 4,\n\tRPL_ISUPPORT = 5,\n\tRPL_REDIR = 10,\n\tRPL_UMODEIS = 221,\n\tRPL_STATSCONN = 250,\n\tRPL_LUSERCLIENT = 251,\n\tRPL_LUSERHOP = 252,\n\tRPL_LUSERUNKNOWN = 253,\n\tRPL_LUSERCHANNELS = 254,\n\tRPL_LUSERME = 255,\n\tRPL_LOCALUSERS = 265,\n\tRPL_GLOBALUSERS = 266,\n\tRPL_WHOISCERTFP = 276,\n\tRPL_AWAY = 301,\n\tRPL_ISON = 303,\n\tRPL_UNAWAY = 305,\n\tRPL_NOWAWAY = 306,\n\tRPL_WHOISREGNICK = 307,\n\tRPL_WHOISHELPOP = 310,\n\tRPL_WHOISUSER = 311,\n\tRPL_WHOISSERVER = 312,\n\tRPL_WHOISOPERATOR = 313,\n\tRPL_WHOWASUSER = 314,\n\tRPL_ENDOFWHO = 315,\n\tRPL_WHOISIDLE = 317,\n\tRPL_ENDOFWHOIS = 318,\n\tRPL_WHOISCHANNELS = 319,\n\tRPL_WHOISSPECIAL = 320,\n\tRPL_LISTSTART = 321,\n\tRPL_LIST = 322,\n\tRPL_LISTEND = 323,\n\tRPL_CHANNELMODEIS = 324,\n\tRPL_CHANNEL_URL = 328,\n\tRPL_CREATIONTIME = 329,\n\tRPL_WHOISACCOUNT = 330,\n\tRPL_TOPIC = 332,\n\tRPL_TOPICWHOTIME = 333,\n\tRPL_WHOISBOT = 335,\n\tRPL_WHOISACTUALLY = 338,\n\tRPL_INVITING = 341,\n\tRPL_INVITELIST = 346,\n\tRPL_ENDOFINVITELIST = 347,\n\tRPL_EXCEPTLIST = 348,\n\tRPL_ENDOFEXCEPTLIST = 349,\n\tRPL_WHOREPLY = 352,\n\tRPL_NAMEREPLY = 353,\n\tRPL_ENDOFNAMES = 366,\n\tRPL_BANLIST = 367,\n\tRPL_ENDOFBANLIST = 368,\n\tRPL_ENDOFWHOWAS = 369,\n\tRPL_MOTD = 372,\n\tRPL_MOTDSTART = 375,\n\tRPL_ENDOFMOTD = 376,\n\tRPL_WHOISHOST = 378,\n\tRPL_WHOISMODES = 379,\n\tRPL_YOUREOPER = 381,\n\tRPL_REAWAY = 597,\n\tRPL_GONEAWAY = 598,\n\tRPL_NOTAWAY = 599,\n\tRPL_LOGON = 600,\n\tRPL_LOGOFF = 601,\n\tRPL_WATCHOFF = 602,\n\tRPL_WATCHSTAT = 603,\n\tRPL_NOWON = 604,\n\tRPL_NOWOFF = 605,\n\tRPL_WATCHLIST = 606,\n\tRPL_ENDOFWATCHLIST = 607,\n\tRPL_CLEARWATCH = 608,\n\t/* RPL_CHANNELSMSG and RPL_WHOWASIP were added recently.\n\t Reference: https://github.com/inspircd/inspircd/commit/150258b1f110aad58c8882b76474a4ceb3b2ab97 */\n\tRPL_CHANNELSMSG = 651, // (is on private/secret channels..., InspIRCd)\n\tRPL_WHOWASIP = 652, // (was connected from..., InspIRCd)\n\tRPL_WHOISSECURE = 671,\n\tRPL_WHOISREALIP = 672, // (is a CGI:IRC client from..., Rizon)\n\tRPL_TARGUMODEG = 716,\n\tRPL_TARGNOTIFY = 717,\n\tRPL_UMODEGMSG = 718,\n\tRPL_QUIETLIST = 728,\n\tRPL_ENDOFQUIETLIST = 729,\n\tRPL_MONONLINE = 730,\n\tRPL_MONOFFLINE = 731,\n\tRPL_MONLIST = 732,\n\tRPL_ENDOFMONLIST = 733,\n\tRPL_LOGGEDIN = 900,\n\tRPL_LOGGEDOUT = 901,\n\tRPL_SASLSUCCESS = 903,\n\tRPL_SASLMECHS = 908,\n\n\t/* Errors */\n\tERR_NOSUCHNICK = 401,\n\tERR_NOSUCHSERVER = 402,\n\tERR_NOSUCHCHANNEL = 403,\n\tERR_CANNOTSENDTOCHAN = 404,\n\tERR_TOOMANYCHANNELS = 405,\n\tERR_UNKNOWNCOMMAND = 421,\n\tERR_NOMOTD = 422,\n\tERR_ERRONEUSNICKNAME = 432,\n\tERR_NICKNAMEINUSE = 433,\n\tERR_BANNICKCHANGE = 435,\n\tERR_UNAVAILRESOURCE = 437,\n\tERR_NICKTOOFAST = 438,\n\tERR_CANTCHANGENICK = 447,\n\tERR_FORBIDDENCHANNEL = 448,\n\tERR_NOHIDING = 459,\n\tERR_NEEDMOREPARAMS = 461,\n\tERR_LINKCHANNEL = 470,\n\tERR_CHANNELISFULL = 471,\n\tERR_INVITEONLYCHAN = 473,\n\tERR_BANNEDFROMCHAN = 474,\n\tERR_BADCHANNELKEY = 475,\n\tERR_BADCHANMASK = 476,\n\tERR_NEEDREGGEDNICK = 477,\n\tERR_BADCHANNAME = 479,\n\tERR_THROTTLE = 480,\n\tERR_SECUREONLYCHAN = 489,\n\tERR_DELAYREJOIN = 495,\n\tERR_TOOMANYJOINS = 500,\n\tERR_TOOMANYWATCH = 512,\n\tERR_DISABLED = 517,\n\tERR_ADMONLY = 519,\n\tERR_OPERONLY = 520,\n\tERR_WHOSYNTAX = 522,\n\tERR_WHOLIMEXCEED = 523,\n\tERR_OPERSPVERIFY = 524,\n\tERR_MONLISTFULL = 734,\n\tERR_NICKLOCKED = 902,\n\tERR_SASLFAIL = 904,\n\tERR_SASLTOOLONG = 905,\n\tERR_SASLABORTED = 906,\n\tERR_SASLALREADY = 907,\n\tERR_BADCHANNEL = 926\n};\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCPrefix.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCPrefix : XRPortablePropertyObject\n@property (readonly) BOOL isServer;\n@property (readonly, copy) NSString *hostmask; // Defaults to empty string\n@property (readonly, copy) NSString *nickname; // Defaults to empty string\n@property (readonly, copy, nullable) NSString *username;\n@property (readonly, copy, nullable) NSString *address;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCPrefixMutable : IRCPrefix\n@property (nonatomic, assign, readwrite) BOOL isServer;\n@property (nonatomic, copy, readwrite) NSString *hostmask;\n@property (nonatomic, copy, readwrite) NSString *nickname;\n@property (nonatomic, copy, readwrite, nullable) NSString *username;\n@property (nonatomic, copy, readwrite, nullable) NSString *address;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCSendingMessage.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCSendingMessage : NSObject\n+ (NSString *)stringWithCommand:(NSString *)command arguments:(nullable NSArray<NSString *> *)arguments;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCServer.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCServer : XRPortablePropertyDict\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly, copy) NSString *serverAddress;\n@property (readonly, copy, nullable) NSString *serverPassword;\n@property (readonly, copy, nullable) NSString *serverPasswordFromKeychain;\n@property (readonly) uint16_t serverPort;\n@property (readonly) BOOL prefersSecuredConnection;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCServerMutable : IRCServer\n@property (nonatomic, copy, readwrite) NSString *serverAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *serverPassword;\n@property (nonatomic, assign, readwrite) uint16_t serverPort;\n@property (nonatomic, assign, readwrite) BOOL prefersSecuredConnection;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCTreeItem.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, TVCLogController;\n\n@interface IRCTreeItem : NSObject\n@property (readonly) BOOL isActive;\n@property (readonly) BOOL isUnread;\n@property (readonly) BOOL isClient;\n@property (readonly) BOOL isChannel;\n@property (readonly) BOOL isPrivateMessage;\n@property (readonly, weak) IRCClient *associatedClient;\n@property (readonly, weak) IRCChannel *associatedChannel;\n@property (readonly) NSString *label;\n@property (readonly) NSString *name;\n@property (readonly) NSString *uniqueIdentifier;\n@property (readonly) NSUInteger dockUnreadCount;\n@property (readonly) NSUInteger nicknameHighlightCount;\n@property (readonly) NSUInteger treeUnreadCount;\n@property (readonly) TVCLogController *viewController;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCUser.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Each user on a server is allocated one instance of IRCUser. \n IRCUser is used to keep track of information related to the user. */\n/* There is ever only one instance of IRCUser kept track of by the\n IRCClient class. It is possible to create a mutable copy of a user\n to change properties, but those changes will not be recognized until\n the modified user is given to IRCClient. IRCClient will then perform\n the actions necessary to update all components depending on the user. */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCUser : XRPortablePropertyObject\n@property (readonly, copy) NSString *nickname;\n@property (readonly, copy, nullable) NSString *username;\n@property (readonly, copy, nullable) NSString *address;\n@property (readonly, copy, nullable) NSString *hostmask;\n@property (readonly, copy, nullable) NSString *hostmaskFragment; // -hostmask without nickname\n@property (readonly, copy, nullable) NSString *realName;\n@property (readonly) BOOL isAway;\n@property (readonly) BOOL isIRCop;\n\n@property (readonly, copy) NSString *banMask;\n\n@property (readonly, copy) NSString *lowercaseNickname;\n@property (readonly, copy) NSString *uppercaseNickname;\n\n/* -presentAwayMessageFor301 keeps track of the last time raw numeric\n 301 (away message) is received and will return YES if the message\n should be presented, NO otherwise. */\n@property (readonly) BOOL presentAwayMessageFor301;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (instancetype)initWithNickname:(NSString *)nickname onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)markAsAway;\n- (void)markAsReturned;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCUserMutable : IRCUser\n@property (nonatomic, copy, readwrite) NSString *nickname; // Defaults to empty string\n@property (nonatomic, copy, readwrite, nullable) NSString *username;\n@property (nonatomic, copy, readwrite, nullable) NSString *address;\n@property (nonatomic, copy, readwrite, nullable) NSString *realName;\n@property (nonatomic, assign, readwrite) BOOL isAway;\n@property (nonatomic, assign, readwrite) BOOL isIRCop;\n\n- (instancetype)initWithClient:(IRCClient *)client;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCUserRelations.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCUser.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel, IRCChannelUser;\n\n@interface IRCUser (IRCUserRelations)\n@property (readonly, copy) NSDictionary<IRCChannel *, IRCChannelUser *> *relations;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/IRCWorld.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCClientConfig, IRCChannel, IRCChannelConfig, IRCTreeItem;\n\nTEXTUAL_EXTERN NSString * const IRCWorldClientListDefaultsKey;\n\nTEXTUAL_EXTERN NSNotificationName const IRCWorldClientListWasModifiedNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCWorldDateHasChangedNotification;\n\nTEXTUAL_EXTERN NSNotificationName const IRCWorldWillDestroyClientNotification;\nTEXTUAL_EXTERN NSNotificationName const IRCWorldWillDestroyChannelNotification;\n\n@interface IRCWorld : NSObject\n@property (readonly) NSUInteger messagesSent;\n@property (readonly) NSUInteger messagesReceived;\n@property (readonly) uint64_t bandwidthIn;\n@property (readonly) uint64_t bandwidthOut;\n@property (readonly, copy) NSArray<IRCClient *> *clientList;\n@property (readonly) NSUInteger clientCount;\n\n- (void)save;\n- (void)savePeriodically;\n\n- (NSArray<__kindof IRCTreeItem *> *)findItemsWithIds:(NSArray<NSString *> *)itemIds;\n\n- (nullable IRCTreeItem *)findItemWithId:(NSString *)itemId;\n\n- (nullable IRCClient *)findClientWithId:(NSString *)clientId;\n- (nullable IRCChannel *)findChannelWithId:(NSString *)channelId onClientWithId:(NSString *)clientId;\n\n- (nullable IRCClient *)findClientWithServerAddress:(NSString *)serverAddress;\n\n- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config;\n- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client;\n- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client;\n\n- (void)destroyClient:(IRCClient *)client;\n- (void)destroyChannel:(IRCChannel *)channel;\n\n- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments; // Defaults to onQueue YES\n- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments onQueue:(BOOL)onQueue;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCAddressBookInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCAddressBook.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCAddressBookEntry ()\n{\n@protected\n\tBOOL _ignoreClientToClientProtocol;\n\tBOOL _ignoreFileTransferRequests;\n\tBOOL _ignoreGeneralEventMessages;\n\tBOOL _ignoreInlineMedia;\n\tBOOL _ignoreNoticeMessages;\n\tBOOL _ignorePrivateMessageHighlights;\n\tBOOL _ignorePrivateMessages;\n\tBOOL _ignorePublicMessageHighlights;\n\tBOOL _ignorePublicMessages;\n\tBOOL _trackUserActivity;\n\tIRCAddressBookEntryType _entryType;\n\tNSString *_hostmask;\n\tNSString *_hostmaskRegularExpression;\n\tNSString *_trackingNickname;\n\tNSArray<IRCAddressBookEntry *> *_parentEntries;\n\n@private\n\tNSString *_uniqueIdentifier;\n\tNSDictionary *_defaults;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCChannelConfigInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelConfigPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelConfig ()\n{\n@protected\n\tBOOL _autoJoin;\n\tBOOL _ignoreGeneralEventMessages;\n\tBOOL _ignoreHighlights;\n\tBOOL _inlineMediaDisabled;\n\tBOOL _inlineMediaEnabled;\n\tBOOL _pushNotifications;\n\tBOOL _showTreeBadgeCount;\n\tIRCChannelType _type;\n\tNSString *_channelName;\n\tNSString *_label;\n\tNSString *_defaultModes;\n\tNSString *_defaultTopic;\n\tNSString *_secretKey;\n\tNSMutableDictionary *_notificationsMutable;\n\n@private\n\tNSString *_uniqueIdentifier;\n\tNSDictionary *_defaults;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCChannelUserInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelUserPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelUser ()\n{\n@protected\n\tNSString *_modes;\n\tdouble _incomingWeight;\n\tdouble _outgoingWeight;\n\tCFAbsoluteTime _lastWeightFade;\n\tNSTimeInterval _creationTime;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCClientConfigInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientConfigPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCClientConfig ()\n{\n@protected\n\tBOOL _autoConnect;\n\tBOOL _autoReconnect;\n\tBOOL _autoSleepModeDisconnect;\n\tBOOL _autojoinWaitsForNickServ;\n\tBOOL _connectionPrefersIPv4;\n\tBOOL _hideAutojoinDelayedWarnings;\n\tBOOL _hideNetworkUnavailabilityNotices;\n\tBOOL _performDisconnectOnPongTimer;\n\tBOOL _performDisconnectOnReachabilityChange;\n\tBOOL _performPongTimer;\n\tBOOL _prefersSecuredConnection;\n\tBOOL _saslAuthenticationDisableExternalMechanism;\n\tBOOL _sendAuthenticationRequestsToUserServ;\n\tBOOL _sendWhoCommandRequestsToChannels;\n\tBOOL _setInvisibleModeOnConnect;\n\tBOOL _sidebarItemExpanded;\n\tBOOL _validateServerCertificateChain;\n\tBOOL _zncIgnoreConfiguredAutojoin;\n\tBOOL _zncIgnorePlaybackNotifications;\n\tBOOL _zncIgnoreUserNotifications;\n\tBOOL _zncOnlyPlaybackLatest;\n\tIRCConnectionAddressType _addressType;\n\tIRCConnectionProxyType _proxyType;\n\tNSArray<IRCAddressBookEntry *> *_ignoreList;\n\tNSArray<IRCChannelConfig *> *_channelList;\n\tNSArray<IRCHighlightMatchCondition *> *_highlightList;\n\tNSArray<NSString *> *_alternateNicknames;\n\tNSArray<NSString *> *_loginCommands;\n\tNSArray<IRCServer *> *_serverList;\n\tNSData *_identityClientSideCertificate;\n\tNSString *_awayNickname;\n\tNSString *_connectionName;\n\tNSString *_nickname;\n\tNSString *_nicknamePassword;\n\tNSString *_normalLeavingComment;\n\tNSString *_proxyAddress;\n\tNSString *_proxyPassword;\n\tNSString *_proxyUsername;\n\tNSString *_realName;\n\tNSString *_serverAddress;\n\tNSString *_sleepModeLeavingComment;\n\tNSString *_username;\n\tNSStringEncoding _fallbackEncoding;\n\tNSStringEncoding _primaryEncoding;\n\tNSTimeInterval _lastMessageServerTime;\n\tNSUInteger _floodControlDelayTimerInterval;\n\tNSUInteger _floodControlMaximumMessages;\n\tuint16_t _proxyPort;\n\tuint16_t _serverPort;\n\tRCMCipherSuiteCollection _cipherSuites;\n\n@private\n\tBOOL _migratedServerPasswordPendingDestroy;\n\tNSUInteger _dictionaryVersion;\n\tNSString *_uniqueIdentifier;\n\tNSDictionary *_defaults;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCHighlightLogEntryInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCHighlightLogEntryPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCHighlightLogEntry ()\n{\n@protected\n\tTVCLogLine *_lineLogged;\n\tNSString *_clientId;\n\tNSString *_channelId;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCHighlightMatchConditionInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCHighlightMatchCondition.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCHighlightMatchCondition ()\n{\n@protected\n\tBOOL _matchIsExcluded;\n\tNSString *_matchChannelId;\n\tNSString *_matchKeyword;\n\n@private\n\tNSString *_uniqueIdentifier;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCMessageInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCMessagePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCMessage ()\n{\n@protected\n\tBOOL _isHistoric;\n\tBOOL _isEventOnlyMessage;\n\tBOOL _isPrintOnlyMessage;\n\tIRCPrefix *_sender;\n\tNSArray<NSString *> *_params;\n\tNSDate *_receivedAt;\n\tNSDictionary<NSString *, NSString *> *_messageTags;\n\tNSString *_batchToken;\n\tNSString *_command;\n\tNSUInteger _commandNumeric;\n\tIRCMessageBatchMessage *_parentBatchMessage;\n}\n\n@end\n\n@interface IRCMessage (IRCMessageLineParser)\n- (BOOL)parseLine:(NSString *)line forClient:(nullable IRCClient *)client;\n- (void)parseExtensions:(NSString *)extensionInfo forClient:(nullable IRCClient *)client;\n- (void)parseSender:(NSString *)senderInfo forClient:(nullable IRCClient *)client;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCModeInfoInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCModeInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCModeInfo ()\n{\n@protected\n\tBOOL _modeIsSet;\n\tNSString *_modeSymbol;\n\tNSString *_modeParameter;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCPrefixInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCPrefix.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCPrefix ()\n{\n@protected\n\tBOOL _isServer;\n\tNSString *_nickname;\n\tNSString *_username;\n\tNSString *_address;\n\tNSString *_hostmask;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCServerInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCServerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCServer ()\n{\n@protected\n\tBOOL _prefersSecuredConnection;\n\tNSString *_serverAddress;\n\tNSString *_serverPassword;\n\tuint16_t _serverPort;\n\n@private\n\tNSString *_uniqueIdentifier;\n\tNSDictionary *_defaults;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/IRCUserInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCUserPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCUser ()\n{\n@protected\n\tNSString *_nickname;\n\tNSString *_username;\n\tNSString *_address;\n\tNSString *_realName;\n\tBOOL _isAway;\n\tBOOL _isIRCop;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/TDCChannelPropertiesSheetInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCChannelPropertiesSheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelConfigMutable;\n\n@interface TDCChannelPropertiesSheet ()\n@property (nonatomic, strong) IRCChannelConfigMutable *config;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/TDCChannelSpotlightAppearanceInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCChannelSpotlightAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TDCChannelSpotlightPanel;\n\n@interface TDCChannelSpotlightAppearance ()\n- (nullable instancetype)initWithWindow:(TDCChannelSpotlightPanel *)window;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/TDCChannelSpotlightControllerInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCChannelSpotlightControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TDCChannelSpotlightAppearance, TDCChannelSpotlightSearchResult;\n\n@interface TDCChannelSpotlightController ()\n- (TDCChannelSpotlightAppearance *)userInterfaceObjects;\n\n@property (readonly, copy) NSString *searchString;\n@property (readonly) NSArray<TDCChannelSpotlightSearchResult *> *searchResults;\n@property (readonly) NSArray<TDCChannelSpotlightSearchResult *> *searchResultsFiltered;\n@property (readonly) NSUInteger searchResultsCount;\n@property (readonly) NSInteger selectedSearchResult; // -1 = none selected\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/TDCFileTransferDialogInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCFileTransferDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCFileTransferDialog ()\n@property (nonatomic, copy, readwrite, nullable) NSString *IPAddress;\n\n- (void)updateClearButton;\n\n- (void)updateMaintenanceTimer;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Internal/TVCLogLineInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLinePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogLine ()\n{\n@protected\n\tBOOL _isEncrypted;\n\tBOOL _isFirstForDay;\n\tBOOL _nicknameColorStyleOverride;\n\tNSArray<NSString *> *_excludeKeywords;\n\tNSArray<NSString *> *_highlightKeywords;\n\tNSDictionary<NSString *, id> *_rendererAttributes;\n\tNSDate *_receivedAt;\n\tNSString *_command;\n\tNSString *_messageBody;\n\tNSString *_nickname;\n\tNSString *_nicknameColorStyle;\n\tTVCLogLineMemberType _memberType;\n\tTVCLogLineType _lineType;\n\tNSUInteger _sessionIdentifier;\n\n@private\n\tNSString *_uniqueIdentifier;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/NSColorHelper.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSColor (TXColorHelper)\n@property (class, readonly, copy) NSArray<NSColor *> *formatterColors;\n\n@property (class, readonly) NSColor *formatterWhiteColor;\n@property (class, readonly) NSColor *formatterBlackColor;\n@property (class, readonly) NSColor *formatterNavyBlueColor;\n@property (class, readonly) NSColor *formatterDarkGreenColor;\n@property (class, readonly) NSColor *formatterRedColor;\n@property (class, readonly) NSColor *formatterBrownColor;\n@property (class, readonly) NSColor *formatterPurpleColor;\n@property (class, readonly) NSColor *formatterOrangeColor;\n@property (class, readonly) NSColor *formatterYellowColor;\n@property (class, readonly) NSColor *formatterLimeGreenColor;\n@property (class, readonly) NSColor *formatterTealColor;\n@property (class, readonly) NSColor *formatterAquaCyanColor;\n@property (class, readonly) NSColor *formatterLightBlueColor;\n@property (class, readonly) NSColor *formatterFuchsiaPinkColor;\n@property (class, readonly) NSColor *formatterNormalGrayColor;\n@property (class, readonly) NSColor *formatterLightGrayColor;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/NSStringHelper.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\nTEXTUAL_EXTERN NSStringEncoding const TXDefaultPrimaryStringEncoding;\nTEXTUAL_EXTERN NSStringEncoding const TXDefaultFallbackStringEncoding;\n\n@interface NSString (TXStringHelper)\n@property (readonly, copy) NSString *stringByAppendingIRCFormattingStop;\n\n@property (readonly, copy, nullable) NSString *channelNameWithoutBang; // \"#channel\" -> \"channel\", \"##channel\" -> \"#channel\"\n- (nullable NSString *)channelNameWithoutBangOn:(IRCClient *)client;\n\n@property (readonly, copy, nullable) NSString *nicknameFromHostmask;\n@property (readonly, copy, nullable) NSString *usernameFromHostmask;\n@property (readonly, copy, nullable) NSString *addressFromHostmask;\n\n- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor;\n- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor honorFormattingPreference:(BOOL)formattingPreference;\n\n@property (readonly, copy) NSString *stripIRCEffects;\n\n@property (getter=isValidInternetAddress, readonly) BOOL validInternetAddress;\n@property (getter=isValidInternetPort, readonly) BOOL validInternetPort;\n\n@property (getter=isHostmask, readonly) BOOL hostmask;\n\n@property (getter=isIPv4Address, readonly) BOOL IPv4Address;\n@property (getter=isIPv6Address, readonly) BOOL IPv6Address;\n@property (getter=isIPAddress, readonly) BOOL IPAddress;\n\n- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname\n\t\t\t\t  username:(NSString * _Nullable * _Nullable)username\n\t\t\t\t   address:(NSString * _Nullable * _Nullable)address;\n\n- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname\n\t\t\t\t  username:(NSString * _Nullable * _Nullable)username\n\t\t\t\t   address:(NSString * _Nullable * _Nullable)address\n\t\t\t\t  onClient:(nullable IRCClient *)client;\n\n@property (getter=isHostmaskNickname, readonly) BOOL hostmaskNickname;\n@property (getter=isHostmaskAddress, readonly) BOOL hostmaskAddress;\n@property (getter=isHostmaskUsername, readonly) BOOL hostmaskUsername;\n\n/* By handing a client to -isHostmask[*]On:, greater validity\n is promised as configuration options from ISUPPORT (005) and\n other contextual information can be accessed. */\n- (BOOL)isHostmaskNicknameOn:(nullable IRCClient *)client;\n- (BOOL)isHostmaskUsernameOn:(nullable IRCClient *)client;\n- (BOOL)isHostmaskAddressOn:(nullable IRCClient *)client;\n\n@property (getter=isChannelName, readonly) BOOL channelName;\n- (BOOL)isChannelNameOn:(IRCClient *)client; // Client to parse CHANTYPES from\n\n@property (readonly, copy, nullable) NSString *stringWithValidURIScheme;\n\n- (NSArray<NSString *> *)base64EncodingWithLineLength:(NSUInteger)lineLength;\n\n- (NSUInteger)colorComponentsOfCharacter:(UniChar)character\n\t\t\t\t\t\t\t  startingAt:(NSUInteger)rangeStart\n\t\t\t\t\t\t foregroundColor:(id _Nullable * _Nullable)foregroundColor\n\t\t\t\t\t\t backgroundColor:(id _Nullable * _Nullable)backgroundColor;\n\n- (nullable NSString *)padNicknameWithCharacter:(UniChar)padCharacter maximumLength:(NSUInteger)maximumLength;\n\n@property (readonly, copy, nullable) NSString *prettyLicenseKey;\n\n@property (readonly, copy) NSString *encodedMessageTagString;\n@property (readonly, copy) NSString *decodedMessageTagString;\n\n@property (getter=isModeSymbol, readonly) BOOL modeSymbol;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/NSViewHelper.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSWindow (TXWindowHelper)\n/* Reset size of window to accommodate -minSize */\n- (void)changeFrameToMin; // display = YES; animate = NO\n- (void)changeFrameToMinAndDisplay:(BOOL)display; // animate = NO\n- (void)changeFrameToMinAndDisplay:(BOOL)display animate:(BOOL)animate;\n\n/* Sets content view to nil, resets frame to fit view, then assigns new view. */\n- (void)replaceContentView:(NSView *)withView;\n@end\n\n@interface NSView (TXViewHelper)\n/* Self top, right, bottom, left will = superview with 0.0 constant. */\n- (void)addConstraintsToSuperviewToHugEdges;\n\n/* Superview width and height will = self with 0.0 constant. */\n/* A priority of 550 is used to encourage hugging. */\n- (void)addConstraintsToSuperviewToEqualDimensions;\n\n/* Remove first subview (if one is present) and replaces it with subview. */\n/* The new superview width and height will equal that of subview with a\n priority of 550. The subview top, right, bottom, and left will equal\n that of the superview with 0.0 constant. */\n/* See \t-addConstraintsToSuperviewToHugEdges\n\t\t-addConstraintsToSuperviewToEqualDimensions */\n- (void)replaceFirstSubview:(NSView *)withView;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/ICLPayloadLocalPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLPayload.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLPayload (ICLPayloadLocalPrivate)\n@property (copy, readonly) NSDictionary<NSString *, id> *javaScriptObject;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCAddressBookMatchCachePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCAddressBookEntry, IRCClient;\n\n@interface IRCAddressBookMatchCache : NSObject\n@property (readonly, weak) IRCClient *client;\n\n- (instancetype)initWithClient:(IRCClient *)client;\n\n/* If multiple address book entries exist for the same host,\n then we return all of them combined into a single instance.\n This object will have a blank hostmask and the entry type\n IRCAddressBookEntryTypeMixed. */\n- (nullable IRCAddressBookEntry *)findAddressBookEntryForHostmask:(NSString *)hostmask;\n\n- (NSArray<IRCAddressBookEntry *> *)findIgnoresForHostmask:(NSString *)hostmask;\n\n- (void)clearCachedMatches;\n- (void)clearCachedMatchesForHostmask:(NSString *)hostmask;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCAddressBookUserTrackingPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCAddressBookUserTracking.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCAddressBookUserTrackingContainer ()\n- (instancetype)initWithClient:(IRCClient *)client;\n\n- (IRCAddressBookUserTrackingStatus)_statusOfUser:(NSString *)nickname;\n\n- (void)addTrackedUser:(NSString *)nickname;\n- (void)_addTrackedUser:(NSString *)nickname;\n\n- (void)removeTrackedUser:(NSString *)nickname;\n- (void)_removeTrackedUser:(NSString *)nickname;\n\n- (void)clearTrackedUsers;\n\n- (void)statusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelConfigPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelConfig.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelConfig ()\n@property (readonly, copy) NSDictionary<NSString *, NSNumber *> *notifications;\n\n- (void)writeSecretKeyToKeychain;\n\n- (void)destroySecretKeyKeychainItem;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelMemberListControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\n/* The member list controller is the controller bound to the view in the\n main window. IRCChannelMemberList, when assigned to it, will maintain a\n 1:1 relation to its internal list and the content of the controller. */\n/* DO NOT modify the controller directly. Allow IRCChannelMemberList to\n do the work for you to maintain the integrity of the internal list and\n the content of the controller. */\n@interface IRCChannelMemberListController : NSArrayController\n/* A controller can be assigned to only one channel or none. */\n/* TVCMainWindow is responsible for assignment using TVCMemberList\n as a proxy. */\n- (void)assignToChannel:(nullable IRCChannel *)channel;\n\n- (void)replaceContents:(NSArray<IRCChannelUser *> *)contents;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelMemberListPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelMemberList.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel, IRCChannelMemberListController;\n\n@protocol IRCChannelMemberListPrivatePrototype <NSObject>\n- (void)addMember:(IRCChannelUser *)member checkForDuplicates:(BOOL)checkForDuplicates;\n\n/* The replaceInAllChannels: flag should only be used in extreme cases because there is A LOT\n of overhead to setting it. Textual only does it when the user list is configured to sort IRCop\n at top and IRCop status changes. That change requires the user to be resorted in every channel\n they are in. Knowing which channels they are in is easy because of IRCUserRelations, but the\n actual process of finding where to sort them at is very expensive. */\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2;\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort;\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort replaceInAllChannels:(BOOL)replaceInAllChannels;\n\n- (void)changeMember:(NSString *)nickname mode:(NSString *)mode value:(BOOL)value;\n\n- (void)resortMember:(IRCChannelUser *)member;\n\n- (void)clearMembers;\n\n- (NSData *)pasteboardDataForMembers:(NSArray<IRCChannelUser *> *)members;\n+ (BOOL)readNicknamesFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<NSString *> *nicknames))callbackBlock;\n+ (BOOL)readMembersFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<IRCChannelUser *> *members))callbackBlock;\n@end\n\n@interface IRCChannelMemberList () <IRCChannelMemberListPrivatePrototype>\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n+ (void)suspendMemberListSerialQueues;\n+ (void)resumeMemberListSerialQueues;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelModePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelMode.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\n@interface IRCChannelMode ()\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (NSArray<IRCModeInfo *> *)updateModes:(NSString *)modeString;\n\n- (void)clear;\n@end\n\n#pragma mark -\n\n@interface IRCChannelModeContainer ()\n- (void)applyModes:(NSArray<IRCModeInfo *> *)modes;\n\n- (void)clear;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannel.h\"\n#import \"IRCChannelMemberListPrivate.h\"\n#import \"TVCLogController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogLine;\n\n@interface IRCChannel () <IRCChannelMemberListPrivatePrototype>\n@property (nonatomic, assign, readwrite) IRCChannelStatus status;\n@property (nonatomic, assign) BOOL sentInitialWhoRequest;\n@property (nonatomic, assign) BOOL channelModesReceived;\n@property (nonatomic, assign) BOOL channelNamesReceived;\n@property (nonatomic, assign, readwrite) BOOL errorOnLastJoinAttempt;\n\n- (instancetype)initWithConfig:(IRCChannelConfig *)config NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithConfigDictionary:(NSDictionary<NSString *, id> *)dic;\n\n- (void)updateConfig:(IRCChannelConfig *)config;\n- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification;\n- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification updateStoredChannelList:(BOOL)updateStoredChannelList;\n\n- (NSDictionary<NSString *, id> *)configurationDictionary;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (void)noteEncryptionStateDidChange;\n#endif\n\n- (void)writeToLogLineToLogFile:(TVCLogLine *)logLine;\n- (void)logFileWriteSessionBegin;\n- (void)logFileWriteSessionEnd;\n\n- (void)print:(TVCLogLine *)logLine;\n- (void)print:(TVCLogLine *)logLine completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;\n\n- (void)reopenLogFileIfNeeded;\n- (void)closeLogFile;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCChannelUserPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelUser.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelUser ()\n- (instancetype)initWithUser:(IRCUser *)user;\n\n- (void)changeUserToUser:(IRCUser *)user;\n\n- (void)conversation;\n- (void)incomingConversation;\n- (void)outgoingConversation;\n\n+ (NSComparator)channelRankComparator;\n+ (NSComparator)nicknameLengthComparator;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCClientConfigPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientConfig.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCClientConfig ()\n/* To provide user with similar behavior, when migrating -connectionPrefersIPv4\n in IRCClientConfig, we set the address type to IRCConnectionAddressTypeIPv4.\n We check if both values are set to offer the user a warning that the preference\n they had has changed in a way they may not want. When user changes the address\n type in Server Properties, we unset -connectionPrefersIPv4 so that the warning\n does not appear again, ever. */\n@property (readonly) BOOL showConnectionPrefersIPv4Warning;\n@property (readonly) BOOL connectionPrefersIPv4 TEXTUAL_DEPRECATED(\"Use -addressType instead\");\n\n- (void)writeNicknamePasswordToKeychain;\n- (void)writeProxyPasswordToKeychain;\n\n- (void)destroyNicknamePasswordKeychainItem;\n- (void)destroyProxyPasswordKeychainItem;\n\n- (void)destroyServerPasswordKeychainItemAfterMigration;\n@end\n\n@interface IRCClientConfigMutable ()\n@property (nonatomic, assign, readwrite) BOOL connectionPrefersIPv4 TEXTUAL_DEPRECATED(\"Use -addressType instead\");\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCClientPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n#import \"IRCClient.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TLOSpokenNotification;\n@class IRCAddressBookUserTrackingContainer, IRCTimedCommand, IRCUserMutable;\n\nenum {\n\tClientIRCv3SupportedCapabilitySASLGeneric\t\t\t= 1 << 22,\n\tClientIRCv3SupportedCapabilitySASLPlainText\t\t\t= 1 << 23, // YES if SASL=plain CAP is supported\n\tClientIRCv3SupportedCapabilitySASLExternal\t\t\t= 1 << 24, // YES if SASL=external CAP is supported\n\tClientIRCv3SupportedCapabilityZNCServerTime\t\t\t= 1 << 25, // YES if the ZNC vendor specific CAP supported\n\tClientIRCv3SupportedCapabilityZNCServerTimeISO\t\t= 1 << 26, // YES if the ZNC vendor specific CAP supported\n\tClientIRCv3SupportedCapabilityZNCPlaybackModule\t\t= 1 << 27, // YES if the ZNC vendor specific CAP supported\n\tClientIRCv3SupportedCapabilityPlanioPlayback\t\t= 1 << 28  // YES if the plan.io vendor specific CAP supported.\n};\n\n@interface IRCClient ()\n@property (nonatomic, copy, nullable) dispatch_block_t disconnectCallback;\n@property (nonatomic, assign, readwrite) IRCClientConnectMode connectType;\n@property (nonatomic, assign, readwrite) IRCClientDisconnectMode disconnectType;\n@property (nonatomic, assign) BOOL sidebarItemIsExpanded;\n@property (nonatomic, copy, readwrite) NSArray<IRCChannel *> *channelList;\n@property (nonatomic, weak, readwrite) IRCChannel *lastSelectedChannel;\n\n- (instancetype)initWithConfig:(IRCClientConfig *)config NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithConfigDictionary:(NSDictionary<NSString *, id> *)dic;\n\n- (void)updateConfig:(IRCClientConfig *)config;\n- (void)updateConfig:(IRCClientConfig *)config updateSelection:(BOOL)updateSelection;\n\n- (NSDictionary<NSString *, id> *)configurationDictionary;\n\n- (void)addChannel:(IRCChannel *)channel;\n- (void)addChannel:(IRCChannel *)channel atPosition:(NSUInteger)position;\n\n- (void)removeChannel:(IRCChannel *)channel; // This only removes the channel from channel array. Use world controller to properly destroy a channel.\n\n- (NSUInteger)indexOfChannel:(IRCChannel *)channel;\n\n- (void)selectFirstChannelInChannelList;\n\n- (void)reloadServerListItems;\n\n- (void)updateStoredChannelList;\n\n- (void)cacheHighlightInChannel:(IRCChannel *)channel withLogLine:(TVCLogLine *)logLine;\n\n- (void)inputText:(id)string destination:(IRCTreeItem *)destination;\n\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command;\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command destination:(IRCTreeItem *)destination;\n\n- (void)enableCapability:(ClientIRCv3SupportedCapability)capability;\n- (void)disableCapability:(ClientIRCv3SupportedCapability)capability;\n\n- (void)noteReachabilityChanged:(BOOL)reachable;\n\n- (void)autoConnectWithDelay:(NSUInteger)delay afterWakeUp:(BOOL)afterWakeUp;\n\n- (void)postEventToViewController:(NSString *)eventToken;\n- (void)postEventToViewController:(NSString *)eventToken forChannel:(IRCChannel *)channel;\n\n- (void)sendFile:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;\n- (void)sendFileResume:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;\n- (void)sendFileResumeAccept:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken;\n\n- (void)notifyFileTransfer:(TXNotificationType)type nickname:(NSString *)nickname filename:(NSString *)filename filesize:(uint64_t)totalFilesize requestIdentifier:(NSString *)identifier;\n\n- (IRCAddressBookUserTrackingContainer *)trackedUsers;\n\n- (IRCUserMutable *)mutableCopyOfUserWithNickname:(NSString *)nickname;\n\n- (void)modifyUser:(IRCUser *)user withBlock:(void (NS_NOESCAPE ^)(IRCUserMutable *userMutable))block;\n- (void)modifyUserUserWithNickname:(NSString *)nickname withBlock:(void (NS_NOESCAPE ^)(IRCUserMutable *userMutable))block;\n\n- (void)reopenLogFileIfNeeded;\n- (void)closeLogFile;\n\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isUtility:(BOOL)isUtility;\n\n- (nullable NSString *)formatNotificationToSpeak:(TLOSpokenNotification *)notification;\n\n- (id)queuedBatchMessageWithToken:(NSString *)batchToken;\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command escapeMessage:(BOOL)escapeMessage;\n\n- (void)onTimedCommand:(IRCTimedCommand *)timedCommand;\n\n- (void)logFileRecordSessionChanged:(BOOL)toNewSession inChannel:(nullable IRCChannel *)channel;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCClientRequestedCommandsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* The response of some commands are shown and hidden depending\n on who sent the command. IRCClientRequestedCommands is used by\n IRCClient internally to keep track of what commands have been\n requested so that it can determine how to treat the response. */\n/* IRCClientRequestedCommands works in conjunction with IRCClient\n by balancing all calls to a command. */\n\n@interface IRCClientRequestedCommands : NSObject\n- (void)removeCommands;\n@end\n\n#pragma mark -\n\n@interface IRCClientRequestedCommands (Helpers)\n#pragma mark -\n#pragma mark ISON Command (Default: hidden)\n\n@property (readonly, getter=inVisibleIsonRequest) BOOL visibleIsonRequest;\n- (void)recordIsonRequestOpened;\n- (void)recordIsonRequestOpenedAsVisible;\n- (void)recordIsonRequestClosed;\n\n#pragma mark -\n#pragma mark MONITOR Command (Default: hidden)\n\n#if 0\n/* The MONITOR command can perform multiple actions which means its results\n do not always have a predetermined number of results or an end numeric. */\n/* To work around this, we feed IRCClientRequestedCommands an estimate\n of the number of responses to expect. We then decrement that by calling\n the *ClosedOne for each response received. When the count reaches zero,\n the request is automatically closed without calling *Closed. */\n/* If we encounter an error, we instead call *Closed which ends the request there. */\n@property (readonly, getter=inVisibleMonitorRequest) BOOL visibleMonitorRequest;\n- (void)recordMonitorRequestOpened; // No limit on count\n- (void)recordMonitorRequestOpenedWithCount:(NSUInteger)count;\n- (void)recordMonitorRequestOpenedAsVisible; // No limit on count\n- (void)recordMonitorRequestOpenedAsVisibleWithCount:(NSUInteger)count;\n- (void)recordMonitorRequestClosedOne; // Does nothing if no count is specified\n- (void)recordMonitorRequestClosed;\n\n#pragma mark -\n#pragma mark NAMES Command (Default: hidden)\n\n@property (readonly, getter=inVisibleNamesRequest) BOOL visibleNamesRequest;\n- (void)recordNamesRequestOpened;\n- (void)recordNamesRequestOpenedAsVisible;\n- (void)recordNamesRequestClosed;\n\n#pragma mark -\n#pragma mark WATCH Command (Default: hidden)\n\n@property (readonly, getter=inVisibleWatchRequest) BOOL visibleWatchRequest;\n- (void)recordWatchRequestOpened; // No limit on count\n- (void)recordWatchRequestOpenedWithCount:(NSUInteger)count;\n- (void)recordWatchRequestOpenedAsVisible; // No limit on count\n- (void)recordWatchRequestOpenedAsVisibleWithCount:(NSUInteger)count;\n- (void)recordWatchRequestClosedOne; // Does nothing if no count is specified\n- (void)recordWatchRequestClosed;\n#endif\n\n#pragma mark -\n#pragma mark WHO Command (Default: hidden)\n\n@property (readonly, getter=inVisibleWhoRequest) BOOL visibleWhoRequest;\n- (void)recordWhoRequestOpened;\n- (void)recordWhoRequestOpenedAsVisible;\n- (void)recordWhoRequestClosed;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCColorFormatPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLine.h\"\n#import \"IRCColorFormat.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel;\n\n@interface NSAttributedString (IRCTextFormatterPrivate)\n/* Given contextual information (client, channel, lineType), the original\n attributed string is converted to use appropriate formatting characters,\n but this method does not allow the result to exceed TXMaximumIRCBodyLength. */\n/* The only valid lineType value is PRIVMSG, ACTION, or NOTICE. */\n/* effectiveRange is the range of the result in the attributed string.\n Use this value to delete those characters during enumeration.  */\n- (NSString *)stringFormattedForChannel:(NSString *)channelName\n\t\t\t\t\t\t\t   onClient:(IRCClient *)client\n\t\t\t\t\t\t   withLineType:(TVCLogLineType)lineType\n\t\t\t\t\t\t effectiveRange:(NSRange * _Nullable)effectiveRange;\n@end\n\n@interface NSMutableAttributedString (IRCTextFormatterPrivate)\n/* This method truncates self to the effective range */\n- (NSString *)stringFormattedForChannel:(NSString *)channelName\n\t\t\t\t\t\t\t   onClient:(IRCClient *)client\n\t\t\t\t\t\t   withLineType:(TVCLogLineType)lineType;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCCommandIndexPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCCommandIndex ()\n+ (void)populateCommandIndex;\n\n+ (void)invalidateCaches;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCConnectionPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCConnection.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCConnection ()\n@property (nonatomic, copy, readwrite) IRCConnectionConfig *config;\n@property (nonatomic, assign, readwrite) BOOL isConnected;\n@property (nonatomic, assign, readwrite) BOOL isConnecting;\n@property (nonatomic, assign, readwrite) BOOL isDisconnecting;\n@property (nonatomic, assign, readwrite) BOOL isSending;\n@property (nonatomic, assign, readwrite) BOOL isSecured;\n@property (nonatomic, assign, readwrite) BOOL isConnectedWithClientSideCertificate;\n@property (nonatomic, assign, readwrite) BOOL EOFReceived;\n@property (nonatomic, copy, readwrite, nullable) NSString *connectedAddress;\n\n- (void)enforceFloodControl;\n\n- (void)openSecuredConnectionCertificateModal;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCExtrasPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCExtras : NSObject\n+ (void)parseIRCProtocolURI:(NSString *)location;\n\n+ (void)parseIRCProtocolURI:(NSString *)location\n\t\t\t withDescriptor:(nullable NSAppleEventDescriptor *)event;\n\n+ (void)createConnectionToServer:(NSString *)serverInfo\n\t\t\t\t\t channelList:(nullable NSString *)channelList\n\t\t\t  connectWhenCreated:(BOOL)connectWhenCreated;\n\n+ (void)createConnectionToServer:(NSString *)serverInfo\n\t\t\t\t\t channelList:(nullable NSString *)channelList\n\t\t\t  connectWhenCreated:(BOOL)connectWhenCreated\n\t   mergeConnectionIfPossible:(BOOL)mergeConnectionIfPossible\n\t\t selectFirstChannelAdded:(BOOL)selectFirstChannelAdded;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCHighlightLogEntryPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCHighlightLogEntry.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\n@interface IRCHighlightLogEntry ()\n@property (readonly, weak) IRCChannel *channel;\n@property (readonly, copy) NSString *channelName;\n@property (readonly, copy) NSString *timeLoggedFormatted;\n@end\n\n@interface IRCHighlightLogEntryMutable : IRCHighlightLogEntry\n@property (nonatomic, copy, readwrite) TVCLogLine *lineLogged;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, readwrite) NSString *channelId;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCISupportInfoPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCISupportInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@interface IRCISupportInfo ()\n@property (nonatomic, copy, readwrite, nullable) NSString *serverAddress;\n\n@property (readonly, copy, nullable) NSString *stringValueForLastUpdate;\n\n- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)processConfigurationData:(NSString *)configurationData;\n\n- (NSArray<IRCModeInfo *> *)parseModes:(NSString *)modeString;\n\n- (void)reset;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCMessageBatchPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Each IRCClient is assigned a single instance of\n IRCMessageBatchMessageContainer which acts as a container for\n all BATCH command events that the client may receive. */\n@interface IRCMessageBatchMessageContainer : NSObject\n@property (readonly, copy) NSDictionary *queuedEntries;\n\n- (void)queueEntry:(id)entry;\n- (void)dequeueEntry:(id)entry;\n- (void)dequeueEntries;\n\n- (id)queuedEntryWithBatchToken:(NSString *)batchToken;\n@end\n\n/* IRCMessageBatchMessage represents a single BATCH event based\n on its token value. Queued entries can either be an IRCMessage\n instance or IRCMessageBatchMessage (for nested batch events). */\n@interface IRCMessageBatchMessage : NSObject\n@property (nonatomic, assign) BOOL batchIsOpen;\n@property (nonatomic, copy) NSString *batchToken;\n@property (nonatomic, copy, nullable) NSString *batchType;\n@property (readonly, copy) NSArray *queuedEntries;\n@property (nonatomic, weak) IRCMessageBatchMessage *parentBatchMessage;\n\n- (void)queueEntry:(id)entry;\n- (void)dequeueEntry:(id)entry;\n- (void)dequeueEntries;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCMessagePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCMessage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCMessageBatchMessage;\n\n@interface IRCMessage ()\n@property (readonly, strong, nullable) IRCMessageBatchMessage *parentBatchMessage;\n\n- (void)markAsNotHistoric;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCServerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCServer.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCServer ()\n/* IRCClient retains a copy of the active IRCServer instance.\n When the -serverList in IRCClientConfig is modified, \n any servers that are removed will have their keychain \n items destroyed. We do not want to destroy the keychain\n items for the IRCServer instance that IRCClient has a copy\n of, so the -destroyKeychainItemsDuringDealloc flag is used.\n This tells the IRCServer instance to hold onto the keychain\n item until there is no longer a reference to it. */\n@property (nonatomic, assign) BOOL destroyKeychainItemsDuringDealloc;\n\n- (void)writeServerPasswordToKeychain;\n\n- (void)destroyServerPasswordKeychainItem;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCTimerCommandPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel;\n\n@interface IRCTimedCommand : NSObject\n@property (readonly, copy) NSString *identifier;\n\n@property (readonly, copy) NSString *clientId;\n@property (readonly, copy, nullable) NSString *channelId;\n\n@property (readonly, copy) NSString *command;\n\n@property (readonly) NSTimeInterval startTime;\n@property (readonly) NSTimeInterval timeRemaining;\n\n@property (readonly) NSTimeInterval timerInterval;\n@property (readonly) BOOL timerIsActive;\n@property (readonly) BOOL repeatTimer;\n@property (readonly) NSUInteger iterations;\n\n@property (readonly) NSUInteger currentIteration;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client;\n- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client inChannel:(nullable IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)start:(NSTimeInterval)interval; // repeatTimer = NO\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer; // iterations = 0\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations; // 0 iterations = infinite\n\n- (void)stop;\n\n/* If the timer has been started before, then\n we already know the values to pass to -start:\n In that case, we return YES.\n If we don't know this information yet, then\n we return NO. */\n/* Restarting the timer resets the iteration count. */\n- (BOOL)restart;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCTreeItemPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCTreeItem.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCTreeItem ()\n@property (nonatomic, assign, readwrite) NSUInteger dockUnreadCount;\n@property (nonatomic, assign, readwrite) NSUInteger nicknameHighlightCount;\n@property (nonatomic, assign, readwrite) NSUInteger treeUnreadCount;\n@property (nonatomic, weak, readwrite) IRCClient *associatedClient;\n@property (nonatomic, strong, readwrite) TVCLogController *viewController;\n\n- (void)resetState;\n\n@property (readonly) NSUInteger numberOfChildren;\n- (nullable IRCTreeItem *)childAtIndex:(NSUInteger)index;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCUserNicknameColorStyleGeneratorPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCTheme.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCUserNicknameColorStyleGenerator : NSObject\n+ (NSString *)nicknameColorStyleForString:(NSString *)inputString;\n+ (NSString *)nicknameColorStyleForString:(NSString *)inputString isOverride:(BOOL * _Nullable)isOverride;\n\n+ (NSNumber *)hashForString:(NSString *)inputString colorStyle:(TPCThemeSettingsNicknameColorStyle)colorStyle;\n\n+ (nullable NSColor *)nicknameColorStyleOverrideForKey:(NSString *)styleKey;\n+ (void)setNicknameColorStyleOverride:(nullable NSColor *)styleValue forKey:(NSString *)styleKey;\n\n+ (void)migrateNicknameColorStyleOverrides;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCUserPersistentStorePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* IRCUserPersistentStore is a class used by IRCUser to store\n properties which are persistent between multiple read-only \n and mutable copies of the same IRCUser instance. */\n@class IRCUserRelations;\n\n@interface IRCUserPersistentStore : NSObject\n@property (nonatomic, strong) IRCUserRelations *relations;\n@property (nonatomic, assign) CFAbsoluteTime presentAwayMessageFor301LastEvent;\n@property (nonatomic, strong) dispatch_source_t removeUserTimer;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCUserPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCUser.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCUser ()\n- (IRCClient *)client;\n\n- (void)cancelRemoveUserTimer;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCUserRelationsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelUser.h\"\n#import \"IRCUserRelations.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* IRCUserRelations is a class used by IRCUser to store which\n IRCChannelUser object is associated with a particular channel. */\n@interface IRCUserRelations : NSObject\n@property (readonly, copy) NSArray<IRCChannel *> *relatedChannels;\n@property (readonly, copy) NSArray<IRCChannelUser *> *relatedUsers;\n@property (readonly, copy) NSDictionary<IRCChannel *, IRCChannelUser *> *relations;\n\n@property (readonly) NSUInteger numberOfRelations;\n\n- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel;\n- (void)disassociateUserWithChannel:(IRCChannel *)channel;\n\n- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel;\n\n- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block;\n@end\n\n#pragma mark -\n\n/* Acts as easy access for internal relations object */\n@interface IRCUser (IRCUserRelationsPrivate)\n- (void)becamePrimaryUser;\n\n- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel;\n- (void)disassociateUserWithChannel:(IRCChannel *)channel;\n\n- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel;\n\n- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block;\n@end\n\n@interface IRCChannelUser (IRCUserRelationsPrivate)\n- (void)associateWithChannel:(IRCChannel *)channel;\n- (void)disassociateWithChannel:(IRCChannel *)channel;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/IRCWorldPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelConfigPrivate.h\"\n#import \"IRCWorld.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCWorld ()\n@property (nonatomic, assign, readwrite) NSUInteger messagesSent;\n@property (nonatomic, assign, readwrite) NSUInteger messagesReceived;\n@property (nonatomic, assign, readwrite) uint64_t bandwidthIn;\n@property (nonatomic, assign, readwrite) uint64_t bandwidthOut;\n@property (nonatomic, assign) BOOL isImportingConfiguration;\n@property (nonatomic, copy, readwrite) NSArray<IRCClient *> *clientList;\n\n- (void)setupConfiguration;\n\n- (nullable IRCTreeItem *)findItemWithPasteboardString:(NSString *)string;\n- (NSString *)pasteboardStringForItem:(IRCTreeItem *)item;\n\n- (void)autoConnectAfterWakeup:(BOOL)afterWakeUp;\n\n- (void)prepareForSleep;\n\n- (void)prepareForScreenSleep;\n- (void)wakeFromScreenSleep;\n\n- (void)noteReachabilityChanged:(BOOL)reachable;\n\n- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config reload:(BOOL)reload;\n- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client add:(BOOL)add adjust:(BOOL)adjust reload:(BOOL)reload;\n\n- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client asType:(IRCChannelType)type;\n\n- (void)destroyClient:(IRCClient *)client;\n\n- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload;\n- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload part:(BOOL)partChannel;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/NSTableVIewHelperPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSTableView (TXTableViewHelper)\n+ (NSFont *)preferredGlobalTableViewFont;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/NSViewHelperPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindow;\n\n@interface NSView (TXViewHelperPrivate)\n/* If this view is attached to an instance of TXMainWindow,\n then this returns the instance its attached to. */\n@property (readonly, nullable) TVCMainWindow *mainWindow;\n@end\n\n@interface NSCell (TXCellHelperPrivate)\n@property (readonly, nullable) NSWindow *window;\n@property (readonly, nullable) TVCMainWindow *mainWindow;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TextualPrivate.h\"\n\n// TLOpenLink.swift\n#import \"TPCPreferencesLocal.h\"\n\n// TLOLinkParser.swift\n#import \"TVCLogLine.h\"\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCAboutDialogPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol TDCAboutDialogDelegate;\n\n@interface TDCAboutDialog : TDCWindowBase\n@end\n\n@protocol TDCAboutDialogDelegate <NSObject>\n@required\n\n- (void)aboutDialogWillClose:(TDCAboutDialog *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCAddressBookSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCAddressBook.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol TDCAddressBookSheetDelegate;\n\n@interface TDCAddressBookSheet : TDCSheetBase\n- (instancetype)initWithEntryType:(IRCAddressBookEntryType)entryType NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithConfig:(IRCAddressBookEntry *)config NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCAddressBookSheetDelegate <NSObject>\n@required\n\n- (void)addressBookSheet:(TDCAddressBookSheet *)sender onOk:(IRCAddressBookEntry *)config;\n- (void)addressBookSheetWillClose:(TDCAddressBookSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelBanListSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCISupportInfo.h\"\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\ntypedef NS_ENUM(NSUInteger, TDCChannelBanListSheetEntryType) {\n\tTDCChannelBanListSheetEntryTypeBan = IRCISupportInfoListTypeBan,\n\tTDCChannelBanListSheetEntryTypeBanException = IRCISupportInfoListTypeBanException,\n\tTDCChannelBanListSheetEntryTypeInviteException = IRCISupportInfoListTypeInviteException,\n\tTDCChannelBanListSheetEntryTypeQuiet = IRCISupportInfoListTypeQuiet\n};\n\n@interface TDCChannelBanListSheet : TDCSheetBase <TDCChannelPrototype>\n@property (readonly) TDCChannelBanListSheetEntryType entryType;\n@property (readonly, copy) NSString *modeSymbol;\n@property (readonly, copy, nullable) NSArray<NSString *> *listOfChanges;\n@property (nonatomic, assign) BOOL contentAlreadyReceived;\n\n/* Returns nil if entry type is not supported by client */\n- (nullable instancetype)initWithEntryType:(TDCChannelBanListSheetEntryType)entryType inChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n\n- (void)clear;\n\n- (void)addEntry:(NSString *)entryMask setBy:(nullable NSString *)entryAuthor creationDate:(nullable NSDate *)entryCreationDate;\n@end\n\n@protocol TDCChannelBanListSheetDelegate <NSObject>\n@required\n\n- (void)channelBanListSheetOnUpdate:(TDCChannelBanListSheet *)sender;\n- (void)channelBanListSheetWillClose:(TDCChannelBanListSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelInviteSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@interface TDCChannelInviteSheet : TDCSheetBase <TDCClientPrototype>\n@property (readonly, copy) NSArray<NSString *> *nicknames;\n\n- (instancetype)initWithNicknames:(NSArray<NSString *> *)nicknames onClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)startWithChannels:(NSArray<NSString *> *)channels;\n@end\n\n@protocol TDCChannelInviteSheetDelegate <NSObject>\n@required\n\n- (void)channelInviteSheet:(TDCChannelInviteSheet *)sender onSelectChannel:(NSString *)channelName;\n- (void)channelInviteSheetWillClose:(TDCChannelInviteSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelModifyModesSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel, IRCChannelModeContainer;\n\n@interface TDCChannelModifyModesSheet : TDCSheetBase <TDCChannelPrototype>\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCChannelModifyModesSheetDelegate <NSObject>\n@required\n\n- (void)channelModifyModesSheet:(TDCChannelModifyModesSheet *)sender onOk:(IRCChannelModeContainer *)modes;\n- (void)channelModifyModesSheetWillClose:(TDCChannelModifyModesSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelModifyTopicSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\n@interface TDCChannelModifyTopicSheet : TDCSheetBase <TDCChannelPrototype>\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCChannelModifyTopicSheetDelegate <NSObject>\n@required\n\n- (void)channelModifyTopicSheet:(TDCChannelModifyTopicSheet *)sender onOk:(NSString *)topic;\n- (void)channelModifyTopicSheetWillClose:(TDCChannelModifyTopicSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelPropertiesNotificationConfigurationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCChannelPropertiesSheetPrivate.h\"\n#import \"TLONotificationController.h\"\n#import \"TLONotificationConfigurationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelPropertiesNotificationConfiguration : TLONotificationConfiguration\n- (instancetype)initWithEventType:(TXNotificationType)aEventType inSheet:(TDCChannelPropertiesSheet *)sheet;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelPropertiesSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCChannelConfig;\n\n@protocol TDCChannelPropertiesSheetDelegate;\n\n@interface TDCChannelPropertiesSheet : TDCSheetBase <TDCChannelPrototype>\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (instancetype)initWithClient:(IRCClient *)client;\n- (instancetype)initWithClientId:(NSString *)clientId;\n\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config;\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClientWithId:(nullable NSString *)clientId;\n\n- (instancetype)initWithConfig:(nullable IRCChannelConfig *)config onClient:(nullable IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCChannelPropertiesSheetDelegate <NSObject>\n@required\n\n- (void)channelPropertiesSheet:(TDCChannelPropertiesSheet *)sender onOk:(IRCChannelConfig *)config;\n- (void)channelPropertiesSheetWillClose:(TDCChannelPropertiesSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelSpotlightAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightAppearance : TVCApplicationAppearance\n#pragma mark -\n#pragma mark Search Field\n\n@property (readonly, copy, nullable) NSColor *searchFieldTextColor;\n@property (readonly, copy, nullable) NSColor *searchFieldCompletionTextColor;\n@property (readonly, copy, nullable) NSColor *searchFieldNoResultsTextColor;\n\n#pragma mark -\n#pragma mark Search Result\n\n@property (readonly, copy, nullable) NSColor *searchResultRowSelectionColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *searchResultRowSelectionColorInactiveWindow;\n@property (readonly) BOOL searchResultRowEmphasized;\n@property (readonly, copy, nullable) NSColor *searchResultChannelNameTextColor;\n@property (readonly, copy, nullable) NSColor *searchResultChannelDescriptionTextColor;\n@property (readonly, copy, nullable) NSColor *searchResultKeyboardShortcutTextColor;\n@property (readonly) CGFloat searchResultKeyboardShortcutDeselectedOffset;\n@property (readonly) CGFloat searchResultKeyboardShortcutSelectedOffset;\n@property (readonly, copy, nullable) NSColor *searchResultSelectedTextColor;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelSpotlightControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\n@protocol TDCChannelSpotlightControllerDelegate;\n\n@interface TDCChannelSpotlightController : TDCWindowBase\n@end\n\n@protocol TDCChannelSpotlightControllerDelegate <NSObject>\n@required\n\n- (void)channelSpotlightController:(TDCChannelSpotlightController *)sender selectChannel:(IRCChannel *)channel;\n- (void)channelSpotlightControllerWillClose:(TDCChannelSpotlightController *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelSpotlightControlsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCChannelSpotlightPanel : NSPanel\n@end\n\n@interface TDCChannelSpotlightTextField : NSTextField\n@end\n\n@interface TDCChannelSpotlightImageView : NSImageView\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelSpotlightSearchResultPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel, TDCChannelSpotlightController;\n\n@interface TDCChannelSpotlightSearchResult : NSObject\n@property (readonly, weak) IRCChannel *channel;\n@property (readonly, copy) NSString *clientId;\n@property (readonly, copy) NSNumber *distance;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)recalculateDistanceWith:(NSString *)searchString;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCChannelSpotlightSearchResultsTablePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TDCChannelSpotlightController;\n\n@interface TDCChannelSpotlightSearchResultRowView : NSTableRowView\n- (instancetype)initWithController:(TDCChannelSpotlightController *)controller;\n@end\n\n@interface TDCChannelSpotlightSearchResultCellView : NSTableCellView\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCFileTransferDialogPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, TDCFileTransferDialogTransferController, TVCBasicTableView;\n\ntypedef NS_ENUM(NSUInteger, TDCFileTransferDialogTransferStatus) {\n\tTDCFileTransferDialogTransferStatusComplete,\n\tTDCFileTransferDialogTransferStatusConnecting,\n\tTDCFileTransferDialogTransferStatusFatalError,\n\tTDCFileTransferDialogTransferStatusInitializing,\n\tTDCFileTransferDialogTransferStatusIsListeningAsReceiver,\n\tTDCFileTransferDialogTransferStatusIsListeningAsSender,\n\tTDCFileTransferDialogTransferStatusMappingListeningPort,\n\tTDCFileTransferDialogTransferStatusReceiving,\n\tTDCFileTransferDialogTransferStatusRecoverableError,\n\tTDCFileTransferDialogTransferStatusSending,\n\tTDCFileTransferDialogTransferStatusStopped,\n\tTDCFileTransferDialogTransferStatusWaitingForLocalIPAddress,\n\tTDCFileTransferDialogTransferStatusWaitingForReceiverToAccept,\n\tTDCFileTransferDialogTransferStatusWaitingForResumeAccept\n};\n\ntypedef NS_ENUM(NSUInteger, TDCFileTransferDialogSelection) {\n\tTDCFileTransferDialogSelectionAll\t\t\t= 0,\n\tTDCFileTransferDialogSelectionSending\t\t= 1,\n\tTDCFileTransferDialogSelectionReceiving\t\t= 2\n};\n\n@class TDCFileTransferDialogTransferController;\n\n@interface TDCFileTransferDialog : TDCWindowBase\n@property (readonly, weak) TVCBasicTableView *fileTransferTable;\n@property (readonly, copy, nullable) NSString *IPAddress;\n\n- (void)show:(BOOL)makeKeyWindow;\n- (void)show:(BOOL)makeKeyWindow restorePosition:(BOOL)restorePosition;\n\n- (void)requestIPAddress; // from external source\n- (void)clearIPAddress;\n\n/* The next two method return a unique identifier specific to each\n added request. This identifier is different from a request token\n as it is available always and never is seen by the other user. \n It is used internally for finding specific requests. */\n/* Returning nil means that something failed and the transfer was\n never added to list of transfers. */\n- (nullable NSString *)addReceiverForClient:(IRCClient *)client\n\t\t\t\t\t\t\t\t   nickname:(NSString *)nickname\n\t\t\t\t\t\t\t\t\taddress:(NSString *)hostAddress\n\t\t\t\t\t\t\t\t\t   port:(uint16_t)hostPort\n\t\t\t\t\t\t\t\t   filename:(NSString *)filename\n\t\t\t\t\t\t\t\t   filesize:(uint64_t)totalFilesize\n\t\t\t\t\t\t\t\t\t  token:(nullable NSString *)transferToken;\n\n- (nullable NSString *)addSenderForClient:(IRCClient *)client\n\t\t\t\t\t\t\t\t nickname:(NSString *)nickname\n\t\t\t\t\t\t\t\t\t path:(NSString *)path\n\t\t\t\t\t\t\t\t autoOpen:(BOOL)autoOpen;\n\n- (BOOL)fileTransferExistsWithToken:(NSString *)transferToken;\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferMatchingPort:(uint16_t)port;\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferSenderMatchingToken:(NSString *)transferToken;\n- (nullable TDCFileTransferDialogTransferController *)fileTransferReceiverMatchingToken:(NSString *)transferToken;\n\n- (nullable TDCFileTransferDialogTransferController *)fileTransferWithUniqueIdentifier:(NSString *)identifier;\n@end\n\n#pragma mark -\n\n@interface TDCFileTransferDialog (TDCFileTransferDialogDownloadDestinationExtension)\n- (nullable NSURL *)downloadDestinationURL;\n\n- (void)setDownloadDestinationURL:(nullable NSData *)downloadDestinationURL;\n\n- (void)startUsingDownloadDestinationURL;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCFileTransferDialogTableCellPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCFileTransferDialogTableCell : NSTableCellView\n- (void)onMaintenanceTimer;\n\n- (void)reloadStatusInformation;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCFileTransferDialogTransferControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, TDCFileTransferDialogTableCell;\n\n@interface TDCFileTransferDialogTransferController : NSObject <TDCClientPrototype>\n@property (nonatomic, weak) TDCFileTransferDialogTableCell *transferTableCell;\n\n@property (readonly) BOOL isResume;\n@property (readonly) BOOL isReversed;\n@property (readonly) BOOL isSender;\n@property (readonly) TDCFileTransferDialogTransferStatus transferStatus;\n@property (readonly) uint64_t totalFilesize;\n@property (readonly) uint64_t processedFilesize;\n@property (readonly) uint64_t currentRecord;\n@property (readonly, copy) NSArray<NSNumber *> *speedRecords;\n@property (readonly, copy, nullable) NSString *errorMessageDescription;\n@property (readonly, copy, nullable) NSString *path;\n@property (readonly, copy) NSString *filename;\n@property (readonly, copy, nullable) NSString *filePath;\n@property (readonly, copy, nullable) NSURL *fileURL;\n@property (readonly, copy) NSString *hostAddress;\n@property (readonly, copy) NSString *peerNickname;\n@property (readonly, copy, nullable) NSString *transferToken;\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly) uint16_t hostPort;\n@property (getter=isActingAsClient, readonly) BOOL actingAsClient;\n@property (getter=isActingAsServer, readonly) BOOL actingAsServer;\n\n+ (nullable instancetype)receiverForClient:(IRCClient *)client\n\t\t\t\t\t\t\t\t  nickname:(NSString *)nickname\n\t\t\t\t\t\t\t\t   address:(NSString *)hostAddress\n\t\t\t\t\t\t\t\t\t  port:(uint16_t)hostPort\n\t\t\t\t\t\t\t\t  filename:(NSString *)filename\n\t\t\t\t\t\t\t\t  filesize:(uint64_t)totalFilesize\n\t\t\t\t\t\t\t\t\t token:(nullable NSString *)transferToken;\n\n+ (nullable instancetype)senderForClient:(IRCClient *)client\n\t\t\t\t\t\t\t\tnickname:(NSString *)nickname\n\t\t\t\t\t\t\t\t\tpath:(NSString *)path;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (void)open;\n- (void)openWithPathOrUserDownloads;\n- (void)openWithPath:(nullable NSString *)path; // Only changes path if self.path == nil\n\n- (void)close;\n- (void)closeAndPostNotification:(BOOL)postNotification;\n\n- (void)sendTransferRequestToClient;\n\n- (void)noteIPAddressLookupFailed;\n- (void)noteIPAddressLookupSucceeded;\n\n- (void)didReceiveSendRequest:(NSString *)hostAddress hostPort:(uint16_t)hostPort;\n\n- (void)didReceiveResumeAccept:(uint64_t)proposedPosition;\n- (void)didReceiveResumeRequest:(uint64_t)proposedPosition;\n\n- (void)onMaintenanceTimer;\n\n- (void)updateClearButton;\n\n- (void)reloadStatusInformation;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCHighlightEntrySheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelConfig, IRCHighlightMatchCondition;\n\n@interface TDCHighlightEntrySheet : TDCSheetBase\n- (instancetype)initWithConfig:(nullable IRCHighlightMatchCondition *)config NS_DESIGNATED_INITIALIZER;\n\n- (void)startWithChannels:(NSArray<IRCChannelConfig *> *)channels;\n@end\n\n@protocol TDCHighlightEntrySheetDelegate <NSObject>\n@required\n\n- (void)highlightEntrySheet:(TDCHighlightEntrySheet *)sender onOk:(IRCHighlightMatchCondition *)config;\n- (void)highlightEntrySheetWillClose:(TDCHighlightEntrySheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseManagerDialogPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\nTEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerActivatedLicenseNotification;\nTEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerDeactivatedLicenseNotification;\nTEXTUAL_EXTERN NSNotificationName const TDCLicenseManagerTrialExpiredNotification;\n\n@interface TDCLicenseManagerDialog : TDCWindowBase\n- (void)activateLicenseKey:(NSString *)licenseKey;\n- (void)activateLicenseKey:(NSString *)licenseKey silently:(BOOL)silently;\n\n- (NSString *)timeRemainingInTrialFormattedMessage;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseManagerMigrateAppStoreSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseManagerMigrateAppStoreSheet : TDCSheetBase\n- (void)start;\n@end\n\n@protocol TDCLicenseManagerMigrateAppStoreSheetDelegate <NSObject>\n@required\n\n- (void)licenseManagerMigrateAppStoreSheet:(TDCLicenseManagerMigrateAppStoreSheet *)sender\n\t\t\t\t\t\t\tconvertReceipt:(NSString *)receiptData\n\t\t\t\t\t\t  licenseOwnerName:(NSString *)licenseOwnerName\n\t\t\t\tlicenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress;\n\n- (void)licenseManagerMigrateAppStoreSheetWillClose:(TDCLicenseManagerMigrateAppStoreSheet *)sender;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseManagerRecoverLostLicenseSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseManagerRecoverLostLicenseSheet : TDCSheetBase\n- (void)start;\n@end\n\n@protocol TDCLicenseManagerRecoverLostLicenseSheet <NSObject>\n@required\n\n- (void)licenseManagerRecoverLostLicenseSheet:(TDCLicenseManagerRecoverLostLicenseSheet *)sender onOk:(NSString *)contactAddress;\n- (void)licenseManagerRecoverLostLicenseSheetWillClose:(TDCLicenseManagerRecoverLostLicenseSheet *)sender;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseUpgradeActivateSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n#import \"TDCLicenseUpgradeEligibilitySheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@protocol TDCLicenseUpgradeActivateSheetDelegate;\n\n@interface TDCLicenseUpgradeActivateSheet : TDCSheetBase\n@property (readonly, copy) NSString *licenseKey;\n@property (readonly) TLOLicenseUpgradeEligibility eligibility;\n\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey\n\t\t\t\t\t   eligibility:(TLOLicenseUpgradeEligibility)eligibility NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCLicenseUpgradeActivateSheetDelegate <NSObject>\n@required\n\n- (void)upgradeActivateSheetActivateLicense:(TDCLicenseUpgradeActivateSheet *)sender;\n- (void)upgradeActivateSheetPurchaseUpgrade:(TDCLicenseUpgradeActivateSheet *)sender;\n- (void)upgradeActivateSheetSuppressed:(TDCLicenseUpgradeActivateSheet *)sender;\n- (void)upgradeActivateSheetWillClose:(TDCLicenseUpgradeActivateSheet *)sender;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseUpgradeCommonActionsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TDCLicenseUpgradeCommonActions : NSObject\n+ (void)contactSupport;\n+ (void)activateLicense:(NSString *)licenseKey;\n+ (void)purchaseUpgradeForLicense:(NSString *)licenseKey;\n+ (void)learnMore;\n+ (void)openStandaloneStore;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseUpgradeDialogPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n#import \"TLOLicenseManagerLastGenPrivate.h\"\n#import \"TDCLicenseUpgradeEligibilitySheetPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@protocol TDCLicenseUpgradeDialogDelegate;\n\n@interface TDCLicenseUpgradeDialog : TDCWindowBase\n@property (readonly, copy) NSString *licenseKey;\n@property (readonly) TLOLicenseUpgradeEligibility eligibility;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey NS_DESIGNATED_INITIALIZER;\n@end\n\n@protocol TDCLicenseUpgradeDialogDelegate <NSObject>\n@required\n\n- (void)licenseUpgradeDialogEligibilityChanged:(TDCLicenseUpgradeDialog *)sender;\n- (void)licenseUpgradeDialogWRemindMeLater:(TDCLicenseUpgradeDialog *)sender;\n- (void)licenseUpgradeDialogWillClose:(TDCLicenseUpgradeDialog *)sender;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCLicenseUpgradeEligibilitySheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\ntypedef NS_ENUM(NSUInteger, TLOLicenseUpgradeEligibility) {\n\tTLOLicenseUpgradeEligibilityUnknown = LONG_MAX,\n\tTLOLicenseUpgradeEligibilityNot = 0,\n\tTLOLicenseUpgradeEligibilityDiscount = 1,\n\tTLOLicenseUpgradeEligibilityFree = 3,\n\tTLOLicenseUpgradeEligibilityAlreadyUpgraded = 2,\n};\n\n@protocol TDCLicenseUpgradeEligibilitySheetDelegate;\n\n@interface TDCLicenseUpgradeEligibilitySheet : TDCSheetBase\n@property (readonly, copy) NSString *licenseKey;\n@property (readonly) TLOLicenseUpgradeEligibility eligibility;\n\n- (instancetype)initWithLicenseKey:(NSString *)licenseKey NS_DESIGNATED_INITIALIZER;\n\n- (void)checkEligibility;\n@end\n\n@protocol TDCLicenseUpgradeEligibilitySheetDelegate <NSObject>\n@required\n\n- (void)upgradeEligibilitySheetContactSupport:(TDCLicenseUpgradeEligibilitySheet *)sender;\n- (void)upgradeEligibilitySheetActivateLicense:(TDCLicenseUpgradeEligibilitySheet *)sender;\n- (void)upgradeEligibilitySheetPurchaseUpgrade:(TDCLicenseUpgradeEligibilitySheet *)sender;\n- (void)upgradeEligibilitySheetPurchaseStandalone:(TDCLicenseUpgradeEligibilitySheet *)sender;\n- (void)upgradeEligibilitySheetChanged:(TDCLicenseUpgradeEligibilitySheet *)sender;\n- (void)upgradeEligibilitySheetWillClose:(TDCLicenseUpgradeEligibilitySheet *)sender;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCNicknameColorSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCNicknameColorSheet : TDCSheetBase\n- (instancetype)initWithNickname:(NSString *)nickname NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCNicknameColorSheetDelegate <NSObject>\n@required\n\n- (void)nicknameColorSheetOnOk:(TDCNicknameColorSheet *)sender;\n- (void)nicknameColorSheetWillClose:(TDCNicknameColorSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCPreferencesControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TDCPreferencesControllerSelection) {\n\tTDCPreferencesControllerSelectionDefault = 0,\n\tTDCPreferencesControllerSelectionNotifications,\n\tTDCPreferencesControllerSelectionStyle,\n\tTDCPreferencesControllerSelectionHiddenPreferences\n};\n\n@protocol TDCPreferencesControllerDelegate;\n\n@interface TDCPreferencesController : TDCWindowBase\n+ (void)openProxySettingsInSystemPreferences;\n\n- (void)show:(TDCPreferencesControllerSelection)selection;\n@end\n\n@protocol TDCPreferencesControllerDelegate <NSObject>\n@required\n\n- (void)preferencesDialogWillClose:(TDCPreferencesController *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCPreferencesNotificationConfigurationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n#import \"TLONotificationConfigurationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCPreferencesNotificationConfiguration : TLONotificationConfiguration\n+ (TDCPreferencesNotificationConfiguration *)objectWithEventType:(TXNotificationType)eventType;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCPreferencesUserStyleSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCPreferencesUserStyleSheet : TDCSheetBase\n- (void)start;\n@end\n\n@protocol TDCPreferencesUserStyleSheetDelegate <NSObject>\n@required\n\n- (void)userStyleSheetRulesChanged:(TDCPreferencesUserStyleSheet *)sender;\n- (void)userStyleSheetWillClose:(TDCPreferencesUserStyleSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCProgressIndicatorSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCProgressIndicatorSheet : TDCSheetBase\n- (void)start;\n- (void)stop;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerChangeNicknameSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@interface TDCServerChangeNicknameSheet : TDCSheetBase <TDCClientPrototype>\n- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TDCServerChangeNicknameSheetDelegate <NSObject>\n@required\n\n- (void)serverChangeNicknameSheet:(TDCServerChangeNicknameSheet *)sender didInputNickname:(NSString *)nickname;\n- (void)serverChangeNicknameSheetWillClose:(TDCServerChangeNicknameSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerChannelListDialogPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCWindowBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@protocol TDCServerChannelListDialogDelegate;\n\n@interface TDCServerChannelListDialog : TDCWindowBase <TDCClientPrototype>\n@property (nonatomic, assign) BOOL contentAlreadyReceived;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)clear;\n\n- (void)addChannel:(NSString *)channel count:(NSUInteger)count topic:(nullable NSString *)topic;\n@end\n\n@protocol TDCServerChannelListDialogDelegate <NSObject>\n@required\n\n- (void)serverChannelListDialogOnUpdate:(TDCServerChannelListDialog *)sender;\n- (void)serverChannelListDialog:(TDCServerChannelListDialog *)sender joinChannels:(NSArray<NSString *> *)channels;\n- (void)serverChannelDialogWillClose:(TDCServerChannelListDialog *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerEndpointListSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCServer;\n\n@protocol TDCServerEndpointListSheetDelegate;\n\n@interface TDCServerEndpointListSheet : TDCSheetBase\n- (void)startWithServerList:(NSArray<IRCServer *> *)serverList;\n@end\n\n@protocol TDCServerEndpointListSheetDelegate <NSObject>\n@required\n\n- (void)serverEndpointListSheet:(TDCServerEndpointListSheet *)ender onOk:(NSArray<IRCServer *> *)serverList;\n- (void)serverEndpointListSheetWillClose:(TDCServerEndpointListSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerEndpointListSheetTablePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCServerEndpointListSheetTableCellView : NSTableCellView\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerHighlightListSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@interface TDCServerHighlightListSheet : TDCSheetBase <TDCClientPrototype>\n- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n\n- (void)addEntry:(id)newEntry;\n@end\n\n@protocol TDCServerHighlightListSheetDelegate <NSObject>\n@required\n\n- (void)serverHighlightListSheetWillClose:(TDCServerHighlightListSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCServerPropertiesSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCClientConfig;\n\ntypedef NS_ENUM(NSUInteger, TDCServerPropertiesSheetSelection) {\n\tTDCServerPropertiesSheetSelectionDefault = 0,\n\n\tTDCServerPropertiesSheetSelectionAddressBook = 1,\n\tTDCServerPropertiesSheetSelectionAutojoin = 2,\n\tTDCServerPropertiesSheetSelectionConnectCommands = 3,\n\tTDCServerPropertiesSheetSelectionEncoding = 4,\n\tTDCServerPropertiesSheetSelectionGeneral = 5,\n\tTDCServerPropertiesSheetSelectionIdentity = 6,\n\tTDCServerPropertiesSheetSelectionHighlights = 7,\n\tTDCServerPropertiesSheetSelectionDisconnectMessages = 8,\n\tTDCServerPropertiesSheetSelectionZncBouncer = 10,\n\tTDCServerPropertiesSheetSelectionClientCertificate = 12,\n\tTDCServerPropertiesSheetSelectionFloodControl = 13,\n\tTDCServerPropertiesSheetSelectionNetworkSocket = 14,\n\tTDCServerPropertiesSheetSelectionProxyServer = 15,\n\tTDCServerPropertiesSheetSelectionRedundancy = 16,\n\n\tTDCServerPropertiesSheetSelectionNewIgnoreEntry = 200\n};\n\n@protocol TDCServerPropertiesSheetDelegate;\n\n@interface TDCServerPropertiesSheet : TDCSheetBase <TDCClientPrototype>\n- (instancetype)initWithClient:(nullable IRCClient *)client NS_DESIGNATED_INITIALIZER;\n\n- (void)startWithSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context;\n@end\n\n@protocol TDCServerPropertiesSheetDelegate <NSObject>\n@required\n\n- (void)serverPropertiesSheet:(TDCServerPropertiesSheet *)sender onOk:(IRCClientConfig *)config;\n- (void)serverPropertiesSheetWillClose:(TDCServerPropertiesSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCSharedProtocolDefinitionsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel;\n\n@protocol TDCClientPrototype <NSObject>\n@required\n\n@property (readonly, strong, nullable) IRCClient *client;\n@property (readonly, copy, nullable) NSString *clientId;\n@end\n\n@protocol TDCChannelPrototype <NSObject, TDCClientPrototype>\n@required\n\n@property (readonly, strong, nullable) IRCChannel *channel;\n@property (readonly, copy, nullable) NSString *channelId;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TDCWelcomeSheetPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCSheetBase.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClientConfig;\n\n@interface TDCWelcomeSheet : TDCSheetBase\n- (void)start;\n@end\n\n@protocol TDCWelcomeSheetDelegate <NSObject>\n@required\n\n- (void)welcomeSheet:(TDCWelcomeSheet *)sender onOk:(IRCClientConfig *)config;\n- (void)welcomeSheetWillClose:(TDCWelcomeSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/THOPluginDispatcherPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCPrefix, IRCMessage;\n@class TVCLogController;\n\n@class THOPluginDidPostNewMessageConcreteObject;\n@class THOPluginWebViewJavaScriptPayloadConcreteObject;\n\n@interface THOPluginDispatcher : NSObject\n+ (dispatch_queue_t)dispatchQueue;\n\n+ (BOOL)receivedCommand:(NSString *)command withText:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt referenceMessage:(nullable IRCMessage *)referenceMessage;\n+ (BOOL)receivedText:(NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination asLineType:(TVCLogLineType)lineType onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt wasEncrypted:(BOOL)wasEncrypted;\n+ (nullable IRCMessage *)interceptServerInput:(IRCMessage *)inputObject for:(IRCClient *)client;\n+ (nullable id)interceptUserInput:(id)inputObject command:(IRCRemoteCommand)commandString;\n+ (NSString *)willRenderMessage:(NSString *)newMessage forViewController:(TVCLogController *)viewController lineType:(TVCLogLineType)lineType memberType:(TVCLogLineMemberType)memberType;\n+ (void)userInputCommandInvokedOnClient:(IRCClient *)client commandString:(NSString *)commandString messageString:(NSString *)messageString;\n+ (void)didReceiveJavaScriptPayload:(THOPluginWebViewJavaScriptPayloadConcreteObject *)payloadObject fromViewController:(TVCLogController *)viewController;\n+ (void)didReceiveServerInput:(IRCMessage *)inputObject onClient:(IRCClient *)client;\n+ (void)enqueueDidPostNewMessage:(THOPluginDidPostNewMessageConcreteObject *)messageObject;\n+ (void)dequeueDidPostNewMessageWithLineNumber:(NSString *)messageLineNumber forViewController:(TVCLogController *)viewController;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/THOPluginItemPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class THOPluginOutputSuppressionRule;\n\ntypedef NS_OPTIONS(NSUInteger, THOPluginItemSupportedFeature) {\n\tTHOPluginItemSupportedFeatureDidReceiveCommandEvent\t\t\t\t= 1 << 1,\n\tTHOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent\t= 1 << 2,\n//\tTHOPluginItemSupportedFeatureInlineMediaManipulation\t\t\t= 1 << 3,\n\tTHOPluginItemSupportedFeatureNewMessagePostedEvent\t\t\t\t= 1 << 4,\n\tTHOPluginItemSupportedFeatureOutputSuppressionRules\t\t\t\t= 1 << 5,\n\tTHOPluginItemSupportedFeaturePreferencePane\t\t\t\t\t\t= 1 << 6,\n\tTHOPluginItemSupportedFeatureServerInputDataInterception\t\t= 1 << 7,\n\tTHOPluginItemSupportedFeatureSubscribedServerInputCommands\t\t= 1 << 8,\n\tTHOPluginItemSupportedFeatureSubscribedUserInputCommands\t\t= 1 << 9,\n\tTHOPluginItemSupportedFeatureUserInputDataInterception\t\t\t= 1 << 10,\n\tTHOPluginItemSupportedFeatureWebViewJavaScriptPayloads\t\t\t= 1 << 11,\n\tTHOPluginItemSupportedFeatureWillRenderMessageEvent\t\t\t\t= 1 << 12,\n};\n\n@interface THOPluginItem : NSObject\n@property (readonly, nullable) NSBundle *bundle;\n@property (readonly, nullable) id primaryClass;\n@property (readonly, assign) THOPluginItemSupportedFeature supportedFeatures;\n@property (readonly, copy, nullable) NSArray<NSString *> *supportedServerInputCommands;\n@property (readonly, copy, nullable) NSArray<NSString *> *supportedUserInputCommands;\n@property (readonly, copy, nullable) NSArray<THOPluginOutputSuppressionRule *> *outputSuppressionRules;\n@property (readonly, copy, nullable) NSString *pluginPreferencesPaneMenuItemTitle;\n@property (readonly, nullable) NSView *pluginPreferencesPaneView;\n\n- (BOOL)loadBundle:(NSBundle *)bundle;\n- (void)unloadBundle;\n\n- (BOOL)supportsFeature:(THOPluginItemSupportedFeature)feature;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/THOPluginManagerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"THOPluginItemPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class THOPluginOutputSuppressionRule;\n\nTEXTUAL_EXTERN NSNotificationName const THOPluginManagerFinishedLoadingPluginsNotification;\n\n@interface THOPluginManager : NSObject\n- (void)loadPlugins;\n- (void)unloadPlugins;\n\n@property (readonly) BOOL pluginsLoaded;\n\n@property (readonly, copy, nullable) NSArray<THOPluginItem *> *loadedPlugins; // nil until load completes\n\n@property (readonly, copy) NSArray<NSString *> *supportedServerInputCommands;\n@property (readonly, copy) NSArray<NSString *> *supportedUserInputCommands;\n\n@property (readonly, copy) NSArray<NSString *> *supportedAppleScriptCommands;\n@property (readonly, copy) NSDictionary<NSString *, NSString *> *supportedAppleScriptCommandsAndPaths;\n\n@property (readonly, copy) NSArray<THOPluginItem *> *pluginsWithPreferencePanes;\n\n@property (readonly, copy) NSArray<THOPluginOutputSuppressionRule *> *pluginOutputSuppressionRules;\n\n/* Returns YES if at least one loaded plugin supports the feature */\n- (BOOL)supportsFeature:(THOPluginItemSupportedFeature)feature;\n\n- (void)findHandlerForOutgoingCommand:(NSString *)command\n\t\t\t\t\t\t\t\t path:(NSString * _Nullable * _Nullable)path\n\t\t\t\t\t\t   isReserved:(BOOL *)isReserved\n\t\t\t\t\t\t\t isScript:(BOOL *)isScript\n\t\t\t\t\t\t  isExtension:(BOOL *)isExtension;\n\n- (void)extrasInstallerAskUserIfTheyWantToInstallCommand:(NSString *)command;\n- (void)extrasInstallerLaunchInstaller;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/THOPluginProtocolPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLine.h\"\n#import \"THOPluginProtocol.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface THOPluginDidPostNewMessageConcreteObject ()\n@property (nonatomic, assign, readwrite) BOOL isProcessedInBulk;\n@property (nonatomic, copy, readwrite) NSString *messageContents;\n@property (nonatomic, copy, readwrite) NSString *lineNumber;\n@property (nonatomic, copy, readwrite, nullable) NSString *senderNickname;\n@property (nonatomic, assign, readwrite) TVCLogLineType lineType;\n@property (nonatomic, assign, readwrite) TVCLogLineMemberType memberType;\n@property (nonatomic, copy, readwrite) NSDate *receivedAt;\n@property (nonatomic, copy, readwrite) NSArray<AHHyperlinkScannerResult *> *listOfHyperlinks;\n@property (nonatomic, copy, readwrite) NSSet<IRCChannelUser *> *listOfUsers;\n@property (nonatomic, assign, readwrite) BOOL keywordMatchFound;\n@end\n\n#pragma mark -\n\n@interface THOPluginDidReceiveServerInputConcreteObject ()\n@property (nonatomic, assign, readwrite) BOOL senderIsServer;\n@property (nonatomic, copy, readwrite) NSString *senderNickname;\n@property (nonatomic, copy, readwrite, nullable) NSString *senderUsername;\n@property (nonatomic, copy, readwrite, nullable) NSString *senderAddress;\n@property (nonatomic, copy, readwrite) NSString *senderHostmask;\n@property (nonatomic, copy, readwrite) NSDate *receivedAt;\n@property (nonatomic, copy, readwrite) NSString *messageSequence;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *messageParameters;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *messageParamaters;\n@property (nonatomic, copy, readwrite) NSString *messageCommand;\n@property (nonatomic, assign, readwrite) NSUInteger messageCommandNumeric;\n@property (nonatomic, copy, readwrite, nullable) NSString *networkAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *networkName;\n@end\n\n#pragma mark -\n\n@interface THOPluginWebViewJavaScriptPayloadConcreteObject ()\n@property (nonatomic, copy, readwrite) NSString *payloadLabel;\n@property (nonatomic, copy, readwrite, nullable) id payloadContents;\n@end\n\n#pragma mark -\n\n@interface NSObject (THOPluginProtocolExtension);\n- (BOOL)receivedCommand:(NSString *)command withText:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt referenceMessage:(nullable IRCMessage *)referenceMessage;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOEncryptionManagerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <EncryptionKit/EncryptionKit.h>\n\n#import \"TLOEncryptionManager.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, TVCMainWindowTitlebarAccessoryViewLockButton;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n#define sharedEncryptionManager()\t\t\t[TXSharedApplication sharedEncryptionManager]\n#endif\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@interface TLOEncryptionManager : NSObject\n/* Returns unique \"account name\" used for messageFrom and messageTo parameters */\n- (NSString *)accountNameForUser:(NSString *)nickname onClient:(IRCClient *)client;\n\n/* Converts the \"account name\" into its individual components */\n- (nullable NSString *)nicknameFromAccountName:(NSString *)accountName;\n- (nullable IRCClient *)connectionFromAccountName:(NSString *)accountName;\n\n/* Begin and end an encrypted conversation with a user */\n- (void)beginConversationWith:(NSString *)messageTo from:(NSString *)messageFrom;\n- (void)refreshConversationWith:(NSString *)messageTo from:(NSString *)messageFrom;\n- (void)endConversationWith:(NSString *)messageTo from:(NSString *)messageFrom;\n\n/* Socialist Millionaire Problem <http://en.wikipedia.org/wiki/Socialist_millionaire> */\n- (void)authenticateUser:(NSString *)messageTo from:(NSString *)messageFrom;\n\n/* Open dialog containing list of fingerprints */\n- (void)presentListOfFingerprints;\n\n/* State information */\n- (OTRKitMessageState)messageStateFor:(NSString *)messageTo from:(NSString *)messageFrom;\n\n- (void)updateLockIconButton:(TVCMainWindowTitlebarAccessoryViewLockButton *)button withStateOf:(NSString *)messageTo from:(NSString *)messageFrom;\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem withStateOf:(NSString *)messageTo from:(NSString *)messageFrom;\n\n- (BOOL)safeToTransferFile:(NSString *)filename to:(NSString *)messageTo from:(NSString *)messageFrom isIncomingFileTransfer:(BOOL)isIncomingFileTransfer;\n\n/* Define configuration options */\n- (void)updatePolicy;\n\n/* Encryption/Decryption */\n- (void)encryptMessage:(NSString *)messageBody\n\t\t\t\t  from:(NSString *)messageFrom\n\t\t\t\t\tto:(NSString *)messageTo\n\t  encodingCallback:(nullable TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback\n\t injectionCallback:(nullable TLOEncryptionManagerInjectCallbackBlock)injectionCallback;\n\n- (void)decryptMessage:(NSString *)messageBody\n\t\t\t\t  from:(NSString *)messageFrom\n\t\t\t\t\tto:(NSString *)messageTo\n\t  decodingCallback:(nullable TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOFileLoggerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCTreeItem, TVCLogLine;\n\nTEXTUAL_EXTERN NSString * const TLOFileLoggerConsoleDirectoryName;\nTEXTUAL_EXTERN NSString * const TLOFileLoggerChannelDirectoryName;\nTEXTUAL_EXTERN NSString * const TLOFileLoggerPrivateMessageDirectoryName;\n\nTEXTUAL_EXTERN NSString * const TLOFileLoggerUndefinedNicknameFormat;\nTEXTUAL_EXTERN NSString * const TLOFileLoggerActionNicknameFormat;\nTEXTUAL_EXTERN NSString * const TLOFileLoggerNoticeNicknameFormat;\n\nTEXTUAL_EXTERN NSString * const TLOFileLoggerISOStandardClockFormat;\n\n@interface TLOFileLogger : NSObject\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithClient:(IRCClient *)client NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithChannel:(IRCChannel *)channel NS_DESIGNATED_INITIALIZER;\n\n- (void)open;\n- (void)reopen;\n- (void)reopenIfNeeded;\n- (void)close;\n\n- (void)reset; // does nothing if file isn't open\n\n- (void)writeLogLine:(TVCLogLine *)logLine;\n- (void)writePlainText:(NSString *)string;\n\n#pragma mark -\n#pragma mark Paths\n\n/* All path information is nullable because path information\n is not cached until log file is opened */\n\n/* File path is the path to the log file for the day */\n/* At the time of a write after midnight, this path can be to a\n log file for the previous date. TLOFileLogger will correct that\n before writing. Be aware this is the case though if you access\n this property after midnight and before another write occurs.\n Unless a specific reason is needed to access this property,\n it may be better to use -writePath instead. */\n@property (readonly, copy, nullable) NSString *filePath;\n\n/* The last path component (file name) of file path */\n@property (readonly, copy, nullable) NSString *fileName;\n\n/* Write path is the path to the folder in which log files\n for the channel or client are written to. */\n@property (readonly, copy, nullable) NSString *writePath;\n\n/* -writePathForItem: only returns nil when there is no\n log location configured in Preferences. */\n+ (nullable NSString *)writePathForItem:(IRCTreeItem *)item;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOInputHistoryPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCTreeItem, TVCMainWindow;\n\n@interface TLOInputHistory : NSObject\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithWindow:(TVCMainWindow *)mainWindow NS_DESIGNATED_INITIALIZER;\n\n- (void)moveFocusTo:(IRCTreeItem *)treeItem;\n\n- (void)destroy:(IRCTreeItem *)treeItem;\n\n- (void)noteInputHistoryObjectScopeDidChange;\n\n- (void)add:(NSAttributedString *)string;\n\n- (nullable NSAttributedString *)up:(NSAttributedString *)string;\n- (nullable NSAttributedString *)down:(NSAttributedString *)string;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOLicenseManagerDownloaderPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TLOLicenseManagerDownloaderRequestType) {\n\tTLOLicenseManagerDownloaderRequestTypeActivation,\n\tTLOLicenseManagerDownloaderRequestTypeMigrateAppStore,\n\tTLOLicenseManagerDownloaderRequestTypeSendLostLicense,\n\tTLOLicenseManagerDownloaderRequestTypeLicenseUpgradeEligibility,\n\tTLOLicenseManagerDownloaderRequestTypeReceiptUpgradeEligibility\n};\n\nTEXTUAL_EXTERN NSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeSuccess;\nTEXTUAL_EXTERN NSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeGenericError;\nTEXTUAL_EXTERN NSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy;\n\ntypedef BOOL (^TLOLicenseManagerDownloaderActionBlock)(NSUInteger statusCode, id _Nullable statusContext);\ntypedef BOOL (^TLOLicenseManagerDownloaderErrorBlock)(NSUInteger statusCode, id _Nullable statusContext);\ntypedef void (^TLOLicenseManagerDownloaderCompletionBlock)(BOOL resultSuccessful, NSUInteger statusCode, id _Nullable statusContext);\n\n@interface TLOLicenseManagerDownloader : NSObject\n@property (nonatomic, copy, nullable) TLOLicenseManagerDownloaderActionBlock actionBlock;\n@property (nonatomic, copy, nullable) TLOLicenseManagerDownloaderActionBlock errorBlock;\n@property (nonatomic, copy, nullable) TLOLicenseManagerDownloaderCompletionBlock completionBlock;\n@property (nonatomic, assign) BOOL isSilentOnFailure;\n@property (nonatomic, assign) BOOL isSilentOnSuccess;\n\n- (void)activateLicense:(NSString *)licenseKey;\n\n- (void)deactivateLicense;\n\n- (void)checkUpgradeEligibilityOfLicense:(NSString *)licenseKey;\n- (void)checkUpgradeEligibilityOfReceipt:(NSString *)receiptData;\n\n- (void)requestLostLicenseKeyForContactAddress:(NSString *)contactAddress;\n\n- (void)migrateMacAppStorePurchase:(NSString *)receiptData\n\t\t\t\t  licenseOwnerName:(NSString *)licenseOwnerName\n\t\tlicenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress;\n\n- (void)cancelRequest;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOLicenseManagerLastGenPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* TLOLicenseManagerLastGen is a class because classes are easier to work with.\n TLOLicenseManager* functions are functions because a plugin can't override the\n logic of the functions as easily. There is no risk in security if\n TLOLicenseManagerLastGen is swizzled. */\n/* TLOLicenseManagerLastGen processes the old location for license file and\n returns license key from it if it is not the current generation. The class\n is also capable of doing the same for a data object so that the activation\n system can know whether a license key is old. */\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@interface TLOLicenseManagerLastGen : NSObject\n/* Only returns a value if license key is old. */\n+ (nullable NSString *)licenseKey; // From saved license file (last gen location)\n+ (nullable NSString *)licenseKeyForLicenseContents:(NSData *)licenseContents;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOLicenseManagerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TLOLicenseManagerActionResult) {\n\tTLOLicenseManagerActionResultSuccess, // Validated successfully and saved\n\tTLOLicenseManagerActionResultGenerationPrevious, // License is for previous version. Discount available?\n\tTLOLicenseManagerActionResultGenerationNext, // License is for next version. Maybe they should update.\n\tTLOLicenseManagerActionResultInvalidSignature, // License signature is invalid\n\tTLOLicenseManagerActionResultCannotRead, // License cannot be read from disk\n\tTLOLicenseManagerActionResultCannotWrite, // License cannot be written to disk\n\tTLOLicenseManagerActionResultMalformedData, // License data is not correct or complete\n\tTLOLicenseManagerActionResultOther // Other failure reason\n};\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\ntypedef NSString *TLOLicenseManagerLicenseDictionaryKey NS_EXTENSIBLE_STRING_ENUM;\n\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyCreationDate;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyGeneration;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyLicenseKey;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyProductName;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyOwnerContactAddress;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeyOwnerName;\nTEXTUAL_EXTERN TLOLicenseManagerLicenseDictionaryKey const TLOLicenseManagerLicenseDictionaryKeySignature;\n\nTEXTUAL_EXTERN NSUInteger const TLOLicenseManagerCurrentLicenseGeneration;\n\nTEXTUAL_EXTERN void TLOLicenseManagerSetup(void);\n\nTEXTUAL_EXTERN BOOL TLOLicenseManagerTextualIsRegistered(void);\n\nTEXTUAL_EXTERN BOOL TLOLicenseManagerIsTrialExpired(void);\nTEXTUAL_EXTERN NSTimeInterval TLOLicenseManagerTimeRemainingTrial(void);\n\nTEXTUAL_EXTERN TLOLicenseManagerActionResult TLOLicenseManagerDeleteLicenseFile(void);\nTEXTUAL_EXTERN TLOLicenseManagerActionResult TLOLicenseManagerWriteLicenseFileContents(NSData * _Nullable newContents);\n\nTEXTUAL_EXTERN BOOL TLOLicenseManagerLicenseKeyIsValid(NSString *licenseKey);\n\nTEXTUAL_EXTERN NSString * _Nullable TLOLicenseManagerLicenseCreationDate(void);\nTEXTUAL_EXTERN NSString * _Nullable TLOLicenseManagerLicenseCreationDateFormatted(void);\nTEXTUAL_EXTERN NSUInteger TLOLicenseManagerLicenseGeneration(void);\nTEXTUAL_EXTERN NSString * _Nullable TLOLicenseManagerLicenseKey(void);\nTEXTUAL_EXTERN NSString * _Nullable TLOLicenseManagerLicenseOwnerContactAddress(void);\nTEXTUAL_EXTERN NSString * _Nullable TLOLicenseManagerLicenseOwnerName(void);\n\nTEXTUAL_EXTERN NSString * TLOLicenseManagerAuthorizationCode(void);\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLONicknameCompletionStatusPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindow;\n\n@interface TLONicknameCompletionStatus : NSObject\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithWindow:(TVCMainWindow *)mainWindow NS_DESIGNATED_INITIALIZER;\n\n- (void)completeNickname:(BOOL)movingForward;\n\n- (void)clear;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLONotificationConfigurationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n  * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NSString *TLONotificationAlertSound NS_EXTENSIBLE_STRING_ENUM;\n\nTEXTUAL_EXTERN TLONotificationAlertSound const TXDefaultAlertSoundPreferenceValue;\nTEXTUAL_EXTERN TLONotificationAlertSound const TXNoAlertSoundPreferenceValue;\n\n@interface TLONotificationConfiguration : NSObject\n@property (readonly) TXNotificationType eventType;\n@property (readonly, copy) NSString *displayName;\n@property (nonatomic, copy, nullable) TLONotificationAlertSound alertSound;\n@property (nonatomic, assign) NSUInteger speakEvent;\n@property (nonatomic, assign) NSUInteger pushNotification;\n@property (nonatomic, assign) NSUInteger disabledWhileAway;\n@property (nonatomic, assign) NSUInteger bounceDockIcon;\n@property (nonatomic, assign) NSUInteger bounceDockIconRepeatedly;\n\n+ (NSString *)localizedAlertDefaultSoundTitle;\n+ (NSString *)localizedAlertNoSoundTitle;\n\n+ (instancetype)configurationWithEventType:(TXNotificationType)eventType;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithEventType:(TXNotificationType)aEventType NS_DESIGNATED_INITIALIZER;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLONotificationControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\nTEXTUAL_EXTERN NSString * const TXNotificationUserInfoClientIdentifierKey;\nTEXTUAL_EXTERN NSString * const TXNotificationUserInfoChannelIdentifierKey;\n\nTEXTUAL_EXTERN NSString * const TXNotificationDialogStandardNicknameFormat;\nTEXTUAL_EXTERN NSString * const TXNotificationDialogActionNicknameFormat;\n\nTEXTUAL_EXTERN NSString * const TXNotificationHighlightLogStandardActionFormat;\nTEXTUAL_EXTERN NSString * const TXNotificationHighlightLogStandardMessageFormat;\n\n@interface TLONotificationController ()\n/* All methods in this controller do not honor any user preference for\n silencing notifications. By the time a notification reaches this point,\n it is assumed that those related conditions have been checked. */\n\n/* This method will automatically configure the notification based on the\n event type such as setting a title or description. It will also perform\n formatter stripping if need be. In addition to properly separating\n notifications by threads. */\n- (void)notify:(TXNotificationType)eventType\n\t\t title:(nullable NSString *)eventTitle\n   description:(nullable NSString *)eventDescription\n\t  userInfo:(nullable NSDictionary<NSString *, id> *)eventContext;\n\n- (void)dismissNotificationsForChannel:(nullable IRCChannel *)channel onClient:(IRCClient *)client;\n\n/* These methods schedule notifications with the UserNotification.framework.\n Nothing more. -notify:title:description:userInfo: is the proper entry point\n for sending notifications related to IRC. These entry points are conveniences\n for sending unrelated notifications such as from the license manager or addons. */\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t onClient:(IRCClient *)client;\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t   forChannel:(IRCChannel *)channel;\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t   forChannel:(nullable IRCChannel *)channel\n\t\t\t\t\t\t\t onClient:(IRCClient *)client;\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t userInfo:(nullable NSDictionary<NSString *, id> *)userInfo;\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t userInfo:(nullable NSDictionary<NSString *, id> *)userInfo\n\t\t\t\t\t threadIdentifier:(NSString *)threadIdentifier;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOSpeechSynthesizerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient;\n\n@interface TLOSpeechSynthesizer : NSObject\n/* If stopped, any items supplied to speak: will be completely ignored. */\n/* Setting the synthesizer to stopped does not clear the queue. Just \n forces speaking to stop and does not allow additions. */\n@property (nonatomic, assign) BOOL isStopped;\n\n- (void)speak:(id)object; // NSString or TLOSpokeNotification\n\n- (void)clearQueue; // Does not stop speaking. Only clears pending items.\n- (void)clearQueueForClient:(IRCClient *)client;\n\n- (void)stopSpeakingAndMoveForward;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TLOSpokenNotificationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCTreeItem;\n\n@interface TLOSpokenNotification : NSObject\n@property (nonatomic, weak, null_unspecified, readonly) IRCClient *client;\n@property (nonatomic, weak, null_unspecified, readonly) IRCChannel *channel;\n@property (nonatomic, copy, null_unspecified, readonly) NSString *nickname;\n@property (nonatomic, copy, null_unspecified, readonly) NSString *text;\n@property (nonatomic, readonly) TVCLogLineType lineType;\n@property (nonatomic, readonly) TXNotificationType notificationType;\n\n- (instancetype)initWithNotification:(TXNotificationType)notificationType\n\t\t\t\t\t\t\tlineType:(TVCLogLineType)lineType\n\t\t\t\t\t\t\t  target:(null_unspecified IRCTreeItem *)target\n\t\t\t\t\t\t\tnickname:(null_unspecified NSString *)nickname\n\t\t\t\t\t\t\t\ttext:(null_unspecified NSString *)text;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCApplicationInfoPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCApplicationInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCApplicationInfo ()\n+ (void)saveTimeIntervalSinceApplicationInstall;\n\n+ (void)incrementApplicationRunCount;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCPathInfoPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPathInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPathInfo ()\n+ (void)_createDirectoryAtPath:(NSString *)directoryPath;\n+ (void)_createDirectoryAtURL:(NSURL *)directoryURL;\n@end\n\n@interface TPCPathInfo (TPCPathInfoTranscriptFolderExtension)\n@property (class, readonly, copy, nullable) NSString *transcriptFolder;\n@property (class, readonly, copy, nullable) NSURL *transcriptFolderURL;\n\n+ (void)setTranscriptFolderURL:(nullable NSData *)transcriptFolderURL;\n\n+ (void)startUsingTranscriptFolderURL;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCPreferencesImportExportPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesImportExport.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferencesImportExport ()\n+ (void)import:(id)object withKey:(NSString *)key;\n\n+ (void)importContentsOfDictionary:(NSDictionary<NSString *, id> *)aDict;\n+ (void)importClientConfiguration:(NSDictionary<NSString *, id> *)config;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCPreferencesLocalPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferences (TPCPreferencesLocalPrivate)\n+ (void)initPreferences;\n\n+ (void)setAppNapEnabled:(BOOL)appNapEnabled;\n\n+ (void)setDeveloperModeEnabled:(BOOL)developerModeEnabled;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n+ (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic;\n+ (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired;\n+ (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled;\n#endif\n\n+ (void)setLogToDisk:(BOOL)logToDisk;\n\n+ (void)setOnlySpeakEventsForSelection:(BOOL)onlySpeakEventsForSelection;\n\n+ (void)setChannelMessageSpeakChannelName:(BOOL)channelMessageSpeakChannelName;\n+ (void)setChannelMessageSpeakNickname:(BOOL)channelMessageSpeakNickname;\n\n+ (void)setHighlightCurrentNickname:(BOOL)highlightCurrentNickname;\n\n+ (void)setLocationToSendNotices:(TXNoticeSendLocation)locationToSendNotices;\n\n+ (void)setAppearance:(TXPreferredAppearance)appearance;\n\n+ (void)setThemeName:(NSString *)value;\n+ (void)setThemeNameWithExistenceCheck:(NSString *)value;\n\n+ (void)setThemeChannelViewFontName:(NSString *)value;\n+ (void)setThemeChannelViewFontNameWithExistenceCheck:(NSString *)value;\n\n+ (void)setThemeChannelViewFontSize:(CGFloat)value;\n\n+ (void)setThemeNicknameFormatPreferenceUserConfigurable:(BOOL)themeNicknameFormatPreferenceUserConfigurable;\n+ (void)setThemeTimestampFormatPreferenceUserConfigurable:(BOOL)themeTimestampFormatPreferenceUserConfigurable;\n+ (void)setThemeChannelViewFontPreferenceUserConfigurable:(BOOL)themeChannelViewFontPreferenceUserConfigurable;\n\n+ (void)setThemeUserStyleSheetRules:(nullable NSString *)themeUserStyleSheetRules;\n\n+ (void)setScrollbackSaveLimit:(NSUInteger)scrollbackSaveLimit;\n+ (void)setScrollbackVisibleLimit:(NSUInteger)scrollbackVisibleLimit;\n\n+ (void)setShowInlineMedia:(BOOL)showInlineMedia;\n\n+ (void)setSoundIsMuted:(BOOL)soundIsMuted;\n\n+ (void)setSound:(nullable NSString *)value forEvent:(TXNotificationType)event;\n\n+ (void)setNotificationEnabled:(BOOL)value forEvent:(TXNotificationType)event;\n+ (void)setDisabledWhileAway:(BOOL)value forEvent:(TXNotificationType)event;\n+ (void)setBounceDockIcon:(BOOL)value forEvent:(TXNotificationType)event;\n+ (void)setBounceDockIconRepeatedly:(BOOL)value forEvent:(TXNotificationType)event;\n+ (void)setEventIsSpoken:(BOOL)value forEvent:(TXNotificationType)event;\n\n+ (nullable NSString *)keyForEvent:(TXNotificationType)event category:(NSString *)category;\n\n+ (void)setFileTransferPortRangeStart:(uint16_t)value;\n+ (void)setFileTransferPortRangeEnd:(uint16_t)value;\n\n+ (void)setTabCompletionSuffix:(NSString *)value;\n\n+ (void)setClientList:(nullable NSArray<NSDictionary *> *)clientList;\n\n+ (void)cleanUpHighlightKeywords;\n\n+ (void)setTextFieldAutomaticSpellCheck:(BOOL)value;\n+ (void)setTextFieldAutomaticGrammarCheck:(BOOL)value;\n+ (void)setTextFieldAutomaticSpellCorrection:(BOOL)value;\n+ (void)setTextFieldSmartCopyPaste:(BOOL)value;\n+ (void)setTextFieldSmartQuotes:(BOOL)value;\n+ (void)setTextFieldSmartDashes:(BOOL)value;\n+ (void)setTextFieldSmartLinks:(BOOL)value;\n+ (void)setTextFieldDataDetectors:(BOOL)value;\n+ (void)setTextFieldTextReplacement:(BOOL)value;\n\n+ (void)setWebKit2Enabled:(BOOL)webKit2Enabled;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCResourceManagerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCResourceManager.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCResourceManager ()\n+ (void)copyResourcesToApplicationSupportFolder;\n@end\n\n@interface TPCResourceManagerDocumentTypeImporter : NSDocument\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCSandboxMigrationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *   Copyright (c) 2024 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCResourceManager.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCSandboxMigration : NSObject\n+ (void)migrateResources;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCThemeControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCThemeController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCThemeController ()\n/* -load is called when app first launches to do first\n load with some extra safety checks. Use -reload if you\n want to reload the theme. */\n- (void)load;\n- (void)reload;\n\n- (void)recreateTemporaryCopyOfThemeIfNecessary;\n\n- (void)copyActiveThemeToDestinationLocation:(TPCThemeStorageLocation)destinationLocation reloadOnCopy:(BOOL)reloadOnCopy openOnCopy:(BOOL)openOnCopy;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TPCThemePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCTheme.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCTheme ()\n- (instancetype)initWithURL:(NSURL *)url inStorageLocation:(TPCThemeStorageLocation)storageLocation NS_DESIGNATED_INITIALIZER;\n\n@property (readonly, copy) NSString *applicationTemplateRepositoryPath;\n\n- (void)updateAppearance;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCAppearance ()\n/* TVCListAppearance will take care of all the hard work such as\n inheritance and retina. You only need to specify \"BigSurDark\"\n for example, not \"BigSurDarkRetina\" */\n- (nullable instancetype)initWithAppearanceNamed:(NSString *)appearanceName\n\t\t\t\t\t\t\t\t\t\t   atURL:(NSURL *)appearanceLocation\n\t\t\t\t\t\t\t\tforRetinaDisplay:(BOOL)forRetinaDisplay NS_DESIGNATED_INITIALIZER;\n\n/* When a subclass finishes applying all appearance values to properties,\n it can flush the top level group which will cause it to disappear from\n memory, thus reducing overall memory use. */\n- (void)flushAppearanceProperties;\n@end\n\n@interface TVCApplicationAppearance ()\n/* Appearance name is inherited from TXApplication */\n- (nullable instancetype)initWithAppearanceAtURL:(NSURL *)appearanceLocation\n\t\t\t\t\t\t\t\tforRetinaDisplay:(BOOL)forRetinaDisplay NS_DESIGNATED_INITIALIZER;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCChannelSelectionOutlineViewCellPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCChannelSelectionViewController;\n\n@interface TVCChannelSelectionOutlineCellView : NSTableCellView\n@property (nonatomic, weak) TVCChannelSelectionViewController *parentController;\n\n@property (nonatomic, weak) IBOutlet NSButton *selectedCheckbox;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCChannelSelectionViewControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCChannelSelectionViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCChannelSelectionOutlineCellView;\n\n@interface TVCChannelSelectionViewController ()\n- (NSOutlineView *)outlineView;\n\n- (void)selectionCheckboxClickedInCell:(TVCChannelSelectionOutlineCellView *)clickedCell;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCContentNavigationOutlineViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCContentNavigationOutlineViewItem;\n\n@interface TVCContentNavigationOutlineView : NSOutlineView\n@property (nonatomic, assign) NSUInteger contentViewPreferredWidth;\n@property (nonatomic, assign) NSUInteger contentViewPreferredHeight;\n@property (nonatomic, copy) NSArray<TVCContentNavigationOutlineViewItem *> *navigationTreeMatrix;\n@property (nonatomic, assign) BOOL expandParentOnDoubleClick;\n\n@property (readonly, weak, nullable) TVCContentNavigationOutlineViewItem *selectedItem;\n\n- (void)navigateToItemWithIdentifier:(NSUInteger)identifier;\n@end\n\n@interface TVCContentNavigationOutlineViewItem : NSObject\n@property (readonly, copy) NSString *label;\n@property (readonly) NSUInteger identifier;\n@property (readonly, weak, nullable) NSView *view;\n@property (readonly, weak, nullable) NSControl *firstResponder;\n@property (readonly, copy, nullable) NSArray<TVCContentNavigationOutlineViewItem *> *children;\n@property (readonly) BOOL isGroupItem;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (instancetype)initWithLabel:(NSString *)label\n\t\t\t\t   identifier:(NSUInteger)identifier\n\t\t\t\t\t\t view:(NSView *)view\n\t\t\t   firstResponder:(nullable NSControl *)firstResponder;\n\n/* view and children cannot both be nil or an exception is raised */\n- (instancetype)initWithLabel:(NSString *)label\n\t\t\t\t   identifier:(NSUInteger)identifier\n\t\t\t\t\t\t view:(nullable NSView *)view\n\t\t\t   firstResponder:(nullable NSControl *)firstResponder\n\t\t\t\t\t children:(nullable NSArray<TVCContentNavigationOutlineViewItem *> *)children NS_DESIGNATED_INITIALIZER;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCDockIconPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCDockIcon : NSObject\n+ (void)updateDockIcon;\n\n+ (void)resetCachedCount;\n\n+ (void)drawWithoutCount;\n+ (void)drawWithHighlightCount:(NSUInteger)highlightCount messageCount:(NSUInteger)messageCount;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCErrorMessagePopoverControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCErrorMessagePopoverController : NSObject\n+ (TVCErrorMessagePopoverController *)sharedController;\n\n- (void)showMessage:(NSString *)message forView:(NSView *)view;\n\n- (void)closeMessage;\n- (void)closeMessageForView:(NSView *)view;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCErrorMessagePopoverPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol TVCErrorMessagePopoverDelegate;\n\n@interface TVCErrorMessagePopover : NSObject\n@property (nonatomic, weak) id <TVCErrorMessagePopoverDelegate> delegate;\n\n@property (readonly, copy) NSString *message;\n@property (readonly, weak) NSView *view;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithMessage:(NSString *)message relativeToView:(NSView *)view NS_DESIGNATED_INITIALIZER;\n\n- (void)showRelativeToRect:(NSRect)rect;\n- (void)showRelativeToRect:(NSRect)rect preferredEdge:(NSRectEdge)preferredEdge;\n\n- (void)close;\n@end\n\n@protocol TVCErrorMessagePopoverDelegate <NSObject>\n@optional\n\n- (void)errorMessagePopoverWillShow:(TVCErrorMessagePopover *)popover;\n- (void)errorMessagePopoverDidShow:(TVCErrorMessagePopover *)popover;\n- (void)errorMessagePopoverWillClose:(TVCErrorMessagePopover *)popover;\n- (void)errorMessagePopoverDidClose:(TVCErrorMessagePopover *)popover;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogControllerHistoricLogFilePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCTreeItem, TVCLogLine;\n\n#define TVCLogControllerHistoricLogSharedInstance()\t\t\t\t[TVCLogControllerHistoricLogFile sharedInstance]\n\n@interface TVCLogControllerHistoricLogFile : NSObject\n+ (TVCLogControllerHistoricLogFile *)sharedInstance;\n\n- (void)writeNewEntryWithLogLine:(TVCLogLine *)logLine forItem:(IRCTreeItem *)item;\n\n- (void)saveData; // asynchronous operation\n\n- (void)resetMaximumLineCount;\n\n@property (readonly) BOOL isSaving;\n\n- (void)forgetItem:(IRCTreeItem *)item;\n- (void)resetDataForItem:(IRCTreeItem *)item;\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t\t\t\t  ascending:(BOOL)ascending\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock;\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t   withUniqueIdentifier:(NSString *)uniqueId\n\t\t   beforeFetchLimit:(NSUInteger)fetchLimitBefore\n\t\t\tafterFetchLimit:(NSUInteger)fetchLimitAfter\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock;\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t beforeUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock;\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t  afterUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock;\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t  afterUniqueIdentifier:(NSString *)uniqueIdAfter\n\t beforeUniqueIdentifier:(NSString *)uniqueIdBefore\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogControllerInlineMediaServicePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCTreeItem;\n\n#define TVCLogControllerInlineMediaSharedInstance()\t\t\t\t[TVCLogControllerInlineMediaService sharedInstance]\n\n@interface TVCLogControllerInlineMediaService : NSObject\n+ (TVCLogControllerInlineMediaService *)sharedInstance;\n\n- (void)processAddress:(NSString *)address\n  withUniqueIdentifier:(NSString *)uniqueIdentifier\n\t\t  atLineNumber:(NSString *)lineNumber\n\t\t\t\t index:(NSUInteger)index\n\t\t\t   forItem:(IRCTreeItem *)item;\n\n- (void)reloadService;\n\n/* This will present a modal alert asking user for permission\n to enable inline media so that they are aware of the risk of\n IP address leaks. Completion block returns YES on permission\n granted. NO in all other cases. */\n+ (void)askPermissionToEnableInlineMediaWithCompletionBlock:(void (NS_NOESCAPE ^)(BOOL granted))completionBlock;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogControllerOperationQueuePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, TVCLogController;\n\ntypedef void (^TVCLogControllerPrintingBlock)(NSOperation *sender);\n\n@interface TVCLogControllerPrintingOperationQueue : NSOperationQueue\n- (void)enqueueMessageBlock:(TVCLogControllerPrintingBlock)callbackBlock for:(TVCLogController *)viewController;\n- (void)enqueueMessageBlock:(TVCLogControllerPrintingBlock)callbackBlock for:(TVCLogController *)viewController isStandalone:(BOOL)isStandalone;\n\n- (void)cancelOperationsForClient:(IRCClient *)client;\n- (void)cancelOperationsForChannel:(IRCChannel *)channel;\n\n- (void)cancelOperationsForViewController:(TVCLogController *)viewController;\n\n- (void)updateReadinessState:(TVCLogController *)viewController;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class ICLPayload;\n\n@interface TVCLogController ()\n@property (nonatomic, assign, readwrite, getter=viewIsEncrypted) BOOL encrypted;\n\n- (instancetype)initWithClient:(IRCClient *)client inWindow:(TVCMainWindow *)window NS_DESIGNATED_INITIALIZER;\n- (instancetype)initWithChannel:(IRCChannel *)channel inWindow:(TVCMainWindow *)window NS_DESIGNATED_INITIALIZER;\n\n- (void)notifyDidBecomeHidden;\n- (void)notifyDidBecomeVisible;\n- (void)notifySelectionChanged;\n\n- (void)changeScrollbackLimit;\n\n- (void)clearBackingView;\n\n- (void)reloadTheme;\n\n- (void)print:(TVCLogLine *)logLine;\n- (void)print:(TVCLogLine *)logLine completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock;\n\n- (void)renderLogLineAtLineNumber:(NSString *)lineNumber\n\t\t\t  numberOfLinesBefore:(NSUInteger)numberOfLinesBefore\n\t\t\t   numberOfLinesAfter:(NSUInteger)numberOfLinesAfter\n\t\t\t\t  completionBlock:(void (^)(NSArray<NSDictionary<NSString *,id> *> * _Nonnull))completionBlock;\n\n- (void)renderLogLinesBeforeLineNumber:(NSString *)lineNumber\n\t\t\t\t  maximumNumberOfLines:(NSUInteger)maximumNumberOfLines\n\t\t\t\t\t   completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock;\n\n- (void)renderLogLinesAfterLineNumber:(NSString *)lineNumber\n\t\t\t\t maximumNumberOfLines:(NSUInteger)maximumNumberOfLines\n\t\t\t\t\t  completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock;\n\n- (void)renderLogLinesAfterLineNumber:(NSString *)lineNumberAfter\n\t\t\t\t\t beforeLineNumber:(NSString *)lineNumberBefore\n\t\t\t\t maximumNumberOfLines:(NSUInteger)maximumNumberOfLines\n\t\t\t\t\t  completionBlock:(void (^)(NSArray<NSDictionary<NSString *,id> *> * _Nonnull))completionBlock;\n\n- (void)notifyLinesAddedToView:(NSArray<NSString *> *)lineNumbers;\n- (void)notifyLinesRemovedFromView:(NSArray<NSString *> *)lineNumbers;\n\n- (void)notifyJumpToLine:(NSString *)lineNumber successful:(BOOL)successful scrolledToBottom:(BOOL)scrolledToBottom;\n\n- (void)notifyHistoricLogWillDeleteLines:(NSArray<NSString *> *)lineNumbers;\n\n- (void)processInlineMediaAtAddress:(NSString *)address withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index;\n\n- (void)processingInlineMediaPayloadSucceeded:(ICLPayload *)payload;\n- (void)processingInlineMediaPayload:(ICLPayload *)payload failedWithError:(NSError *)error;\n\n- (void)logViewWebViewClosedUnexpectedly;\n- (void)logViewWebViewFinishedLoading;\n- (void)logViewWebViewKeyDown:(NSEvent *)e;\n- (void)logViewWebViewReceivedDropWithFile:(NSString *)filename;\n\n- (nullable TVCLogLine *)lastLine;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogLinePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogLineXPC, IRCTreeItem;\n\n@interface TVCLogLine ()\n@property (readonly) BOOL fromCurrentSession;\n\n- (NSString *)renderedBodyForTranscriptLog;\n- (NSString *)renderedBodyForTranscriptLogInChannel:(nullable IRCChannel *)channel;\n\n+ (TVCLogLine *)logLineFromXPCObject:(TVCLogLineXPC *)xpcObject;\n- (TVCLogLineXPC *)xpcObjectForTreeItem:(IRCTreeItem *)treeItem;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogPolicyPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogView;\n\n@interface TVCLogPolicy : NSObject\n@property (nonatomic, copy, nullable) NSString *anchorURL;\n@property (nonatomic, copy, nullable) NSString *channelName;\n@property (nonatomic, copy, nullable) NSString *nickname;\n\n- (void)displayContextMenuInWebView:(TVCLogView *)webView;\n\n- (void)channelNameDoubleClicked;\n- (void)nicknameDoubleClicked;\n- (void)topicBarDoubleClicked;\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n- (NSArray<NSMenuItem *> *)webView1:(WebView *)webView logView:(TVCLogView *)logView contextMenuWithDefaultMenuItems:(NSArray *)defaultMenuItems;\n- (void)webView1:(WebView *)webView logView:(TVCLogView *)logView resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource;\n- (NSUInteger)webView1:(WebView *)webView logView:(TVCLogView *)logView dragDestinationActionMaskForDraggingInfo:(id<NSDraggingInfo>)draggingInfo;\n- (void)webView1:(WebView *)webView logView:(TVCLogView *)logView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id <WebPolicyDecisionListener>)listener;\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n- (void)webView2:(WKWebView *)webView logView:(TVCLogView *)logView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;\n- (void)webView2:(WKWebView *)webView logView:(TVCLogView *)logView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;\n- (NSMenu *)webView2:(WKWebView *)webView logView:(TVCLogView *)logView contextMenuWithDefaultMenu:(NSMenu *)defaultMenu;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogScriptEventSinkPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogView;\n\n@interface TVCLogScriptEventSink : NSObject\n- (instancetype)initWithWebView:(nullable TVCLogView *)webView NS_DESIGNATED_INITIALIZER;\n\n+ (void)logToJavaScriptConsole:(NSString *)message inWebView:(TVCLogView *)webView, ...;\n+ (void)logToJavaScriptConsole:(NSString *)message inWebView:(TVCLogView *)webView withArguments:(va_list)arguments;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogViewInternalWK1.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogPolicy, TVCLogView;\n\n@interface TVCLogViewInternalWK1 : WebView\n@property (nonatomic, weak) TVCLogView *t_parentView;\n@property (nonatomic, assign) BOOL t_viewHasLoaded;\n@property (nonatomic, assign) BOOL t_viewHasScriptObject;\n\n- (instancetype)initWithHostView:(TVCLogView *)hostView;\n\n- (void)_t_evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable))completionHandler;\n\n@property (readonly) TVCLogPolicy *webViewPolicy;\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward;\n\n+ (void)emptyCaches;\n@end\n\nNS_ASSUME_NONNULL_END\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogViewInternalWK2.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogPolicy, TVCLogView;\n\n@interface TVCLogViewInternalWK2 : WKWebView\n/* This flag will be YES unless a WebKit2 processes terminates for\n an unexpected reason such as a crash or memory exhaustion.\n In those cases, this property will become NO.\n The rest of Textual will give it priority over any other user\n preference asking for asking access to WebKit2. */\n@property (readonly, class) BOOL t_safeToUse;\n\n@property (nonatomic, weak) TVCLogView *t_parentView;\n@property (nonatomic, assign) BOOL t_viewIsLoading;\n@property (nonatomic, assign) BOOL t_viewIsNavigating;\n\n- (instancetype)initWithHostView:(TVCLogView *)hostView;\n\n- (void)_t_evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable))completionHandler;\n\n@property (readonly) TVCLogPolicy *webViewPolicy;\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward;\n\n+ (void)emptyCaches;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCLogViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogView.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogController, TVCLogPolicy;\n\n@interface TVCLogView ()\n@property (nonatomic, weak) TVCLogController *viewController;\n\n@property (readonly) TVCLogPolicy *webViewPolicy;\n\n@property (nonatomic, copy, readwrite, nullable) NSString *selection;\n\n@property (nonatomic, assign) BOOL viewingBottom;\n\n- (instancetype)initWithViewController:(TVCLogController *)viewController NS_DESIGNATED_INITIALIZER;\n\n- (void)informDelegateWebViewClosedUnexpectedly;\n- (void)informDelegateWebViewFinishedLoading;\n\n- (void)setViewFinishedLayout;\n\n- (BOOL)keyDown:(NSEvent *)e inView:(NSView *)view;\n\n- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;\n\n- (void)copyContentString;\n\n- (void)print;\n@end\n\n@interface TVCLogView (TVCLogViewBackingViewProxy)\n+ (void)emptyCaches;\n\n- (void)stopLoading;\n\n- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward;\n\n- (void)redrawViewIfNeeded;\n- (void)redrawView;\n\n- (void)resetScrollerPosition;\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom;\n- (void)saveScrollerPosition;\n- (void)restoreScrollerPosition;\n\n- (void)enableOffScreenUpdates;\n- (void)disableOffScreenUpdates;\n\n- (void)setAutomaticScrollingEnabled:(BOOL)automaticScrollingEnabled;\n@end\n\n@interface TVCLogView (TVCLogViewJavaScriptHandlerPrivate)\n- (NSString *)compiledFunctionCall:(NSString *)function withArguments:(nullable NSArray *)arguments;\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n- (id)webScriptObjectToCommon:(WebScriptObject *)object;\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindow;\n\n@interface TVCMainWindowAppearance ()\n- (nullable instancetype)initWithWindow:(TVCMainWindow *)mainWindow;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowChannelViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowChannelView : NSSplitView\n- (void)populateSubviews;\n\n- (void)updateArrangement;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowLoadingScreenPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMainWindowLoadingScreen.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowLoadingScreenView ()\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n\n#import \"TVCMainWindow.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCUser;\n@class TLOInputHistory;\n@class TVCMainWindowChannelView;\n@class TVCMainWindowTitlebarAccessoryView, TVCMainWindowTitlebarAccessoryViewController;\n@class TVCMainWindowTitlebarAccessoryViewLockButton;\n@class TVCTextViewIRCFormattingMenu;\n@class TXMenuControllerMainWindowProxy;\n\ntypedef NS_OPTIONS(NSUInteger, TVCMainWindowShiftSelectionFlags) {\n\tTVCMainWindowShiftSelectionFlagMaintainGrouping\t\t\t= 1 << 0,\n\tTVCMainWindowShiftSelectionFlagPerformDeselect\t\t\t= 1 << 1, // deselect previous selection\n\tTVCMainWindowShiftSelectionFlagPerformDeselectChildren\t= 1 << 2, // deselect previous selection + children (if group item)\n//\tTVCMainWindowShiftSelectionFlagPerformDeselectAll\t\t= 1 << 2  // deselect all\n};\n\ntypedef NS_OPTIONS(NSUInteger, TVCMainWindowMouseLocation) {\n\tTVCMainWindowMouseLocationOutsideWindow\t\t\t\t\t= 0,\n\tTVCMainWindowMouseLocationInsideWindow\t\t\t\t\t= 1 << 1,\n\tTVCMainWindowMouseLocationInsideWindowTitle\t\t\t\t= 1 << 2,\n\tTVCMainWindowMouseLocationOnTopOfWindowTitleControl\t\t= 1 << 3\n};\n\n@interface TVCMainWindow ()\n@property (nonatomic, assign) BOOL ignoreOutlineViewSelectionChanges;\n@property (nonatomic, assign) BOOL ignoreNextOutlineViewSelectionChange;\n\n- (TLOInputHistory *)inputHistoryManager;\n- (TVCMainWindowChannelView *)channelView;\n- (TVCMainWindowTitlebarAccessoryView *)titlebarAccessoryView;\n- (nullable TVCMainWindowTitlebarAccessoryViewController *)titlebarAccessoryViewController;\n- (TVCMainWindowTitlebarAccessoryViewLockButton *)titlebarAccessoryViewLockButton;\n- (TVCTextViewIRCFormattingMenu *)formattingMenu;\n- (TXMenuControllerMainWindowProxy *)mainMenuProxy;\n\n- (TVCMainWindowMouseLocation)locationOfMouseInWindow;\n- (TVCMainWindowMouseLocation)locationOfMouse:(NSPoint)mouseLocation;\n\n- (BOOL)reloadingTheme;\n\n- (BOOL)reloadLoadingScreen;\n\n- (void)updateTitle;\n- (void)updateTitleFor:(IRCTreeItem *)item;\n\n- (void)reloadTree;\n- (void)reloadTreeItem:(IRCTreeItem *)item;\n- (void)reloadTreeGroup:(IRCTreeItem *)item;\n\n- (void)adjustSelection;\n\n- (void)maybeToggleFullscreenAfterLaunch;\n\n- (void)updateAlphaValueToReflectPreferences;\n\n- (void)updateChannelViewBoxContentViewSelection;\n- (void)updateChannelViewArrangement;\n\n- (void)redirectKeyDown:(NSEvent *)e;\n\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command;\n\n- (void)selectItemInSelectedItems:(IRCTreeItem *)selectedItem;\n- (void)selectItemInSelectedItems:(IRCTreeItem *)selectedItem refreshChannelView:(BOOL)refreshChannelView;\n\n- (void)shiftSelection:(nullable IRCTreeItem *)oldItem toItem:(nullable IRCTreeItem *)newItem options:(TVCMainWindowShiftSelectionFlags)selectionOptions;\n\n- (void)channelViewSelectionChangeTo:(IRCTreeItem *)selectedItem;\n\n- (void)updateDrawingForUserInUserList:(IRCUser *)user;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowSegmentedControlPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowSegmentedController : NSSegmentedControl\n- (IBAction)segmentedCellClicked:(id)sender;\n\n- (void)updateSegmentedController;\n- (void)updateSegmentedControllerOrigin;\n@end\n\n@interface TVCMainWindowSegmentedControllerCell : NSSegmentedCell\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowSplitViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowSplitView.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowSplitView ()\n- (void)restorePositions;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowTextViewAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowTextViewAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindow;\n\n@interface TVCMainWindowTextViewAppearance ()\n- (nullable instancetype)initWithWindow:(TVCMainWindow *)mainWindow;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowTextViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMainWindowTextView.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindowSegmentedController, TVCMainWindowSegmentedControllerCell;\n\n@interface TVCMainWindowTextView ()\n- (TVCMainWindowSegmentedController *)segmentedController;\n- (TVCMainWindowSegmentedControllerCell *)segmentedControllerCell;\n\n- (void)updateTextDirection;\n\n- (void)updateTextBasedOnPreferredFontSize;\n\n- (void)updateSegmentedController;\n\n- (void)reloadOriginPoints;\n- (void)reloadOriginPointsAndRecalculateSize;\n\n- (void)recalculateTextViewSize;\n- (void)recalculateTextViewSizeForced;\n\n- (void)resetSpellingIgnores;\n@end\n\n@interface TVCMainWindowTextViewBackground : NSView\n@end\n\n@interface TVCMainWindowTextViewContentView : NSView\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMainWindowTitlebarAccessoryViewPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowTitlebarAccessoryView : NSView\n@end\n\n@interface TVCMainWindowTitlebarAccessoryViewController : NSTitlebarAccessoryViewController\n@end\n\n@interface TVCMainWindowTitlebarAccessoryViewLockButton : NSButton\n- (void)disableDrawingCustomBackgroundColor;\n- (void)enableDrawingCustomBackgroundColor;\n\n- (void)positionImageOverContent;\n- (void)positionImageOnLeftSide;\n\n- (void)setIconAsLocked;\n- (void)setIconAsUnlocked;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMemberListAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMemberListAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMemberList, TVCMainWindow;\n\n@interface TVCMemberListAppearance ()\n- (nullable instancetype)initWithMemberList:(TVCMemberList *)MemberList inWindow:(TVCMainWindow *)mainWindow;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMemberListCellPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMemberList;\n\n@interface TVCMemberListRowCell : NSTableRowView\n- (instancetype)initWithMemberList:(TVCMemberList *)memberList;\n@end\n\n@interface TVCMemberListCell : NSTableCellView\n- (void)drawWithExpansionFrame;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMemberListPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMemberList.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMemberListUserInfoPopover;\n@class IRCChannel;\n@class IRCChannelMemberListController;\n\n@interface TVCMemberList ()\n@property (nonatomic, weak) id keyDelegate;\n\n- (TVCMemberListAppearance *)userInterfaceObjects;\n- (nullable NSVisualEffectView *)visualEffectView;\n- (TVCMemberListUserInfoPopover *)memberListUserInfoPopover;\n- (IRCChannelMemberListController *)contentController;\n\n- (void)refreshAllDrawings;\n\n- (void)refreshDrawingForChangesToPreference:(NSString *)preferenceKey;\n\n- (void)assignToChannel:(nullable IRCChannel *)channel;\n@end\n\n@protocol TVCMemberListDelegate <NSObject>\n@required\n\n- (void)memberListKeyDown:(NSEvent *)e;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCMemberListUserInfoPopoverPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMemberListUserInfoPopover : NSPopover\n@property (readonly, weak) NSTextField *nicknameField;\n@property (readonly, weak) NSTextField *usernameField;\n@property (readonly, weak) NSTextField *addressField;\n@property (readonly, weak) NSTextField *realNameField;\n@property (readonly, weak) NSTextField *privilegesField;\n@property (readonly, weak) NSTextField *awayStatusField;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCNotificationConfigurationViewControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCNotificationConfigurationViewController : NSObject\n@property (nonatomic, copy) NSArray *notifications; // __kindof TVCNotificationConfiguration* or NSString*\n\n@property (nonatomic, assign) BOOL allowsMixedState; // Default: NO\n\n- (void)attachToView:(NSView *)view;\n\n- (void)reload;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCServerListAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCServerListAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCServerList, TVCMainWindow;\n\n@interface TVCServerListAppearance ()\n- (nullable instancetype)initWithServerList:(TVCServerList *)serverList inWindow:(TVCMainWindow *)mainWindow;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCServerListCellPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCServerList;\n\n@interface TVCServerListRowCell : NSTableRowView\n- (instancetype)initWithServerList:(TVCServerList *)serverList;\n@end\n\n@interface TVCServerListGroupRowCell : TVCServerListRowCell\n@end\n\n@interface TVCServerListChildRowCell : TVCServerListRowCell\n@end\n\n@interface TVCServerListCell : NSTableCellView\n- (void)populateMessageCountBadge;\n@end\n\n@interface TVCServerListCellChildItem : TVCServerListCell\n@end\n\n@interface TVCServerListCellGroupItem : TVCServerListCell\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCServerListPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCServerList.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCServerList ()\n@property (nonatomic, weak) id keyDelegate;\n\n- (TVCServerListAppearance *)userInterfaceObjects;\n- (nullable NSVisualEffectView *)visualEffectView;\n\n- (BOOL)leftMouseIsDownInView;\n\n- (void)addItemToList:(NSUInteger)rowIndex inParent:(nullable id)parent;\n\n- (void)removeItemFromList:(id)object;\n\n- (void)refreshAllDrawings;\n- (void)refreshAllUnreadMessageCountBadges;\n\n- (void)refreshMessageCountForItem:(IRCTreeItem *)cellItem;\n- (void)refreshMessageCountForRow:(NSInteger)rowIndex;\n@end\n\n@protocol TVCServerListDelegate <NSObject>\n@required\n\n- (void)serverListKeyDown:(NSEvent *)e;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCTextFormatterMenuPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define TVCTextViewIRCFormattingMenuFormatterMenuTag\t\t\t53037\n\n@interface TVCTextViewIRCFormattingMenu : NSObject\n@property (readonly, weak) NSMenuItem *formatterMenu;\n@property (readonly, weak) NSMenu *foregroundColorMenu;\n@property (readonly, weak) NSMenu *backgroundColorMenu;\n\n@property (readonly) BOOL firstResponderSupportsFormatting;\n\n@property (readonly) BOOL textIsBold;\n@property (readonly) BOOL textIsItalicized;\n@property (readonly) BOOL textIsMonospace;\n@property (readonly) BOOL textIsStruckthrough;\n@property (readonly) BOOL textIsUnderlined;\n@property (readonly) BOOL textHasForegroundColor;\n@property (readonly) BOOL textHasBackgroundColor;\n@property (readonly) BOOL textHasSpoiler;\n\n- (IBAction)insertBoldCharIntoTextBox:(id)sender;\n- (IBAction)insertItalicCharIntoTextBox:(id)sender;\n- (IBAction)insertMonospaceCharIntoTextBox:(id)sender;\n- (IBAction)insertStrikethroughCharIntoTextBox:(id)sender;\n- (IBAction)insertUnderlineCharIntoTextBox:(id)sender;\n- (IBAction)insertForegroundColorCharIntoTextBox:(id)sender;\n- (IBAction)insertBackgroundColorCharIntoTextBox:(id)sender;\n- (IBAction)insertSpoilerCharIntoTextBox:(id)sender;\n\n- (IBAction)removeBoldCharFromTextBox:(id)sender;\n- (IBAction)removeItalicCharFromTextBox:(id)sender;\n- (IBAction)removeMonospaceCharFromTextBox:(id)sender;\n- (IBAction)removeStrikethroughCharFromTextBox:(id)sender;\n- (IBAction)removeUnderlineCharFromTextBox:(id)sender;\n- (IBAction)removeForegroundColorCharFromTextBox:(id)sender;\n- (IBAction)removeBackgroundColorCharFromTextBox:(id)sender;\n- (IBAction)removeSpoilerCharFromTextBox:(id)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCTextViewWithIRCFormatterPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCTextViewWithIRCFormatter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCTextViewWithIRCFormatter ()\n@property (nonatomic, copy) NSFont *preferredFont;\n@property (nonatomic, copy) NSColor *preferredFontColor;\n\n- (void)keyDownToSuper:(NSEvent *)e;\n\n- (void)updateAllFontSizesToMatchTheDefaultFont;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TVCWK1AutoScrollerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCWK1AutoScroller : NSObject\n@property (readonly) BOOL canScroll;\n@property (readonly) BOOL viewingBottom;\n@property (nonatomic, assign) BOOL automaticScrollingEnabled;\n\n- (instancetype)initWitFrameView:(WebFrameView *)frameView;\n\n- (void)redrawFrame;\n\n/* -resetScrollerPosition does not actually move the scroller\n to the bottom if passed a true value. It simply resets the\n internal state so that when -restoreScrollerPosition is called,\n it will automatically scroll to the bottom or not. */\n- (void)resetScrollerPosition;\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom;\n- (void)saveScrollerPosition;\n- (void)restoreScrollerPosition;\n@end\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXAppearancePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *     Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXAppearance ()\n- (void)updateAppearance;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXApplicationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXApplication : NSApplication\n+ (BOOL)checkForOtherCopiesOfTextualRunning;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXGlobalModelsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXGlobalModels.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSDateFormatter *TXSharedISOStandardDateFormatter(void);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXMasterControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXMasterController ()\n@property (nonatomic, assign) NSUInteger terminatingClientCount;\n\n- (void)applicationWakeStepOne;\n- (void)applicationWakeStepTwo;\n\n- (void)prepareThirdPartyServiceSparkleFramework;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXMenuControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCServerPropertiesSheetPrivate.h\"\n#import \"TXMenuController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCTreeItem;\n\n@interface TXMenuController ()\n@property (nonatomic, copy, nullable) NSString *pointedNickname; // Takes priority if sender of an action returns nil userInfo value\n\n- (void)populateNavigationChannelList;\n\n- (IBAction)performNavigationAction:(id)sender;\n\n- (IBAction)openHelpMenuItem:(id)sender;\n\n- (IBAction)joinChannelClicked:(id)sender;\n\n- (void)memberChangeColor:(NSString *)nickname;\n\n- (void)memberInChannelViewDoubleClicked:(id)sender;\n- (void)memberInMemberListDoubleClicked:(id)sender;\n\n- (void)memberSendDroppedFiles:(NSArray<NSString *> *)files to:(NSString *)nickname;\n- (void)memberSendDroppedFiles:(NSArray<NSString *> *)files row:(NSUInteger)row;\n- (void)memberSendDroppedFilesToSelectedChannel:(NSArray<NSString *> *)files; // Only works if -selectedChannel is a private message\n\n- (void)showServerPropertiesSheetForClient:(IRCClient *)client withSelection:(TDCServerPropertiesSheetSelection)selection context:(nullable id)context;\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)manageLicense:(id)sender activateLicenseKeyWithURL:(NSURL *)licenseKeyURL;\n\n- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey;\n- (void)manageLicense:(id)sender activateLicenseKey:(nullable NSString *)licenseKey licenseKeyPassedByArgument:(BOOL)licenseKeyPassedByArgument;\n#endif\n\n- (void)toggleMuteOnNotificationsShortcutOn:(BOOL)toggleOn;\n- (void)toggleMuteOnNotificationSoundsShortcutOn:(BOOL)toggleOn;\n\n- (void)navigateToTreeItemAtURL:(NSURL *)url;\n- (void)navigateToTreeItemWithIdentifier:(NSString *)identifier;\n- (void)navigateToTreeItem:(IRCTreeItem *)item;\n\n- (IBAction)emptyAction:(id)sender TEXTUAL_DEPRECATED(\"Do not target this method\");\n@end\n\n@interface TXMenuControllerMainWindowProxy : NSObject\n- (IBAction)showWelcomeSheet:(id)sender;\n\n- (IBAction)manageLicense:(id)sender;\n\n- (IBAction)openStandaloneStoreWebpage:(id)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXSharedApplicationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXSharedApplication.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define windowController()\t\t\t\t[TXSharedApplication sharedWindowController]\n\n#define sharedNotificationController()\t[TXSharedApplication sharedNotificationController]\n\n#define sharedPluginManager()\t\t\t[TXSharedApplication sharedPluginManager]\n\n@class OELReachability;\n@class THOPluginManager;\n@class TDCFileTransferDialog;\n@class TLONotificationController, TLOSpeechSynthesizer;\n@class TVCLogControllerPrintingOperationQueue;\n@class TXWindowController;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@class TLOEncryptionManager;\n#endif\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@class TDCLicenseManagerDialog;\n#endif\n\n@interface TXSharedApplication ()\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n+ (TLOEncryptionManager *)sharedEncryptionManager;\n#endif\n\n+ (OELReachability *)sharedNetworkReachabilityNotifier;\n+ (TLONotificationController *)sharedNotificationController;\n+ (THOPluginManager *)sharedPluginManager;\n+ (TVCLogControllerPrintingOperationQueue *)sharedPrintingQueue;\n+ (TLOSpeechSynthesizer *)sharedSpeechSynthesizer;\n+ (TXWindowController *)sharedWindowController;\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n+ (TDCLicenseManagerDialog *)sharedLicenseManagerDialog;\n#endif\n\n+ (TDCFileTransferDialog *)sharedFileTransferDialog;\n@end\n\n@interface NSObject (TXSharedApplicationObjectExtensionPrivate)\n+ (void)setGlobalMasterControllerClassReference:(TXMasterController *)masterController;\n@end\n\nTEXTUAL_EXTERN os_log_t ApplicationTerminationLogSubsystem(void);\n\n#define LogToConsoleTerminationProgress(_message, ...)\t\\\n\tLogToConsoleDebugWithSubsystem(ApplicationTerminationLogSubsystem(), _message, ##__VA_ARGS__)\t\\\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TXWindowControllerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TXWindowController : NSObject\n/* By default only one instance of a particular class (window) may\n be maintained a reference to at any given time. Supply a related\n object in order to uniquely identify a window. */\n- (void)addWindowToWindowList:(id)window;\n- (void)addWindowToWindowList:(id)window inRelationTo:(nullable id)relatedObject;\n- (void)addWindowToWindowList:(id)window withDescription:(NSString *)windowDescription;\n\n- (void)removeWindowFromWindowList:(id)window;\n- (void)removeWindowFromWindowList:(id)window inRelationTo:(nullable id)relatedObject;\n\n- (nullable id)windowFromWindowList:(NSString *)windowDescription;\n\n- (NSArray *)windowsFromWindowList:(NSArray<NSString *> *)windowDescriptions;\n\n- (BOOL)maybeBringWindowForward:(NSString *)windowDescription;\n\n- (void)popMainWindowSheetIfExists;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/TextualPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <Security/Security.h>\n\n#import <WebKit/WebKit.h>\n\n#import <CocoaExtensions/CocoaExtensions.h>\n\n#import <AutoHyperlinks/AutoHyperlinks.h>\n\n#import <GRMustache/GRMustache.h>\n\n#import \"StaticDefinitions.h\"\n\n/* Defines for script support instead of importing the\n entire Carbon framework for three items. */\n#ifndef kASAppleScriptSuite\n\t#define kASAppleScriptSuite 'ascr'\n#endif\n\n#ifndef kASSubroutineEvent\n\t#define kASSubroutineEvent 'psbr'\n#endif\n\n#ifndef keyASSubroutineName\n\t#define keyASSubroutineName 'snam'\n#endif\n\n#import \"TXSharedApplicationPrivate.h\"\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/WKWebViewPrivate.h",
    "content": "\ntypedef NS_OPTIONS(NSUInteger, _WKFindOptions) {\n\t_WKFindOptionsCaseInsensitive\t\t\t\t\t= 1 << 0,\n\t_WKFindOptionsAtWordStarts\t\t\t\t\t\t= 1 << 1,\n\t_WKFindOptionsTreatMedialCapitalAsWordStart\t\t= 1 << 2,\n\t_WKFindOptionsBackwards\t\t\t\t\t\t\t= 1 << 3,\n\t_WKFindOptionsWrapAround\t\t\t\t\t\t= 1 << 4,\n\t_WKFindOptionsShowOverlay\t\t\t\t\t\t= 1 << 5,\n\t_WKFindOptionsShowFindIndicator\t\t\t\t\t= 1 << 6,\n\t_WKFindOptionsShowHighlight\t\t\t\t\t\t= 1 << 7,\n\t_WKFindOptionsDetermineMatchIndex\t\t\t\t= 1 << 8\n};\n\ntypedef const struct OpaqueWKPage *WKPageRef;\n\ntypedef const struct OpaqueWKInspector *WKInspectorRef;\n\nWKInspectorRef WKPageGetInspector(WKPageRef page);\n\nvoid WKInspectorShow(WKInspectorRef inspectorRef);\n\n@interface WKWebView ()\n- (WKPageRef)_pageForTesting;\n@end\n\n@interface WKView : NSView\n- (WKPageRef)pageRef;\n@end\n\n@interface _WKProcessPoolConfiguration : NSObject <NSCopying>\n@property (nonatomic) NSUInteger maximumProcessCount;\n@end\n\n@interface WKProcessPool ()\n- (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration;\n\n- (_WKProcessPoolConfiguration *)_configuration;\n@end\n\n@interface NSView (WKViewSwizzle)\n@end\n\n@interface WKPreferences ()\n@property (nonatomic, setter=_setAllowFileAccessFromFileURLs:) BOOL _allowFileAccessFromFileURLs; // 10.11\n@property (nonatomic, setter=_setDeveloperExtrasEnabled:) BOOL _developerExtrasEnabled; // 10.11\n@end\n\n@interface WKWebViewConfiguration ()\n@property (nonatomic, setter=_setAllowUniversalAccessFromFileURLs:) BOOL _allowUniversalAccessFromFileURLs; // 10.12\n@end\n\n/* Defined in WebKit/Source/WebKit/UIProcess/API/Cocoa/WKNavigationDelegatePrivate.h */\n/* Breaking the law, breaking the law... */\ntypedef NS_ENUM(NSInteger, _WKProcessTerminationReason) {\n\t_WKProcessTerminationReasonExceededMemoryLimit,\n\t_WKProcessTerminationReasonExceededCPULimit,\n\t_WKProcessTerminationReasonRequestedByClient,\n\t_WKProcessTerminationReasonCrash,\n};\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Private/WebScriptObjectHelperPrivate.h",
    "content": "/* *********************************************************************\n\n        Copyright (c) 2010 - 2018 Codeux Software, LLC\n     Please see ACKNOWLEDGEMENT for additional information.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n\n * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n * Neither the name of \"Codeux Software, LLC\", nor the names of its \n   contributors may be used to endorse or promote products derived \n   from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n SUCH DAMAGE.\n\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\n#import <JavaScriptCore/JavaScriptCore.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface WebScriptObject (TXWebScriptObjectHelper)\n- (nullable id)toCommonInContext:(JSContextRef)jsContextRef;\n@end\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TDCAlert.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAlert.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString * const TDCAlertSuppressionPrefix;\n\ntypedef NS_ENUM(NSUInteger, TDCAlertResponse) {\n\tTDCAlertResponseDefault = 1000,\n\tTDCAlertResponseAlternate = 1001,\n\tTDCAlertResponseOther = 1002\n};\n\ntypedef void (^TDCAlertCompletionBlock)(TDCAlertResponse buttonClicked, BOOL suppressed, id _Nullable underlyingAlert);\n\n@interface TDCAlert : NSObject\n/* Return the actual suppression key used internally.\n Do not feed this to the suppressionKey: field of these alerts.\n This is what is fed to that field turns into once the alert is processed. */\n+ (NSString *)suppressionKeyWithBase:(NSString *)base;\n\n/* All methods consider it valid to have suppression text but no suppression key.\n When suppression text is present, the user will be presented with a checkbox\n titled the value of suppressionText. If suppressionKey is not set, then nothing\n is recorded to user defaults. This provides a convenient way to ask the user a\n an unrelated question and receive a response. The response is in the callback\n block. If suppressed is YES, then the user enabled the checkbox. Even if\n no suppression key is present. */\n\n#pragma mark -\n#pragma mark Modal Alerts (Panel)\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate;\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText;\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t\t\taccessoryView:(nullable NSView *)accessoryView;\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse;\n\n+ (BOOL)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t\t\taccessoryView:(nullable NSView *)accessoryView\n\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse;\n\n+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\t  otherButton:(nullable NSString *)buttonOther;\n\n+ (TDCAlertResponse)modalAlertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\t  otherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t   suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\t  suppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t\taccessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t  suppressionResponse:(nullable BOOL *)suppressionResponse;\n\n#pragma mark -\n#pragma mark Non-blocking Alerts (Panel)\n\n/* The underlying TVCAlert object returned by the non-blocking\n methods does NOT need to be retained. Simply ignore the return\n value if you have no use in accessing the object. */\n/* Return value is only nil if completion block is immediately\n returned for suppression. */\n+ (TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t title:(NSString *)titleText\n\t\t\t\t defaultButton:(NSString *)buttonDefault\n\t\t\t   alternateButton:(nullable NSString *)buttonAlternate;\n\n+ (TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t title:(NSString *)titleText\n\t\t\t\t defaultButton:(NSString *)buttonDefault\n\t\t\t   alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t   otherButton:(nullable NSString *)buttonOther;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t  accessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (nullable TVCAlert *)alertWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\t  title:(NSString *)titleText\n\t\t\t\t\t\t  defaultButton:(NSString *)buttonDefault\n\t\t\t\t\t\talternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\t\totherButton:(nullable NSString *)buttonOther\n\t\t\t\t\t\t suppressionKey:(nullable NSString *)suppressKey\n\t\t\t\t\t\tsuppressionText:(nullable NSString *)suppressText\n\t\t\t\t\t\t  accessoryView:(nullable NSView *)accessoryView\n\t\t\t\t\t\tcompletionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n#pragma mark -\n#pragma mark Non-blocking Alerts (Sheet)\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther;\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t   accessoryView:(nullable NSView *)accessoryView\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t  suppressionKey:(nullable NSString *)suppressKey\n\t\t\t suppressionText:(nullable NSString *)suppressText\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n\n+ (void)alertSheetWithWindow:(NSWindow *)window\n\t\t\t\t\t\tbody:(NSString *)bodyText\n\t\t\t\t\t   title:(NSString *)titleText\n\t\t\t   defaultButton:(NSString *)buttonDefault\n\t\t\t alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t otherButton:(nullable NSString *)buttonOther\n\t\t\t  suppressionKey:(nullable NSString *)suppressKey\n\t\t\t suppressionText:(nullable NSString *)suppressText\n\t\t\t   accessoryView:(nullable NSView *)accessoryView\n\t\t\t completionBlock:(nullable TDCAlertCompletionBlock)completionBlock;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TDCInputPrompt.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCAlert.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCInputPrompt : TDCAlert\n+ (TVCAlertResponseButton)promptWithMessage:(NSString *)bodyText\n\t\t\t\t\t\t\t\ttitle:(NSString *)titleText\n\t\t\t\t\t\tdefaultButton:(NSString *)buttonDefault\n\t\t\t\t\t  alternateButton:(nullable NSString *)buttonAlternate\n\t\t\t\t\t\tprefillString:(nullable NSString *)prefillString\n\t\t\t\t\t\t resultString:(NSString * _Nonnull * _Nonnull )resultString;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TDCSheetBase.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCValidatedComboBox, TVCValidatedTextField;\n\n@interface TDCSheetBase : NSObject\n@property (nonatomic, weak) id delegate;\n@property (nonatomic, weak) NSWindow *window;\n@property (nonatomic, strong) IBOutlet NSWindow *sheet; // Window being attached\n@property (nonatomic, weak) IBOutlet NSButton *okButton;\n@property (nonatomic, weak) IBOutlet NSButton *cancelButton;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n/* Window is allowed to be set after init */\n- (instancetype)initWithWindow:(nullable NSWindow *)window; // NS_DESIGNATED_INITIALIZER\n\n- (void)startSheet;\n- (void)endSheet;\n\n- (IBAction)ok:(id)sender;\n- (IBAction)cancel:(id)sender;\n\n- (void)close;\n\n- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField;\n- (BOOL)okOrErrorForComboBox:(TVCValidatedComboBox *)comboBox;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TDCWindowBase.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TDCWindowBase : NSObject\n@property (nonatomic, weak) id delegate;\n@property (nonatomic, strong) IBOutlet NSWindow *window;\n@property (nonatomic, weak) IBOutlet NSButton *okButton;\n@property (nonatomic, weak) IBOutlet NSButton *cancelButton;\n\n- (void)show;\n- (void)close;\n\n- (IBAction)ok:(id)sender;\n- (IBAction)cancel:(id)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/THOPluginManager.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *   Copyright (c) 2024 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <os/log.h>\n\n/**\n * Subsystem that plugin can use for logging using `os_log` and related systems.\n *\n * Plugins are loaded directly into Textual and are not executed on a separate\n * process. As such, the returned subsystem uses the same identifier of Textual.\n * The category is different. The category is in the format:\n * `Extension['<BUNDLE NAME>']`\n *\n * Accessing the logging subsystem through this function is not optimized \n * if aggressive logging is performed. In that case, retain a reference,\n * or create a subsystem outside of this initializer.\n *\n * @return Subsystem that plugin can use for logging.\n */\n#define THOPluginLoggingSubsystem()\t\t\\\n\t_THOPluginLoggingSubsystemForBundle([NSBundle bundleForClass:[self class]])\n\nTEXTUAL_EXTERN os_log_t _THOPluginLoggingSubsystemForBundle(NSBundle *bundle);\n"
  },
  {
    "path": "Sources/App/Classes/Headers/THOPluginProtocol.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"THOPluginManager.h\"\n#import \"IRCCommandIndex.h\"\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class AHHyperlinkScannerResult;\n@class IRCClient, IRCChannel, IRCChannelUser, IRCPrefix, IRCMessage;\n@class TVCLogController;\n\n@class THOPluginDidPostNewMessageConcreteObject;\n@class THOPluginDidReceiveServerInputConcreteObject;\n@class THOPluginOutputSuppressionRule;\n@class THOPluginWebViewJavaScriptPayloadConcreteObject;\n\n#pragma mark -\n#pragma mark Localization\n\n#define TPILocalizedString(k, ...)\t\tTXLocalizedStringAlternative(TPIBundleFromClass(), k, ##__VA_ARGS__)\n\n/**\n * @brief Returns the NSBundle that owns the calling class.\n */\n#define TPIBundleFromClass()\t\t\t\t[NSBundle bundleForClass:[self class]]\n\n/**\n * A plugin must declare the minimum version of Textual that it is compatible with.\n *\n * Textual declares the constant named THOPluginProtocolCompatibilityMinimumVersion.\n * This constant is compared against the minimum version that a plugin specifies.\n * If the plugin's value is equal to or greater than this constant, then the plugin\n * is considered safe to load. \n *\n * Unlike the version information that visible to the end user, this constant does\n * not change often. It only changes when modifications have been made to Textual’s\n * codebase that may result in crashes when loading existing plugins.\n *\n * For example, even though Textual’s visible version number is “5.0.4”, the value\n * of this constant is “5.0.0”\n *\n * To declare compatibility, add a new entry to a plugin's Info.plist file with \n * the key named: \"MinimumTextualVersion\" - Set the value of this entry, as a \n * String, to the return value of THOPluginProtocolCompatibilityMinimumVersion.\n *\n * @return \"7.2.4\" as of June 30, 2024\n */\nextern NSString * const THOPluginProtocolCompatibilityMinimumVersion;\n\n/**\n * The `THOPluginProtocol` protocol defines methods and properties that the \n * primary class of a plugin can inherit from.\n */\n@protocol THOPluginProtocol <NSObject>\n\n@optional\n\n#pragma mark -\n#pragma mark Initialization\n\n/** @name Initialization */\n\n/**\n * @brief Method invoked during initialization of a plugin.\n *\n * @discussion This method is invoked very early on. It occurs once the principal \n *  class of the plugin has been allocated and is guaranteed to be the first call\n *  home that a plugin will receive.\n */\n- (void)pluginLoadedIntoMemory;\n\n/**\n * @brief Method invoked prior to deallocation of a plugin.\n */\n- (void)pluginWillBeUnloadedFromMemory;\n\n#pragma mark -\n#pragma mark Input Manipulation\n\n/** @name Input Manipulation */\n\n/**\n * @brief Method invoked to inform the plugin that a plain text message was received\n *  (*PRIVMSG*, *ACTION*, or *NOTICE*)\n *\n * @discussion This method is invoked on the main thread which means that slow code\n *  can lockup the user interface of Textual. If you have no intent to ignore content,\n *  then do work in the background and immediately return `YES`.\n *\n * @param text The message contents\n * @param textAuthor The author (sender) of the message\n * @param textDestination The channel that the message is destined for\n * @param lineType The line type of the message\n *\n *    Possible values: `TVCLogLineTypePrivateMessage`, `TVCLogLineTypeAction`,\n *           `TVCLogLineTypeNotice`\n * @param client The client the message was received on\n * @param receivedAt The date & time of the message. Depending on whether a custom\n *    value was specified using the server-time IRCv3 capability, this `NSDate`\n *    object may be very far in the past, or even possibly in the future.\n * @param wasEncrypted Whether or not the message was encrypted\n *\n * @return `YES` to display the contents of the message to the user, `NO` otherwise.\n */\n- (BOOL)receivedText:(NSString *)text\n\t      authoredBy:(IRCPrefix *)textAuthor\n\t     destinedFor:(nullable IRCChannel *)textDestination\n\t      asLineType:(TVCLogLineType)lineType\n\t        onClient:(IRCClient *)client\n\t      receivedAt:(NSDate *)receivedAt\n\t    wasEncrypted:(BOOL)wasEncrypted;\n\n/**\n * @brief Method used to modify and/or completely ignore incoming data from the server.\n *\n * @warning This method is invoked on each plugin in the order loaded. This method\n *  does not stop for the first result returned which means that value being passed may\n *  have been modified by a plugin above the one being talked to.\n *\n * @warning Textual does not perform validation against the instance of `IRCMessage` that\n *  is returned which means that if Textual tries to access specific information which\n *  has been improperly modified or removed, then the entire application may crash.\n *\n * @param input An instance of `IRCMessage`\n * @param client The client responsible for the event\n *\n * @return The original and/or modified copy of `IRCMessage` or `nil` to prevent the data\n *  from being processed altogether.\n */\n- (nullable IRCMessage *)interceptServerInput:(IRCMessage *)input for:(IRCClient *)client;\n\n/**\n * @brief Method used to modify and/or completely ignore text entered into the main text\n *  field of Textual.\n *\n * @warning This method is invoked on each plugin in the order loaded. This method\n *  does not stop for the first result returned which means that value being passed may\n *  have been modified by a plugin above the one being talked to.\n *\n * @param input The value of the text field as either an instance of `NSString` or\n *  `NSAttributedString`.\n * @param command Textual allows the end user to send text entered into the text field as\n *  an action without using the `/me` command. When this occurs, Textual informs lower-level\n *  APIs of this intent by changing the value of this parameter from “privmsg” to “action” —\n *  In most cases a plugin should disregard this parameter and pass it untouched.\n *\n * @return The original and/or modified copy of input or `nil` to prevent the data from\n *  being processed altogether.\n */\n- (nullable id)interceptUserInput:(id)input command:(IRCRemoteCommand)command;\n\n#pragma mark -\n#pragma mark Preferences Pane\n\n/** @name Preferences */\n\n/**\n * @brief Defines an `NSView` used by the Preferences window of Textual to\n *  allow user-interactive configuration of the plugin.\n *\n * @return An instance of NSView with a width of at least 590.\n */\n@property (nonatomic, readonly, strong) NSView *pluginPreferencesPaneView;\n\n/**\n * @brief Defines an `NSString` which is used by the Preferences window of\n *  Textual to create a new entry in its navigation list.\n */\n@property (nonatomic, readonly, copy) NSString *pluginPreferencesPaneMenuItemName;\n\n#pragma mark -\n#pragma mark Renderer Events\n\n/** @name Renderer Events */\n\n/**\n * @brief Method invoked prior to a message being converted to its HTML equivalent.\n *\n * @discussion This methods can be used to modify the text that will be displayed for a \n *  certain message by replacing one or more segments of it.\n * \n * Considerations:\n *\n * 1. `nil` or a string with zero length indicates that there is no interest in modifying \n *  `newMessage`\n * 2. There is no way to inform the renderer that you do not want a specific value of \n *  `newMessage` shown to the end user. Use the various other methods provided by the \n *  `THOPluginProtocol` to accomplish that task.\n *\n * @warning This method is invoked on each plugin in the order loaded. This method does not \n *  stop for the first result returned which means that value being passed may have been\n *  modified by a plugin above the one being talked to.\n *\n * @warning Under no circumstances should you insert HTML at this point. Doing so will result \n *  in undefined behavior.\n *\n * @param newMessage An unedited copy of the message being rendered\n * @param viewController The view responsible for the event\n * @param lineType The line type of `newMessage`\n * @param memberType The member type of `newMessage`\n *\n * @return The original and/or modified copy of `newMessage`\n */\n- (NSString *)willRenderMessage:(NSString *)newMessage\n\t\t\t  forViewController:(TVCLogController *)viewController\n\t\t\t\t\t   lineType:(TVCLogLineType)lineType\n\t\t\t\t\t memberType:(TVCLogLineMemberType)memberType;\n\n#pragma mark -\n#pragma mark Subscribed Events\n\n/** @name Subscribed Events */\n\n/**\n * @brief Defines a list of commands that the plugin will support as user input\n *  from the main text field.\n *\n * @discussion Considerations:\n *\n * 1. If a command is a number, then insert it into the array as an `NSString`\n * 2. If a plugin tries to add a command already built into Textual onto\n *  this list, it will not work.\n * 3. It is possible, but unlikely, that another plugin the end user has\n *  loaded is subscribed to the same command. When that occurs, all plugins\n *  subscribed to the command will be informed of when the command is performed.\n * 4. To avoid conflicts, a plugin cannot subscribe to a command already\n *  defined by a script. If a script and a plugin both share the same command,\n *  then neither will be executed and an error will be printed to the console.\n *\n * @return An `NSArray` containing a lowercase list of commands that the plugin\n *  will support as user input from the main text field.\n */\n@property (nonatomic, readonly, copy) NSArray<NSString *> *subscribedUserInputCommands;\n\n/**\n * @brief Method invoked when a subscribed user input command requires processing.\n *\n * @param client The client responsible for the event\n * @param commandString The name of the command\n * @param messageString Data that follows `commandString`\n */\n- (void)userInputCommandInvokedOnClient:(IRCClient *)client commandString:(NSString *)commandString messageString:(NSString *)messageString;\n\n/**\n * @brief Defines a list of commands that the plugin will support as server input.\n *\n * @return An `NSArray` containing a lowercase list of commands that the plugin\n *  will support as server input.\n *\n * @discussion If a command is a number, then insert it into the array as an `NSString`\n */\n@property (nonatomic, readonly, copy) NSArray<NSString *> *subscribedServerInputCommands;\n\n/**\n * @brief Method invoked when a subscribed server input command requires processing.\n *\n * @param inputObject An instance of THOPluginDidReceiveServerInputConcreteObject\n * @param client The client responsible for the event\n *\n * @see THOPluginDidReceiveServerInputConcreteObject\n */\n- (void)didReceiveServerInput:(THOPluginDidReceiveServerInputConcreteObject *)inputObject onClient:(IRCClient *)client;\n\n#pragma mark -\n#pragma mark WebView Events\n\n/** @name WebView Events */\n\n/**\n * @brief Method invoked when the Document Object Model (DOM) of a view has been modified.\n *\n * @discussion This method is invoked when a message has been added to the Document Object\n *  Model (DOM) of viewController\n *\n * @warning Do not do any heavy work when the\n *  [isProcessedInBulk]([THOPluginDidPostNewMessageConcreteObject isProcessedInBulk]) property \n *  of `messageObject` is set to `YES` because thousand of other messages may be processing at \n *  the same time.\n *\n * @warning This method is invoked on an asynchronous background dispatch queue. Not the\n *  main thread. If you interact with WebKit when this method is invoked, then make sure\n *  that you do so on the main thread. If you don't, WebKit will throw an exception.\n *\n * @param messageObject An instance of THOPluginDidPostNewMessageConcreteObject\n * @param viewController The view responsible for the event\n *\n * @see THOPluginDidPostNewMessageConcreteObject\n */\n- (void)didPostNewMessage:(THOPluginDidPostNewMessageConcreteObject *)messageObject forViewController:(TVCLogController *)viewController;\n\n/**\n * @brief Method invoked when the JavaScript function `app.sendPluginPayload()` is executed.\n *\n * @discussion A plugin that injects JavaScript into Textual's WebView can use this method\n *  to send data back to the plugin.\n * \n * A payload can be passed by invoking the JavaScript function \n *  `app.sendPluginPayload(payloadLabel, payloadContent)`\n *\n * @warning This method is invoked on an asynchronous background dispatch queue. Not the\n *  main thread. If you interact with WebKit when this method is invoked, then make sure\n *  that you do so on the main thread. If you don't, WebKit will throw an exception.\n *\n * @param payloadObject An instance of THOPluginWebViewJavaScriptPayloadConcreteObject\n * @param viewController The view responsible for the event\n *\n * @see THOPluginWebViewJavaScriptPayloadConcreteObject\n */\n- (void)didReceiveJavaScriptPayload:(THOPluginWebViewJavaScriptPayloadConcreteObject *)payloadObject fromViewController:(TVCLogController *)viewController;\n\n#pragma mark -\n#pragma mark Reserved Calls\n\n/* The behavior of this method call is undefined. It exists for internal\n purposes for the plugins packaged with Textual by default. It is not\n recommended to use it, or try to understand it. */\n@property (nonatomic, readonly, copy) NSArray<THOPluginOutputSuppressionRule *> *pluginOutputSuppressionRules;\n@end\n\n#pragma mark -\n\n/**\n * This object is a container for values related to\n * [THOPluginProtocol didPostNewMessage:forViewController:]\n */\n@interface THOPluginDidPostNewMessageConcreteObject : NSObject\n/**\n * @brief Whether the message was posted as a result of a bulk operation\n */\n@property (readonly) BOOL isProcessedInBulk;\n\n/**\n * @brief The contents of the message visible to the end user\n */\n@property (readonly, copy) NSString *messageContents;\n\n/**\n * @brief The ID of the message that can be used to access it using `getElementByID()`\n */\n@property (readonly, copy) NSString *lineNumber;\n\n/**\n * @brief The nickname of the person and/or server responsible for producing the \n *  message.\n *\n * @discussion This value may be empty.\n */\n@property (readonly, copy, nullable) NSString *senderNickname;\n\n/**\n * @brief The line type of the message\n */\n@property (readonly) TVCLogLineType lineType;\n\n/**\n * @brief The member type of the message\n */\n@property (readonly) TVCLogLineMemberType memberType;\n\n/**\n * @brief The date & time displayed left of the message in the WebView\n */\n@property (readonly, copy) NSDate *receivedAt;\n\n/**\n * @brief Array of URLs found in the message body\n */\n@property (readonly, copy) NSArray<AHHyperlinkScannerResult *> *listOfHyperlinks;\n\n/**\n * @brief List of users from the channel that appear in the message\n */\n@property (readonly, copy) NSSet<IRCChannelUser *> *listOfUsers;\n\n/**\n * @brief Whether or not a highlight word was matched\n */\n@property (readonly) BOOL keywordMatchFound;\n@end\n\n#pragma mark -\n\n/**\n * This object is a container for values related to\n * [THOPluginProtocol didReceiveServerInput:onClient:]\n */\n@interface THOPluginDidReceiveServerInputConcreteObject : NSObject\n/**\n * @brief Whether the input was from a regular user or from a server\n */\n@property (readonly) BOOL senderIsServer;\n\n/**\n * @brief The nickname section of the sender's hostmask\n *\n * @discussion The value of this property is the server address if senderIsServer is `YES`\n */\n@property (readonly, copy) NSString *senderNickname;\n\n/**\n * @brief The username (ident) section of the sender's hostmask\n */\n@property (readonly, copy, nullable) NSString *senderUsername;\n\n/**\n * @brief The address section of the sender's hostmask\n */\n@property (readonly, copy, nullable) NSString *senderAddress;\n\n/**\n * @brief The combined hostmask of the sender\n */\n@property (readonly, copy) NSString *senderHostmask;\n\n/**\n * @brief The date & time during which the input was received\n *\n * @discussion If the original message specifies a custom value using the server-time\n *  capability, then the value of this property will reflect the value defined by the\n *  server-time capability; not the exact date & time it was received on the socket.\n */\n@property (readonly, copy) NSDate *receivedAt;\n\n/**\n * @brief The input itself\n */\n@property (readonly, copy) NSString *messageSequence;\n\n/**\n * @brief The input, split up into sections\n */\n@property (readonly, copy) NSArray<NSString *> *messageParameters;\n\n/**\n * @brief The input's command\n */\n@property (readonly, copy) NSString *messageCommand;\n\n/**\n * @brief The value of -messageCommand as an integer\n */\n@property (readonly) NSUInteger messageCommandNumeric;\n\n/**\n * @brief The server address of the IRC network\n *\n * @discussion The value of this attribute is the address of the server that \n *  Textual is currently connected to and may differ from senderNickname even\n *  if senderIsServer is `YES`\n */\n@property (readonly, copy, nullable) NSString *networkAddress;\n\n/**\n * @brief The name of the IRC network\n */\n@property (readonly, copy, nullable) NSString *networkName;\n@end\n\n#pragma mark -\n\n/**\n * This object is a container for values related to \n * [THOPluginProtocol didReceiveJavaScriptPayload:fromViewController:]\n */\n@interface THOPluginWebViewJavaScriptPayloadConcreteObject : NSObject\n/**\n * @brief A description of the payload\n */\n@property (readonly, copy) NSString *payloadLabel;\n\n/**\n * @brief The payload contents\n */\n@property (readonly, copy, nullable) id <NSCopying> payloadContents;\n@end\n\n#pragma mark -\n\n@interface THOPluginOutputSuppressionRule : NSObject\n@property (nonatomic, copy) NSString *match;\n@property (nonatomic, assign) BOOL restrictConsole;\n@property (nonatomic, assign) BOOL restrictChannel;\n@property (nonatomic, assign) BOOL restrictPrivateMessage;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/THOUnicodeHelper.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface THOUnicodeHelper : NSObject\n+ (BOOL)isPrivate:(UniChar)c;\n+ (BOOL)isIdeographic:(UniChar)c;\n+ (BOOL)isIdeographicOrPrivate:(UniChar)c;\n+ (BOOL)isAlphabeticalCodePoint:(NSInteger)c;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOEncryptionManager.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\ntypedef void (^TLOEncryptionManagerEncodingDecodingCallbackBlock)(NSString *originalString, BOOL wasEncrypted);\n\ntypedef void (^TLOEncryptionManagerInjectCallbackBlock)(NSString *encodedString);\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOInternetAddressLookup.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol TLOInternetAddressLookupDelegate;\n\n@interface TLOInternetAddressLookup : NSObject\n@property (nonatomic, assign) BOOL IPv4AddressIsValid; // Defaults to YES\n@property (nonatomic, assign) BOOL IPv6AddressIsValid; // ^\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithDelegate:(id <TLOInternetAddressLookupDelegate>)delegate NS_DESIGNATED_INITIALIZER;\n\n- (void)performLookup;\n- (void)cancelLookup;\n@end\n\n@protocol TLOInternetAddressLookupDelegate <NSObject>\n@required\n\n- (void)internetAddressLookupReturnedAddress:(NSString *)address;\n- (void)internetAddressLookupFailed;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOKeyEventHandler.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define TXKeyReturnCode\t\t\t0x24\n#define TXKeyTabCode\t\t\t0x30\n#define TXKeySpacebarCode\t\t0x31\n#define TXKeyBackspaceCode\t\t0x33\n#define TXKeyEscapeCode\t\t\t0x35\n#define TXKeyEnterCode\t\t\t0x4C\n#define TXKeyHomeCode\t\t\t0x73\n#define TXKeyPageUpCode\t\t\t0x74\n#define TXKeyDeleteCode\t\t\t0x75\n#define TXKeyEndCode\t\t\t0x77\n#define TXKeyPageDownCode\t\t0x79\n#define TXKeyLeftArrowCode\t\t0x7B\n#define TXKeyRightArrowCode\t\t0x7C\n#define TXKeyDownArrowCode\t\t0x7D\n#define TXKeyUpArrowCode\t\t0x7E\n\n@protocol TLOKeyEventHandlerPrototype <NSObject>\n@optional\n- (void)setKeyHandlerTarget:(id)target;\n\n- (void)registerSelector:(SEL)selector key:(NSUInteger)keyCode modifiers:(NSUInteger)modifiers;\n- (void)registerSelector:(SEL)selector character:(UniChar)character modifiers:(NSUInteger)modifiers;\n- (void)registerSelector:(SEL)selector characters:(NSRange)characterRange modifiers:(NSUInteger)modifiers;\n@end\n\n@interface TLOKeyEventHandler : NSObject <TLOKeyEventHandlerPrototype>\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithTarget:(id)target NS_DESIGNATED_INITIALIZER;\n\n- (BOOL)processKeyEvent:(NSEvent *)event;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOLinkParser.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class AHHyperlinkScannerResult;\n\n@interface TLOLinkParser : NSObject\n+ (NSArray<AHHyperlinkScannerResult *> *)locateLinksInString:(NSString *)string;\n\n@property (readonly, class, copy) NSArray<NSString *> *bannedLineTypes;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLONotificationController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <UserNotifications/UserNotifications.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\ntypedef NS_ENUM(NSUInteger, TXNotificationType) {\n\tTXNotificationTypeHighlight\t\t\t\t\t\t\t= 1000,\n\tTXNotificationTypeNewPrivateMessage\t\t\t\t\t= 1001,\n\tTXNotificationTypeChannelMessage\t\t\t\t\t= 1002,\n\tTXNotificationTypeChannelNotice\t\t\t\t\t\t= 1003,\n\tTXNotificationTypePrivateMessage\t\t\t\t\t= 1004,\n\tTXNotificationTypePrivateNotice\t\t\t\t\t\t= 1005,\n\tTXNotificationTypeKick\t\t\t\t\t\t\t\t= 1006,\n\tTXNotificationTypeInvite\t\t\t\t\t\t\t= 1007,\n\tTXNotificationTypeConnect\t\t\t\t\t\t\t= 1008,\n\tTXNotificationTypeDisconnect\t\t\t\t\t\t= 1009,\n\tTXNotificationTypeAddressBookMatch\t\t\t\t\t= 1010,\n\tTXNotificationTypeFileTransferSendSuccessful\t\t= 1011,\n\tTXNotificationTypeFileTransferReceiveSuccessful\t\t= 1012,\n\tTXNotificationTypeFileTransferSendFailed\t\t\t= 1013,\n\tTXNotificationTypeFileTransferReceiveFailed\t\t\t= 1014,\n\tTXNotificationTypeFileTransferReceiveRequested\t\t= 1015,\n\tTXNotificationTypeUserJoined\t\t\t\t\t\t= 1016,\n\tTXNotificationTypeUserParted\t\t\t\t\t\t= 1017,\n\tTXNotificationTypeUserDisconnected\t\t\t\t\t= 1018\n};\n\n@interface TLONotificationController : NSObject\n@property (nonatomic, assign) BOOL areNotificationsDisabled;\n\n- (NSString *)titleForEvent:(TXNotificationType)event;\n@end\n\n@interface TLONotificationController (Preferences)\n- (nullable NSString *)soundForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n- (BOOL)speakEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n- (BOOL)notificationEnabledForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n- (BOOL)disabledWhileAwayForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n- (BOOL)bounceDockIconForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n- (BOOL)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOSoundPlayer.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOSoundPlayer : NSObject\n+ (void)playAlertSound:(NSString *)name;\n\n+ (NSArray<NSString *> *)uniqueListOfSounds;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TLOpenLink.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOpenLink : NSObject\n+ (void)open:(NSURL *)url;\n+ (void)open:(NSURL *)url inBackground:(BOOL)inBackground;\n\n+ (void)openWithString:(NSString *)url;\n+ (void)openWithString:(NSString *)url inBackground:(BOOL)inBackground;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCApplicationInfo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCApplicationInfo : NSObject\n+ (BOOL)sandboxEnabled;\n\n+ (nullable NSDate *)applicationLaunchDate;\n\n+ (NSTimeInterval)timeIntervalSinceApplicationLaunch;\n+ (NSTimeInterval)timeIntervalSinceApplicationInstall;\n\n+ (NSUInteger)applicationRunCount;\n\n+ (NSString *)applicationName;\n+ (NSString *)applicationNameWithoutVersion;\n\n+ (NSString *)applicationVersion;\n+ (NSString *)applicationVersionShort;\n\n+ (NSString *)applicationBundleIdentifier;\n\n+ (NSString *)applicationBuildScheme;\n\n+ (int)applicationProcessID;\n\n+ (NSDictionary<NSString *, id> *)applicationInfoPlist;\n\n+ (NSTimeInterval)applicationBirthday;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCPathInfo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPathInfo : NSObject\n#pragma mark -\n#pragma mark Application Specific\n\n@property (readonly, class, copy) NSString *applicationBundle;\n@property (readonly, class, copy) NSURL *applicationBundleURL;\n\n@property (readonly, class, copy) NSString *applicationResources;\n@property (readonly, class, copy) NSURL *applicationResourcesURL;\n\n@property (readonly, class, copy, nullable) NSString *applicationCaches;\n@property (readonly, class, copy, nullable) NSURL *applicationCachesURL;\n\n@property (readonly, class, copy, nullable) NSString *groupContainer;\n@property (readonly, class, copy, nullable) NSURL *groupContainerURL;\n\n@property (readonly, class, copy, nullable) NSString *groupContainerApplicationCaches;\n@property (readonly, class, copy, nullable) NSURL *groupContainerApplicationCachesURL;\n\n@property (readonly, class, copy, nullable) NSString *applicationSupport;\n@property (readonly, class, copy, nullable) NSURL *applicationSupportURL;\n\n@property (readonly, class, copy, nullable) NSString *groupContainerApplicationSupport;\n@property (readonly, class, copy, nullable) NSURL *groupContainerApplicationSupportURL;\n\n@property (readonly, class, copy, nullable) NSString *applicationLogs;\n@property (readonly, class, copy, nullable) NSURL *applicationLogsURL;\n\n@property (readonly, class, copy) NSString *applicationTemporary;\n@property (readonly, class, copy) NSURL *applicationTemporaryURL;\n\n@property (readonly, class, copy) NSString *applicationTemporaryProcessSpecific;\n@property (readonly, class, copy) NSURL *applicationTemporaryProcessSpecificURL;\n\n@property (readonly, class, copy) NSString *bundledExtensions;\n@property (readonly, class, copy) NSURL *bundledExtensionsURL;\n\n@property (readonly, class, copy) NSString *bundledScripts;\n@property (readonly, class, copy) NSURL *bundledScriptsURL;\n\n@property (readonly, class, copy) NSString *bundledThemes;\n@property (readonly, class, copy) NSURL *bundledThemesURL;\n\n@property (readonly, class, copy, nullable) NSString *customExtensions;\n@property (readonly, class, copy, nullable) NSURL *customExtensionsURL;\n\n@property (readonly, class, copy, nullable) NSString *customScripts;\n@property (readonly, class, copy, nullable) NSURL *customScriptsURL;\n\n@property (readonly, class, copy, nullable) NSString *customThemes;\n@property (readonly, class, copy, nullable) NSURL *customThemesURL;\n\n#pragma mark -\n#pragma mark System Specific\n\n@property (readonly, class, copy, nullable) NSString *systemApplications;\n@property (readonly, class, copy, nullable) NSURL *systemApplicationsURL;\n\n@property (readonly, class, copy) NSString *systemDiagnosticReports;\n@property (readonly, class, copy) NSURL *systemDiagnosticReportsURL;\n\n#pragma mark -\n#pragma mark User Specific\n\n@property (readonly, class, copy, nullable) NSString *userApplicationScripts;\n@property (readonly, class, copy, nullable) NSURL *userApplicationScriptsURL;\n\n@property (readonly, class, copy) NSString *userDiagnosticReports;\n@property (readonly, class, copy) NSURL *userDiagnosticReportsURL;\n\n@property (readonly, class, copy, nullable) NSString *userDownloads;\n@property (readonly, class, copy, nullable) NSURL *userDownloadsURL;\n\n@property (readonly, class, copy) NSString *userHome;\n@property (readonly, class, copy) NSURL *userHomeURL;\n\n@property (readonly, class, copy, nullable) NSString *userPreferences;\n@property (readonly, class, copy, nullable) NSURL *userPreferencesURL;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCPreferencesImportExport.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferencesImportExport : NSObject\n+ (void)importInWindow:(NSWindow *)window;\n\n+ (void)exportInWindow:(NSWindow *)window;\n\n+ (NSDictionary<NSString *, id> *)exportedPreferencesDictionary;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCPreferencesLocal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLONotificationController.h\"\n#import \"TPCPreferences.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString * const TPCPreferencesThemeNameDefaultsKey;\nTEXTUAL_EXTERN NSString * const TPCPreferencesThemeFontNameDefaultsKey;\nTEXTUAL_EXTERN NSString * const TPCPreferencesThemeFontSizeDefaultsKey;\n\nTEXTUAL_EXTERN NSString * const TPCPreferencesThemeNameMissingLocallyDefaultsKey;\nTEXTUAL_EXTERN NSString * const TPCPreferencesThemeFontNameMissingLocallyDefaultsKey;\n\nTEXTUAL_EXTERN NSUInteger const TPCPreferencesDictionaryVersion;\n\ntypedef NS_ENUM(NSUInteger, TXNicknameHighlightMatchType) {\n\tTXNicknameHighlightMatchTypePartial = 0,\n\tTXNicknameHighlightMatchTypeExact,\n    TXNicknameHighlightMatchTypeRegularExpression,\n};\n\ntypedef NS_ENUM(NSUInteger, TXTabKeyAction) {\n\tTXTabKeyActionNicknameComplete = 0,\n\tTXTabKeyActionUnreadChannel,\n\tTXTabKeyActionNone = 100,\n};\n\ntypedef NS_ENUM(NSUInteger, TXUserDoubleClickAction) {\n\tTXUserDoubleClickActionWhois = 100,\n\tTXUserDoubleClickActionPrivateMessage = 200,\n\tTXUserDoubleClickActionInsertTextField = 300,\n};\n\ntypedef NS_ENUM(NSUInteger, TXNoticeSendLocation) {\n\tTXNoticeSendLocationServerConsole = 0,\n\tTXNoticeSendLocationSelectedChannel = 1,\n\tTXNoticeSendLocationQuery = 2,\n};\n\ntypedef NS_ENUM(NSUInteger, TXCommandWKeyAction) {\n\tTXCommandWKeyActionCloseWindow = 0,\n\tTXCommandWKeyActionPartChannel = 1,\n\tTXCommandWKeyActionDisconnect = 2,\n\tTXCommandWKeyActionTerminate = 3,\n};\n\ntypedef NS_ENUM(NSUInteger, TXHostmaskBanFormat) {\n\tTXHostmaskBanFormatWHNIN  = 0, // With Hostmask, No Username/Nickname\n\tTXHostmaskBanFormatWHAINN = 1, // With Hostmask and Username, No Nickname\n\tTXHostmaskBanFormatWHANNI = 2, // With Hostmask and Nickname, No Username\n\tTXHostmaskBanFormatExact  = 3, // Exact Match\n};\n\ntypedef NS_ENUM(NSUInteger, TVCMainWindowTextViewFontSize) {\n\tTVCMainWindowTextViewFontSizeNormal\t\t\t= 1,\n\tTVCMainWindowTextViewFontSizeLarge\t\t\t= 2,\n\tTVCMainWindowTextViewFontSizeExtraLarge\t\t= 3,\n\tTVCMainWindowTextViewFontSizeHumongous\t\t= 4,\n};\n\ntypedef NS_ENUM(NSUInteger, TXFileTransferRequestReply) {\n\tTXFileTransferRequestReplyIgnore\t\t\t\t\t= 1,\n\tTXFileTransferRequestReplyOpenDialog\t\t\t\t= 2,\n\tTXFileTransferRequestReplyAutomaticallyDownload\t\t= 3,\n};\n\ntypedef NS_ENUM(NSUInteger, TXFileTransferIPAddressMethodDetection) {\n\t/* integers are out of order to preserve existing preferences */\n\tTXFileTransferIPAddressMethodRouterOnly \t\t\tNS_SWIFT_NAME(routerOnly)\t\t\t= 3,\n\tTXFileTransferIPAddressMethodRouterAndFirstParty \tNS_SWIFT_NAME(routerAndFirstParty)\t= 1,\n\tTXFileTransferIPAddressMethodRouterAndThirdParty\tNS_SWIFT_NAME(routerAndThirdParty)\t= 4,\n\tTXFileTransferIPAddressMethodManual\t\t\t\t\tNS_SWIFT_NAME(manual)\t\t\t\t= 2,\n};\n\ntypedef NS_ENUM(NSUInteger, TXChannelViewArrangement) {\n\tTXChannelViewArrangedHorizontally\tNS_SWIFT_NAME(horizontal) \t= 0,\n\tTXChannelViewArrangedVertically \tNS_SWIFT_NAME(vertical)\t\t= 1\n};\n\ntypedef NS_ENUM(NSUInteger, TXPreferredAppearance) {\n\tTXPreferredAppearanceInherited \t= 0,\n\tTXPreferredAppearanceLight \t\t= 1,\n\tTXPreferredAppearanceDark\t\t= 2\n};\n\n@interface TPCPreferences (TPCPreferencesLocal)\n+ (BOOL)appNapEnabled;\n\n+ (BOOL)developerModeEnabled;\n\n+ (nullable NSString *)masqueradeCTCPVersion;\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n+ (BOOL)receiveBetaUpdates;\n#endif\n\n+ (BOOL)channelNavigationIsServerSpecific;\n\n+ (BOOL)automaticallyDetectHighlightSpam;\n\n+ (BOOL)rememberServerListQueryStates;\n\n+ (TVCMainWindowTextViewFontSize)mainTextViewFontSize;\n+ (BOOL)focusMainTextViewOnSelectionChange;\n\n+ (BOOL)logToDisk; // Checks whether checkbox for logging is checked.\n+ (BOOL)logToDiskIsEnabled; // Checks whether checkbox is checked and whether an actual path is configured.\n\n+ (BOOL)postNotificationsWhileInFocus;\n\n+ (BOOL)automaticallyFilterUnicodeTextSpam;\n\n+ (BOOL)conversationTrackingIncludesUserModeSymbol;\n\n+ (NSString *)defaultRealName;\n+ (NSString *)defaultUsername;\n+ (NSString *)defaultNickname;\n+ (nullable NSString *)defaultAwayNickname;\n+ (NSString *)defaultKickMessage;\n\n+ (NSString *)IRCopDefaultKillMessage;\n+ (NSString *)IRCopDefaultGlineMessage;\n+ (NSString *)IRCopDefaultShunMessage;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n+ (BOOL)textEncryptionIsOpportunistic;\n+ (BOOL)textEncryptionIsRequired;\n+ (BOOL)textEncryptionIsEnabled;\n#endif\n\n+ (BOOL)enableEchoMessageCapability;\n\n+ (BOOL)giveFocusOnMessageCommand;\n\n+ (BOOL)amsgAllConnections;\n+ (BOOL)awayAllConnections;\n+ (BOOL)nickAllConnections;\n+ (BOOL)clearAllConnections;\n\n+ (BOOL)memberListSortFavorsServerStaff;\n+ (BOOL)memberListUpdatesUserInfoPopoverOnScroll;\n+ (BOOL)memberListDisplayNoModeSymbol;\n\n+ (TXNoticeSendLocation)locationToSendNotices;\n\n+ (BOOL)disableNicknameColorHashing;\n\n+ (BOOL)displayDockBadge;\n+ (BOOL)displayPublicMessageCountOnDockBadge;\n\n+ (BOOL)setAwayOnScreenSleep;\n+ (BOOL)disconnectOnSleep;\n\n+ (BOOL)preferModernCiphers;\n+ (BOOL)preferModernSockets;\n\n+ (BOOL)autoAddScrollbackMark;\n+ (BOOL)showDateChanges;\n+ (BOOL)showInlineMedia;\n+ (BOOL)showJoinLeave;\n+ (BOOL)displayServerMOTD;\n+ (BOOL)rightToLeftFormatting;\n+ (BOOL)removeAllFormatting;\n\n+ (NSUInteger)trackUserAwayStatusMaximumChannelSize;\n\n+ (TXPreferredAppearance)appearance;\n\n+ (BOOL)disableSidebarTranslucency;\n+ (BOOL)hideMainWindowSegmentedController;\n\n+ (BOOL)reloadScrollbackOnLaunch;\n\n+ (BOOL)automaticallyReloadCustomThemesWhenTheyChange;\n\n+ (BOOL)autoJoinOnInvite;\n\n+ (BOOL)confirmQuit;\n+ (BOOL)rejoinOnKick;\n+ (BOOL)copyOnSelect;\n+ (BOOL)replyToCTCPRequests;\n\n+ (BOOL)inputHistoryIsChannelSpecific;\n\n+ (TXCommandWKeyAction)commandWKeyAction;\n\n+ (BOOL)commandReturnSendsMessageAsAction;\n+ (BOOL)controlEnterSendsMessage;\n\n+ (BOOL)openBrowserInBackground;\n\n+ (BOOL)connectOnDoubleclick;\n+ (BOOL)disconnectOnDoubleclick;\n+ (BOOL)joinOnDoubleclick;\n+ (BOOL)leaveOnDoubleclick;\n\n+ (NSUInteger)autojoinMaximumChannelJoins;\n+ (NSTimeInterval)autojoinDelayBetweenChannelJoins;\n+ (NSTimeInterval)autojoinDelayAfterIdentification;\n\n+ (TXUserDoubleClickAction)userDoubleClickOption;\n\n+ (TXHostmaskBanFormat)banFormat;\n\n+ (BOOL)webKit2Enabled;\n+ (BOOL)webKit2ProcessPoolSizeLimited;\n+ (BOOL)webKit2PreviewLinks;\n\n+ (NSString *)themeName;\n+ (NSString *)themeNameDefault;\n\n+ (NSString *)themeNicknameFormat;\n+ (NSString *)themeNicknameFormatDefault;\n\n+ (NSString *)themeTimestampFormat;\n+ (NSString *)themeTimestampFormatDefault;\n\n+ (nullable NSString *)themeUserStyleSheetRules;\n\n+ (CGFloat)mainWindowTransparency;\n\n+ (nullable NSFont *)themeChannelViewFont;\n+ (NSString *)themeChannelViewFontName;\n+ (NSString *)themeChannelViewFontNameDefault;\n+ (CGFloat)themeChannelViewFontSize;\n\n+ (BOOL)themeNicknameFormatPreferenceUserConfigurable;\n+ (BOOL)themeTimestampFormatPreferenceUserConfigurable;\n+ (BOOL)themeChannelViewFontPreferenceUserConfigurable;\n\n+ (BOOL)themeChannelViewUsesCustomScrollers;\n\n+ (NSUInteger)scrollbackSaveLimit;\n+ (NSUInteger)scrollbackVisibleLimit;\n\n+ (TXChannelViewArrangement)channelViewArrangement;\n\n+ (BOOL)soundIsMuted;\n\n+ (BOOL)onlySpeakEventsForSelection;\n\n+ (BOOL)channelMessageSpeakChannelName;\n+ (BOOL)channelMessageSpeakNickname;\n\n+ (nullable NSString *)soundForEvent:(TXNotificationType)event;\n\n+ (BOOL)speakEvent:(TXNotificationType)event;\n+ (BOOL)notificationEnabledForEvent:(TXNotificationType)event;\n+ (BOOL)disabledWhileAwayForEvent:(TXNotificationType)event;\n+ (BOOL)bounceDockIconForEvent:(TXNotificationType)event;\n+ (BOOL)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event;\n\n+ (TXTabKeyAction)tabKeyAction;\n\n+ (BOOL)fileTransferRequestsAreReversed;\n+ (BOOL)fileTransfersPreventIdleSystemSleep;\n\n+ (TXFileTransferRequestReply)fileTransferRequestReplyAction;\n+ (TXFileTransferIPAddressMethodDetection)fileTransferIPAddressDetectionMethod;\n\n+ (uint16_t)fileTransferPortRangeStart;\n+ (uint16_t)fileTransferPortRangeEnd;\n\n+ (nullable NSString *)fileTransferManuallyEnteredIPAddress;\n+ (nullable NSString *)fileTransferIPAddressInterfaceName;\n\n+ (nullable NSString *)tabCompletionSuffix;\n\n+ (BOOL)tabCompletionDoNotAppendWhitespace;\n+ (BOOL)tabCompletionCutForwardToFirstWhitespace;\n\n+ (nullable NSArray<NSDictionary *> *)clientList;\n\n+ (TXNicknameHighlightMatchType)highlightMatchingMethod;\n\n+ (BOOL)logHighlights;\n+ (BOOL)highlightCurrentNickname;\n\n+ (CGFloat)swipeMinimumLength;\n\n+ (nullable NSArray<NSString *> *)highlightMatchKeywords;\n+ (nullable NSArray<NSString *> *)highlightExcludeKeywords;\n\n+ (NSDictionary<NSString *, id> *)defaultPreferences;\n\n+ (BOOL)textFieldAutomaticSpellCheck;\n+ (BOOL)textFieldAutomaticGrammarCheck;\n+ (BOOL)textFieldAutomaticSpellCorrection;\n+ (BOOL)textFieldSmartCopyPaste;\n+ (BOOL)textFieldSmartQuotes;\n+ (BOOL)textFieldSmartDashes;\n+ (BOOL)textFieldSmartLinks;\n+ (BOOL)textFieldDataDetectors;\n+ (BOOL)textFieldTextReplacement;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCPreferencesReload.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_OPTIONS(NSUInteger, TPCPreferencesReloadAction) {\n\tTPCPreferencesReloadActionAppearance\t\t\t\t\t\t\t= 1 << 0,\n\tTPCPreferencesReloadActionChannelViewArrangement\t\t\t\t= 1 << 1,\n\tTPCPreferencesReloadActionDockIconBadges\t\t\t\t\t\t= 1 << 2,\n\tTPCPreferencesReloadActionHighlightKeywords\t\t\t\t\t\t= 1 << 3,\n\tTPCPreferencesReloadActionHighlightLogging\t\t\t\t\t\t= 1 << 4,\n\tTPCPreferencesReloadActionIRCCommandCache\t\t\t\t\t\t= 1 << 5,\n\tTPCPreferencesReloadActionInputHistoryScope\t\t\t\t\t\t= 1 << 6,\n\tTPCPreferencesReloadActionLogTranscripts\t\t\t\t\t\t= 1 << 7,\n\tTPCPreferencesReloadActionMainWindowTransparencyLevel\t\t\t= 1 << 8,\n\tTPCPreferencesReloadActionMemberList\t\t\t\t\t\t\t= 1 << 9,\n\tTPCPreferencesReloadActionMemberListSortOrder\t\t\t\t\t= 1 << 10,\n\tTPCPreferencesReloadActionMemberListUserBadges\t\t\t\t\t= 1 << 11,\n\tTPCPreferencesReloadActionPreferencesChanged\t\t\t\t\t= 1 << 12,\n\tTPCPreferencesReloadActionScrollbackSaveLimit\t\t\t\t\t= 1 << 13,\n\tTPCPreferencesReloadActionScrollbackVisibleLimit\t\t\t\t= 1 << 14,\n\tTPCPreferencesReloadActionServerList\t\t\t\t\t\t\t= 1 << 15,\n\tTPCPreferencesReloadActionServerListUnreadBadges\t\t\t\t= 1 << 16,\n\tTPCPreferencesReloadActionStyle\t\t\t\t\t\t\t\t\t= 1 << 17,\n//\tTPCPreferencesReloadActionStyleWithTableViews\t\t\t\t\t= 1 << 18,\n\tTPCPreferencesReloadActionTextDirection\t\t\t\t\t\t\t= 1 << 19,\n\tTPCPreferencesReloadActionTextFieldFontSize\t\t\t\t\t\t= 1 << 20,\n\tTPCPreferencesReloadActionTextFieldSegmentedControllerOrigin\t= 1 << 21,\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tTPCPreferencesReloadActionEncryptionPolicy\t\t\t\t\t\t= 1 << 22,\n#endif\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tTPCPreferencesReloadActionSparkleFrameworkFeedURL\t\t\t\t= 1 << 23,\n#endif\n};\n\n@interface TPCPreferences (TPCPreferencesReload)\n+ (void)performReloadActionForKeys:(NSArray<NSString *> *)keys;\n+ (void)performReloadAction:(TPCPreferencesReloadAction)reloadAction;\n+ (void)performReloadAction:(TPCPreferencesReloadAction)reloadAction forKey:(nullable NSString *)key; // key is only used for context\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCPreferencesUserDefaultsLocal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesUserDefaults.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferencesUserDefaults (TPCPreferencesUserDefaultsLocal)\n+ (BOOL)keyIsExcludedFromExportImport:(NSString *)defaultName;\n+ (BOOL)keyIsExcludedFromMigration:(NSString *)defaultName;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCResourceManager.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString * const TPCResourceManagerBundleDocumentTypeExtension;\nTEXTUAL_EXTERN NSString * const TPCResourceManagerBundleDocumentTypeExtensionWithoutPeriod;\n\nTEXTUAL_EXTERN NSString * const TPCResourceManagerScriptDocumentTypeExtension;\nTEXTUAL_EXTERN NSString * const TPCResourceManagerScriptDocumentTypeExtensionWithoutPeriod;\n\n@interface TPCResourceManager : NSObject\n/* Open a property list file in the Resources folder of Textual named `name` in optional\n subdirectory `subpath`. If `key` is specified, then the object value of `key` is returned\n from the root object of the property list as long as that object is a dictionary.\n The root object is returned if `key` is not specified if it is a dictionary.\n The value of this returned object is cached unless `cacheValue` is NO.\n Cache is also bypassed when `cacheValue` is NO. */\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name cacheValue:(BOOL)cacheValue;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath cacheValue:(BOOL)cacheValue;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name key:(nullable NSString *)key;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name key:(nullable NSString *)key cacheValue:(BOOL)cacheValue;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key;\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key cacheValue:(BOOL)cacheValue;\n\n/* Open a property list file in the Resources folder of Textual named `name` in optional\n subdirectory `subpath`. If `key` is specified, then the object value of `key` is returned\n from the root object of the property list as long as that object is an array.\n The root object is returned if `key` is not specified if it is an array.\n The value of this returned object is cached unless `cacheValue` is NO.\n Cache is also bypassed when `cacheValue` is NO. */\n+ (nullable NSArray *)arrayFromResources:(NSString *)name;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name cacheValue:(BOOL)cacheValue;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath cacheValue:(BOOL)cacheValue;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name key:(nullable NSString *)key;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name key:(nullable NSString *)key cacheValue:(BOOL)cacheValue;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key;\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key cacheValue:(BOOL)cacheValue;\n\n/* Open a property list file in the Resources folder of Textual named `name` in optional\n subdirectory `subpath`. If `key` is specified, then the object value of `key` is returned\n from the root object of the property list as long as that object is kind of `class`.\n The root object is returned if `key` is not specified if it is kind of `class`.\n The value of this returned object is cached unless `cacheValue` is NO.\n Cache is also bypassed when `cacheValue` is NO. */\n+ (nullable id)objectFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key kindOf:(Class)class cacheValue:(BOOL)cacheValue;\n\n/* This cache object is used for loading resources using the methods above.\n The key used for each cache entry is an implementation detail and is subject to change. */\n@property (class, strong, readonly) NSCache *sharedResourcesCache;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCTheme.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define TPCThemeSettingsDisabledIndentationOffset\t -99\n\n#define TPCThemeSettingsNewestTemplateEngineVersion\t\t4\n\ntypedef NS_ENUM(NSUInteger, TPCThemeAppearanceType) {\n\tTPCThemeAppearanceTypeDefault = 0, // Automatically picked based on window appearance\n\tTPCThemeAppearanceTypeDark,\n\tTPCThemeAppearanceTypeLight\n};\n\ntypedef NS_ENUM(NSUInteger, TPCThemeStorageLocation) {\n\tTPCThemeStorageLocationUnknown = 0,\n\tTPCThemeStorageLocationBundle,\n\tTPCThemeStorageLocationCustom\n};\n\ntypedef NS_ENUM(NSUInteger, TPCThemeSettingsNicknameColorStyle) {\n\tTPCThemeSettingsNicknameColorStyleDefault = 0, // Automatically picked based on appearance\n\tTPCThemeSettingsNicknameColorStyleDark,\n\tTPCThemeSettingsNicknameColorStyleLight\n};\n\n/* If a theme is modified in such a way after it is initialized\n that it can no longer be used, then this notification is posted.\n A way, amongst many, in which the integrity of a theme can\n be compromised is by deleting the CSS or JavaScript file. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeIntegrityCompromisedNotification;\n\n/* If theme has been restored to a usable state. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeIntegrityRestoredNotification;\n\n/* If the theme has been deleted. Drop reference to theme object\n when this occurs. Holding a reference to a theme object after\n it has been deleted can result in undefined behavior especially\n if another theme is installed using the same URL. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeWasDeletedNotification;\n\n/* The theme can change the variety to match appearance changes,\n or when one variety becomes compromised and another must be used. */\n/* Notification used for first case. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeAppearanceChangedNotification;\n\n/* Notification used for second case. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeVarietyChangedNotification;\n\n/* A CSS or JavaScript file within the global variety or the variety\n in use was modified. */\nTEXTUAL_EXTERN NSNotificationName const TPCThemeWasModifiedNotification;\n\n@class GRMustacheTemplate, GRMustacheTemplateRepository;\n@class TPCThemeSettings;\n\n@interface TPCTheme : NSObject\n@property (readonly, copy) NSString *name;\n\n@property (readonly, copy) NSURL *originalURL;\n@property (readonly) TPCThemeStorageLocation storageLocation;\n\n@property (readonly) BOOL usable; // If the theme is in a state that can be selected by the user.\n\n@property (readonly) TPCThemeAppearanceType appearance;\n\n/* Global files are listed first with variety specific files second. */\n/* These properties DO NOT list all files of these types.\n Only files named \"design.css\" and \"scripts.js\" respectively. */\n@property (readonly, copy) NSArray<NSURL *> *cssFiles;\n@property (readonly, copy) NSArray<NSURL *> *jsFiles;\n\n@property (readonly, copy) NSArray<NSString *> *cssFilePaths;\n@property (readonly, copy) NSArray<NSString *> *jsFilePaths;\n\n/* Order of repositories is: variety specific -> global -> app */\n@property (readonly, copy) NSArray<GRMustacheTemplateRepository *> *templateRepositories;\n\n/* Settings */\n@property (readonly, strong) TPCThemeSettings *settings;\n\n/* Temporary location */\n/* Themes are copied to a temporary location when they are in use. */\n/* These properties remap the relevant URLs to the temporary location. */\n/* These files will not exist until the theme is in use. */\n@property (readonly, copy) NSURL *temporaryURL;\n\n@property (readonly, copy) NSArray<NSURL *> *temporaryCSSFiles;\n@property (readonly, copy) NSArray<NSURL *> *temporaryJSFiles;\n\n@property (readonly, copy) NSArray<NSString *> *temporaryCSSFilePaths;\n@property (readonly, copy) NSArray<NSString *> *temporaryJSFilePaths;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n/* Templates */\n- (nullable GRMustacheTemplate *)templateWithLineType:(TVCLogLineType)type;\n- (nullable GRMustacheTemplate *)templateWithName:(NSString *)name;\n@end\n\n@interface TPCThemeSettings : NSObject\n@property (readonly) TPCThemeAppearanceType appearance;\n@property (readonly) BOOL invertSidebarColors;\n@property (readonly) BOOL js_postHandleEventNotifications;\n@property (readonly) BOOL js_postAppearanceChangesNotification;\n@property (readonly) BOOL js_postPreferencesDidChangesNotifications;\n@property (readonly) BOOL usesIncompatibleTemplateEngineVersion;\n@property (readonly, copy, nullable) NSFont *themeChannelViewFont;\n@property (readonly, copy, nullable) NSString *themeNicknameFormat;\n@property (readonly, copy, nullable) NSString *themeTimestampFormat;\n@property (readonly, copy, nullable) NSString *settingsKeyValueStoreName;\n@property (readonly, copy, nullable) NSColor *channelViewOverlayColor;\n@property (readonly, copy, nullable) NSColor *underlyingWindowColor;\n@property (readonly) BOOL underlyingWindowColorIsDark;\n@property (readonly) double indentationOffset;\n@property (readonly) TPCThemeSettingsNicknameColorStyle nicknameColorStyle;\n@property (readonly) NSUInteger templateEngineVersion;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (nullable id)styleSettingsRetrieveValueForKey:(NSString *)key error:(NSString * _Nullable * _Nullable)resultError;\n- (BOOL)styleSettingsSetValue:(nullable id)objectValue forKey:(NSString *)objectKey error:(NSString * _Nullable * _Nullable)resultError;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TPCThemeController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCTheme.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString * const TPCThemeControllerCustomThemeNameBasicPrefix;\nTEXTUAL_EXTERN NSString * const TPCThemeControllerCustomThemeNameCompletePrefix;\n\nTEXTUAL_EXTERN NSString * const TPCThemeControllerBundledThemeNameBasicPrefix;\nTEXTUAL_EXTERN NSString * const TPCThemeControllerBundledThemeNameCompletePrefix;\n\nTEXTUAL_EXTERN NSNotificationName const TPCThemeControllerThemeListDidChangeNotification;\n\n/* Theme is not loaded until main window is woken which means\n while you could in theory access this object before then,\n objects below that are marked non-nil will actually be nil. */\n@interface TPCThemeController : NSObject\n@property (readonly, strong) TPCTheme *theme;\n\n@property (readonly, strong) TPCThemeSettings *settings;\n\n@property (readonly) TPCThemeStorageLocation storageLocation;\n\n@property (readonly, copy) NSString *name;\n\n@property (readonly, copy) NSURL *originalURL; // Where original copy of theme is.\n@property (readonly, copy) NSURL *temporaryURL; // Where cached copy of theme is.\n\n@property (readonly, copy) NSString *originalPath;\n@property (readonly, copy) NSString *temporaryPath;\n\n@property (readonly, copy) NSString *cacheToken;\n\n@property (getter=isBundledTheme, readonly) BOOL bundledTheme;\n\n/* Calls for all themes */\n- (void)enumerateAvailableThemesWithBlock:(void(NS_NOESCAPE ^)(NSString *fileName, TPCThemeStorageLocation storageLocation, BOOL multipleVariants, BOOL *stop))enumerationBlock;\n\n- (BOOL)themeExists:(NSString *)themeName;\n\n+ (nullable NSString *)pathOfThemeWithName:(NSString *)themeName;\n+ (nullable NSString *)pathOfThemeWithName:(NSString *)themeName storageLocation:(nullable TPCThemeStorageLocation *)storageLocation;\n\n+ (nullable NSString *)buildFilename:(NSString *)name forStorageLocation:(TPCThemeStorageLocation)storageLocation;\n\n+ (nullable NSString *)extractThemeSource:(NSString *)source;\n+ (nullable NSString *)extractThemeName:(NSString *)source;\n\n+ (TPCThemeStorageLocation)storageLocationOfThemeWithName:(NSString *)themeName;\n\n+ (nullable NSString *)descriptionForStorageLocation:(TPCThemeStorageLocation)storageLocation;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCAlert.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* TVCAlert acts as a non-blocking substitute to NSAlert\n which can be used to show messages that aren't important. */\ntypedef NS_ENUM(NSUInteger, TVCAlertResponseButton) {\n\tTVCAlertResponseButtonFirst = 1000,\n\tTVCAlertResponseButtonSecond = 1001,\n\tTVCAlertResponseButtonThird = 1002\n};\n\ntypedef NS_ENUM(NSUInteger, TVCAlertType)\n{\n\t/* Standard alert */\n\tTVCAlertTypeInformational = 0,\n\n\t/* Warning icon appears above icon. No other difference. */\n\tTVCAlertTypeWarning\n};\n\n@class TVCAlert;\n\ntypedef void (^TVCAlertCompletionBlock)(TVCAlert *sender, TVCAlertResponseButton buttonClicked);\ntypedef BOOL (^TVCAlertButtonClickedBlock)(TVCAlert *sender, TVCAlertResponseButton buttonClicked);\n\n@interface TVCAlert : NSObject\n/* All properties are immutable once alert is visible */\n@property (nonatomic, copy) NSString *messageText;\n@property (nonatomic, copy) NSString *informativeText;\n\n@property (nonatomic, strong, null_resettable) NSImage *icon;\n\n@property (nonatomic, assign) TVCAlertType type;\n\n- (NSButton *)setTitle:(NSString *)title forButton:(TVCAlertResponseButton)button;\n- (NSButton *)setTitle:(NSString *)title forButtonAtIndex:(NSUInteger)index;\n\n@property (copy, readonly) NSArray<NSButton *> *buttons;\n\n@property (nonatomic, assign) BOOL showsSuppressionButton;\n\n@property (readonly, weak) NSButton *suppressionButton;\n\n@property (nonatomic, strong, nullable) NSView *accessoryView;\n\n@property (readonly, strong) NSWindow *window;\n\n- (void)showAlert;\n- (void)showAlertWithCompletionBlock:(nullable TVCAlertCompletionBlock)completionBlock;\n\n- (void)showAlertInWindow:(NSWindow *)window;\n- (void)showAlertInWindow:(NSWindow *)window withCompletionBlock:(nullable TVCAlertCompletionBlock)completionBlock;\n\n- (TVCAlertResponseButton)runModal;\n\n/* A block that is called when a button is clicked.\n\n If the block returns YES, then the alert is dismissed.\n If the block returns NO, then no action is taken.\n\n This feature allows you to take action when a button is clicked,\n while keeping it visible to the user, without the need to override\n the target / action of the button in question. */\n/* Changing a button clicked block is permitted with an alert visible. */\n/* An exception is thrown for out-of-bounds access so call this AFTER\n a button at the index is added. */\n- (void)setButtonClickedBlock:(nullable TVCAlertButtonClickedBlock)block forButton:(TVCAlertResponseButton)button;\n- (void)setButtonClickedBlock:(nullable TVCAlertButtonClickedBlock)block forButtonAtIndex:(NSUInteger)index;\n\n/* End alert */\n- (void)endAlert; // TVCAlertResponseButtonFirst\n- (void)endAlertWithResponse:(TVCAlertResponseButton)response;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCAppearance : NSObject\n- (instancetype)init NS_UNAVAILABLE;\n\n/* Top level group */\n/* Nonnull until -flushAppearanceProperties is called. */\n@property (readonly, copy, nullable) NSDictionary<NSString *, id> *appearanceProperties;\n\n/* Properties */\n@property (readonly) BOOL isHighResolutionAppearance;\n\n/* Stateless Accessors */\n- (nullable NSColor *)colorForKey:(NSString *)key;\n- (nullable NSColor *)colorInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n- (nullable NSGradient *)gradientForKey:(NSString *)key;\n- (nullable NSGradient *)gradientInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n- (nullable NSFont *)fontForKey:(NSString *)key;\n- (nullable NSFont *)fontInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n- (nullable NSImage *)imageForKey:(NSString *)key;\n- (nullable NSImage *)imageInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n- (NSSize)sizeForKey:(NSString *)key;\n- (NSSize)sizeInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n- (CGFloat)measurementForKey:(NSString *)key;\n- (CGFloat)measurementInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key;\n\n/* Stateful Accessors */\n/* Stateful appearance properties require the properties to have a\n \"activeWindow\" and \"inactiveWindow\" dictionary value which contains\n the value of the property itself. */\n/*\n Example:\n\n <key>exampleStatefulColor</key>\n <dict>\n\t <key>activeWindow</key>\n\t <dict>\n\t\t <key>type</key>\n\t\t <integer>1</integer>\n\t\t <key>value</key>\n\t\t <string>0.0 0.3</string>\n\t </dict>\n\t <key>inactiveWindow</key>\n\t <dict>\n\t\t <key>type</key>\n\t\t <integer>1</integer>\n\t\t <key>value</key>\n\t\t <string>1.0</string>\n\t </dict>\n </dict>\n*/\n- (nullable NSColor *)colorForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n- (nullable NSColor *)colorInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n\n- (nullable NSGradient *)gradientForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n- (nullable NSGradient *)gradientInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n\n- (nullable NSFont *)fontForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n- (nullable NSFont *)fontInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n\n- (nullable NSImage *)imageForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n- (nullable NSImage *)imageInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow;\n@end\n\n/* TVCApplicationAppearance keeps a copy of TXAppearance properties.\n The properties it keeps are those that were set when the object was created.\n To update to the latest properties, create a new instance of the object. */\n@interface TVCApplicationAppearance : TVCAppearance <TXAppearanceProperties>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCAutoExpandingTextField.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCAutoExpandingTextField : NSTextField\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCAutoExpandingTokenField.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCAutoExpandingTokenField : NSTokenField\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCBasicTableView.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCBasicTableView : NSTableView\n@property (nonatomic, weak) id pasteboardDelegate;\n@property (nonatomic, weak) id textEditingDelegate;\n\n@property (readonly, assign) BOOL presentMenuForEmptySelection;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCChannelSelectionViewController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@protocol TVCChannelSelectionViewControllerDelegate;\n\n@interface TVCChannelSelectionViewController : NSObject\n@property (nonatomic, weak) id <TVCChannelSelectionViewControllerDelegate> delegate;\n\n@property (nonatomic, copy) NSArray<NSString *> *selectedClientIds;\n@property (nonatomic, copy) NSArray<NSString *> *selectedChannelIds;\n\n- (void)attachToView:(NSView *)view;\n@end\n\n#pragma mark -\n\n@protocol TVCChannelSelectionViewControllerDelegate <NSObject>\n@required\n\n- (void)channelSelectionControllerSelectionChanged:(TVCChannelSelectionViewController *)controller;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCLogController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel;\n@class TVCLogLine, TVCLogView, TVCMainWindow;\n\nTEXTUAL_EXTERN NSNotificationName const TVCLogControllerViewFinishedLoadingNotification;\n\n@interface TVCLogController : NSObject\n@property (readonly) TVCLogView *backingView;\n@property (readonly, getter=viewIsEncrypted) BOOL encrypted;\n@property (readonly, getter=viewIsLoaded) BOOL loaded;\n@property (readonly, getter=viewIsSelected) BOOL selected;\n@property (readonly, getter=viewIsVisible) BOOL visible;\n@property (readonly) NSUInteger numberOfLines;\n@property (readonly, weak) IRCClient *associatedClient;\n@property (readonly, weak) IRCChannel *associatedChannel;\n@property (readonly, weak) TVCMainWindow *attachedWindow;\n@property (readonly, copy, nullable) NSString *newestLineNumberFromPreviousSession;\n@property (readonly, copy, nullable) NSString *oldestLineNumber;\n@property (readonly, copy, nullable) NSString *newestLineNumber;\n\n- (instancetype)init NS_UNAVAILABLE;\n\n- (void)nextHighlight;\n- (void)previousHighlight;\n\n- (BOOL)highlightAvailable:(BOOL)previous;\n\n@property (readonly, copy) NSString *uniqueIdentifier;\n\n- (void)moveToTop;\n- (void)moveToBottom;\n\n- (void)jumpToCurrentSession;\n- (void)jumpToPresent;\n\n- (void)jumpToLine:(NSString *)lineNumber;\n- (void)jumpToLine:(NSString *)lineNumber completionHandler:(void (^ _Nullable)(BOOL result))completionHandler;\n\n- (void)setTopic:(nullable NSString *)topic;\n\n@property (readonly) BOOL inlineMediaEnabledForView;\n\n- (void)mark;\n- (void)unmark;\n\n- (void)goToMark;\n\n- (void)clear;\n\n- (void)changeTextSize:(BOOL)bigger;\n\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments; // Defaults to onQueue YES\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments onQueue:(BOOL)onQueue;\n@end\n\n#pragma mark -\n\n@interface TVCLogControllerPrintOperationContext : NSObject\n@property (readonly, weak) IRCClient *client;\n@property (readonly, weak) IRCChannel *channel;\n@property (readonly, getter=isHighlight) BOOL highlight;\n@property (readonly, copy) TVCLogLine *logLine;\n@property (readonly, copy) NSString *lineNumber;\n@end\n\ntypedef void (^TVCLogControllerPrintOperationCompletionBlock)(TVCLogControllerPrintOperationContext *context);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCLogLine.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannel;\n\nTEXTUAL_EXTERN NSString * const TVCLogLineUndefinedNicknameFormat;\nTEXTUAL_EXTERN NSString * const TVCLogLineActionNicknameFormat;\nTEXTUAL_EXTERN NSString * const TVCLogLineNoticeNicknameFormat;\n\nTEXTUAL_EXTERN NSString * const TVCLogLineSpecialNoticeMessageFormat;\n\nTEXTUAL_EXTERN NSString * const TVCLogLineDefaultCommandValue;\n\ntypedef NS_ENUM(NSUInteger, TVCLogLineType) {\n\tTVCLogLineTypeUndefined\t\t\t\t\t= 0,\n\tTVCLogLineTypeAction,\n\tTVCLogLineTypeActionNoHighlight,\n\tTVCLogLineTypeCTCP,\n\tTVCLogLineTypeCTCPQuery,\n\tTVCLogLineTypeCTCPReply,\n\tTVCLogLineTypeDCCFileTransfer,\n\tTVCLogLineTypeDebug,\n\tTVCLogLineTypeInvite,\n\tTVCLogLineTypeJoin,\n\tTVCLogLineTypeKick,\n\tTVCLogLineTypeKill,\n\tTVCLogLineTypeMode,\n\tTVCLogLineTypeNick,\n\tTVCLogLineTypeNotice,\n\tTVCLogLineTypeOffTheRecordEncryptionStatus,\n\tTVCLogLineTypePart,\n\tTVCLogLineTypePrivateMessage,\n\tTVCLogLineTypePrivateMessageNoHighlight,\n\tTVCLogLineTypeQuit,\n\tTVCLogLineTypeTopic,\n\tTVCLogLineTypeWebsite,\n};\n\ntypedef NS_ENUM(NSUInteger, TVCLogLineMemberType) {\n\tTVCLogLineMemberTypeNormal = 0,\n\tTVCLogLineMemberTypeLocalUser,\n};\n\n#define IRCCommandFromLineType(t)\t\t[TVCLogLine stringForLineType:t]\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface TVCLogLine : XRPortablePropertyObject\n@property (readonly) BOOL isEncrypted;\n@property (readonly) BOOL isFirstForDay; // // YES if is first line for the day defined by receivedAt\n@property (readonly, copy) NSDate *receivedAt;\n@property (readonly, copy) NSString *nicknameColorStyle;\n@property (readonly) BOOL nicknameColorStyleOverride; // YES if the nicknameColorStyle was set by the user\n@property (readonly, copy, nullable) NSString *nickname;\n@property (readonly, copy) NSString *messageBody;\n@property (readonly, copy) NSString *command; // Can be the actual command (PRIVMSG, NOTICE, etc.) or the raw numeric (001, 002, etc.)\n@property (readonly, copy) NSString *uniqueIdentifier;\n@property (readonly) TVCLogLineType lineType;\n@property (readonly) TVCLogLineMemberType memberType;\n@property (readonly, copy, nullable) NSArray<NSString *> *highlightKeywords;\n@property (readonly, copy, nullable) NSArray<NSString *> *excludeKeywords;\n@property (readonly, copy, nullable) NSDictionary<NSString *, id> *rendererAttributes;\n@property (readonly) NSUInteger sessionIdentifier;\n\n- (nullable instancetype)initWithData:(NSData *)data NS_DESIGNATED_INITIALIZER;\n\n@property (readonly, copy) NSString *formattedTimestamp;\n\n@property (readonly, copy) NSString *formattedNickname;\n- (nullable NSString *)formattedNicknameInChannel:(nullable IRCChannel *)channel;\n\n@property (readonly, copy, nullable) NSString *lineTypeString;\n@property (readonly, copy) NSString *memberTypeString;\n\n+ (nullable NSString *)stringForLineType:(TVCLogLineType)type;\n+ (NSString *)stringForMemberType:(TVCLogLineMemberType)type;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface TVCLogLineMutable : TVCLogLine\n@property (nonatomic, assign, readwrite) BOOL isEncrypted;\n@property (nonatomic, assign, readwrite) BOOL isFirstForDay;\n@property (nonatomic, copy, readwrite) NSDate *receivedAt;\n@property (nonatomic, copy, readwrite, nullable) NSString *nickname;\n@property (nonatomic, copy, readwrite) NSString *messageBody;\n@property (nonatomic, copy, readwrite) NSString *command;\n@property (nonatomic, assign, readwrite) TVCLogLineType lineType;\n@property (nonatomic, assign, readwrite) TVCLogLineMemberType memberType;\n@property (nonatomic, copy, readwrite, nullable) NSArray<NSString *> *highlightKeywords;\n@property (nonatomic, copy, readwrite, nullable) NSArray<NSString *> *excludeKeywords;\n@property (nonatomic, copy, readwrite, nullable) NSDictionary<NSString *, id> *rendererAttributes;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCLogRenderer.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class GRMustacheTemplate;\n@class TVCLogController;\n\ntypedef NSString *TVCLogRendererConfigurationAttribute NS_STRING_ENUM;\ntypedef NSString *TVCLogRendererResultsAttribute NS_STRING_ENUM;\n\n/* Properties to configure the renderer and provide additional\n context so that it can provide the best possible results. */\n/* These properties do not apply to attributed strings */\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationRenderLinksAttribute; // BOOL\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationLineTypeAttribute; // TVCLogLineType\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationMemberTypeAttribute; // TVCLogMemberType\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationHighlightKeywordsAttribute; // NSArray<NSString *>\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationExcludedKeywordsAttribute; // NSArray<NSString *>\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationDoNotEscapeBodyAttribute; // BOOL\n\n/* These properties apply to attributed strings */\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationAttributedStringPreferredFontAttribute; // NSFont\nTEXTUAL_EXTERN TVCLogRendererConfigurationAttribute const TVCLogRendererConfigurationAttributedStringPreferredFontColorAttribute; // NSColor\n\n/* Properties that are returned in the outputDictionary of a render */\n/* The output dictionary is not guaranteed to contain any key. */\nTEXTUAL_EXTERN TVCLogRendererResultsAttribute const TVCLogRendererResultsListOfLinksInBodyAttribute; // NSArray<AHHyperlinkScannerResult *>\nTEXTUAL_EXTERN TVCLogRendererResultsAttribute const TVCLogRendererResultsListOfLinksMappedInBodyAttribute; // NSDictionary<NSString *, NSString *>\nTEXTUAL_EXTERN TVCLogRendererResultsAttribute const TVCLogRendererResultsKeywordMatchFoundAttribute; // BOOL\nTEXTUAL_EXTERN TVCLogRendererResultsAttribute const TVCLogRendererResultsListOfUsersFoundAttribute; // NSSet<IRCChannelUser *>\nTEXTUAL_EXTERN TVCLogRendererResultsAttribute const TVCLogRendererResultsOriginalBodyWithoutEffectsAttribute; // NSString\n\n@interface TVCLogRenderer : NSObject\n+ (NSString *)escapeHTML:(NSString *)html;\n\n+ (nullable NSColor *)mapColor:(id)color;\n+ (NSColor *)mapColorCode:(NSUInteger)colorCode;\n\n+ (nullable NSString *)renderTemplateNamed:(NSString *)templateName;\n+ (nullable NSString *)renderTemplateNamed:(NSString *)templateName attributes:(nullable NSDictionary<NSString *, id> *)templateTokens;\n\n+ (nullable NSString *)renderTemplate:(GRMustacheTemplate *)template;\n+ (nullable NSString *)renderTemplate:(GRMustacheTemplate *)template attributes:(nullable NSDictionary<NSString *, id> *)templateTokens;\n\n+ (NSAttributedString *)renderBodyAsAttributedString:(NSString *)body withAttributes:(NSDictionary<TVCLogRendererConfigurationAttribute, id> *)inputDictionary;\n\n+ (NSString *)renderBody:(NSString *)body\n\t   forViewController:(TVCLogController *)viewController\n\t\t  withAttributes:(NSDictionary<TVCLogRendererConfigurationAttribute, id> *)inputDictionary\n\t\t\t  resultInfo:(NSDictionary<TVCLogRendererResultsAttribute, id> * _Nullable * _Nullable)outputDictionary;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCLogView.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString * const TVCLogViewCommonUserAgentString;\n\n@interface TVCLogView : NSObject\n@property (readonly) BOOL hasSelection;\n- (void)clearSelection;\n@property (readonly, copy, nullable) NSString *selection;\n\n/* [TPCPreferences webKit2Enabled] will return YES as long as\n the preference to enable WebKit2 is enabled. */\n/* [TVCLogView webKit2Enabled] will reflect the value of\n [TPCPreferences webKit2Enabled] until such time that a\n WebKit2 process closes unexpectedly. Such as a crash.\n It will then return NO until the app is relaunched. */\n@property (readonly, class) BOOL webKit2Enabled;\n@property (readonly) BOOL isUsingWebKit2;\n\n@property (readonly) NSView *webView;\n\n@property (readonly, getter=isLayingOutView) BOOL layingOutView;\n\n- (instancetype)init NS_UNAVAILABLE;\n@end\n\n@interface TVCLogView (TVCLogViewJavaScriptHandler)\n- (void)evaluateJavaScript:(NSString *)code;\n- (void)evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable result))completionHandler;\n\n- (void)evaluateFunction:(NSString *)function;\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments;\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(id _Nullable result))completionHandler;\n\n- (void)booleanByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(BOOL result))completionHandler;\n- (void)booleanByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(BOOL result))completionHandler;\n\n- (void)stringByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSString * _Nullable result))completionHandler;\n- (void)stringByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSString * _Nullable result))completionHandler;\n\n- (void)arrayByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSArray * _Nullable result))completionHandler;\n- (void)arrayByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSArray * _Nullable result))completionHandler;\n\n- (void)dictionaryByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSDictionary<NSString *, id> * _Nullable result))completionHandler;\n- (void)dictionaryByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSDictionary<NSString *, id> * _Nullable result))completionHandler;\n\n+ (NSString *)escapeJavaScriptString:(NSString *)string;\n\n+ (NSString *)descriptionOfJavaScriptResult:(id)scriptResult;\n\n- (void)logToJavaScriptConsole:(NSString *)message, ...;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindow.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCTreeItem;\n@class TVCMainWindowLoadingScreenView;\n@class TVCMainWindowSplitView, TVCMainWindowTextView;\n@class TVCServerList, TVCMemberList;\n@class TVCLogController;\n\ntypedef NS_ENUM(NSUInteger, TVCServerListNavigationMovementType) {\n\tTVCServerListNavigationMovementTypeAll = 0,\t// Move to next item\n\tTVCServerListNavigationMovementTypeActive,  // Move to next active item\n\tTVCServerListNavigationMovementTypeUnread,  // Move to next unread item\n};\n\ntypedef NS_ENUM(NSUInteger, TVCServerListNavigationSelectionType) {\n\tTVCServerListNavigationSelectionTypeAny = 0,\t// Move to next item\n\tTVCServerListNavigationSelectionTypeChannel,\t// Move to next channel item\n\tTVCServerListNavigationSelectionTypeServer,\t\t// Move to next server item\n};\n\nTEXTUAL_EXTERN NSNotificationName const TVCMainWindowAppearanceChangedNotification;\nTEXTUAL_EXTERN NSNotificationName const TVCMainWindowRedrawSubviewsNotification;\n\nTEXTUAL_EXTERN NSNotificationName const TVCMainWindowWillReloadThemeNotification;\nTEXTUAL_EXTERN NSNotificationName const TVCMainWindowDidReloadThemeNotification;\n\nTEXTUAL_EXTERN NSNotificationName const TVCMainWindowSelectionChangedNotification;\n\nTEXTUAL_EXTERN NSString * const TVCServerListDragType;\n\n@interface TVCMainWindow : NSWindow\n@property (readonly, getter=isDisabled) BOOL disabled;\n\n@property (readonly) TVCMainWindowAppearance *userInterfaceObjects;\n\n@property (readonly, weak) TVCMainWindowLoadingScreenView *loadingScreen;\n@property (readonly, weak) TVCMainWindowSplitView *contentSplitView;\n@property (readonly, unsafe_unretained) TVCMainWindowTextView *inputTextField;\n@property (readonly, weak) TVCMemberList *memberList;\n@property (readonly, weak) TVCServerList *serverList;\n\n@property (readonly) BOOL multipleItemsSelected;\n@property (readonly, nullable) IRCTreeItem *selectedItem;\n@property (readonly, copy) NSArray<IRCTreeItem *> *selectedItems;\n@property (readonly, nullable) IRCClient *selectedClient;\n@property (readonly, nullable) IRCChannel *selectedChannel;\n@property (readonly, nullable) TVCLogController *selectedViewController;\n\n@property (readonly, nullable) IRCTreeItem *previouslySelectedItem;\n\n- (void)select:(nullable IRCTreeItem *)item;\n- (void)selectPreviousItem;\n- (void)deselect:(IRCTreeItem *)item;\n- (void)deselectGroup:(IRCTreeItem *)item;\n\n- (BOOL)isItemVisible:(IRCTreeItem *)item;\n- (BOOL)isItemSelected:(IRCTreeItem *)item;\n- (BOOL)isItemInSelectedGroup:(IRCTreeItem *)item;\n\n- (void)expandClient:(IRCClient *)client;\n\n- (nullable IRCChannel *)selectedChannelOn:(IRCClient *)client;\n\n- (void)navigateServerEntries:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType;\n- (void)navigateChannelEntries:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType;\n- (void)navigateToNextEntry:(BOOL)isMovingDown;\n\n- (void)selectNextServer:(NSEvent *)e;\n- (void)selectNextChannel:(NSEvent *)e;\n- (void)selectNextWindow:(NSEvent *)e;\n- (void)selectPreviousServer:(NSEvent *)e;\n- (void)selectPreviousChannel:(NSEvent *)e;\n- (void)selectPreviousWindow:(NSEvent *)e;\n- (void)selectNextActiveServer:(NSEvent *)e;\n- (void)selectNextUnreadChannel:(NSEvent *)e;\n- (void)selectNextActiveChannel:(NSEvent *)e;\n- (void)selectPreviousSelection:(NSEvent *)e;\n- (void)selectPreviousActiveServer:(NSEvent *)e;\n- (void)selectPreviousUnreadChannel:(NSEvent *)e;\n- (void)selectPreviousActiveChannel:(NSEvent *)e;\n\n@property (getter=isUsingDarkAppearance, readonly) BOOL usingDarkAppearance;\n\n@property (readonly) double textSizeMultiplier;\n\n- (void)changeTextSize:(BOOL)bigger;\n\n- (void)markAllAsRead;\n- (void)markAllAsReadInGroup:(nullable IRCTreeItem *)item;\n\n- (void)reloadTheme; // reloaded asynchronously\n\n- (void)clearContentsOfClient:(IRCClient *)client;\n- (void)clearContentsOfChannel:(IRCChannel *)channel;\n\n- (void)clearAllViews;\n\n- (void)textEntered;\n\n@property (getter=isMemberListVisible, readonly) BOOL memberListVisible;\n@property (getter=isServerListVisible, readonly) BOOL serverListVisible;\n\n- (NSRect)defaultWindowFrame;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindowAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCServerListAppearance, TVCMemberListAppearance, TVCMainWindowTextViewAppearance;\n\n@interface TVCMainWindowAppearance : TVCApplicationAppearance\n@property (readonly) TVCServerListAppearance *serverList;\n@property (readonly) TVCMemberListAppearance *memberList;\n@property (readonly) TVCMainWindowTextViewAppearance *textView;\n\n@property (readonly) NSSize defaultWindowSize;\n\n@property (readonly, copy, nullable) NSColor *channelViewOverlayDefaultBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelViewOverlayDefaultBackgroundColorInactiveWindow;\n\n@property (readonly, copy, nullable) NSColor *loadingScreenBackgroundColor;\n\n@property (readonly, copy, nullable) NSColor *splitViewDividerColor;\n\n@property (readonly, copy, nullable) NSColor *titlebarAccessoryViewBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *titlebarAccessoryViewBackgroundColorInactiveWindow;\n\n@property (readonly) CGFloat titlebarAccessoryViewLeftMargin;\n@property (readonly) CGFloat titlebarAccessoryViewRightMargin;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindowLoadingScreen.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Animation is disabled unless an animated method is invoked */\n@interface TVCMainWindowLoadingScreenView : NSVisualEffectView\n- (void)showProgressViewWithReason:(NSString *)progressReason;\n- (void)setProgressViewReason:(NSString *)progressReason;\n\n- (void)showTrialExpiredView;\n- (void)showWelcomeAddServerView;\n\n@property (readonly) BOOL viewIsVisible;\n\n- (void)hide;\n- (void)hideAnimated;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindowSplitView.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowSplitView : NSSplitView\n- (void)expandServerList;\n- (void)collapseServerList;\n- (void)toggleServerListVisibility;\n\n@property (getter=isServerListCollapsed, readonly) BOOL serverListCollapsed;\n\n- (void)expandMemberList;\n- (void)collapseMemberList;\n- (void)toggleMemberListVisibility;\n\n@property (getter=isMemberListCollapsed, readonly) BOOL memberListCollapsed;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindowTextView.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCTextViewWithIRCFormatter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowTextView : TVCTextViewWithIRCFormatter\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMainWindowTextViewAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAppearance.h\"\n#import \"TPCPreferencesLocal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowTextViewAppearance : TVCApplicationAppearance\n#pragma mark -\n#pragma mark Text View\n\n@property (readonly) NSSize textViewInset;\n@property (readonly, copy, nullable) NSColor *textViewTextColor;\n@property (readonly, copy, nullable) NSColor *textViewPlaceholderTextColor;\n@property (readonly, copy, nullable) NSColor *textViewBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutlineColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutlineColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewInsideShadowColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewInsideShadowColorInactiveWindow;\n@property (readonly, copy, nullable) NSGradient *textViewInsideGradientActiveWindow;\n@property (readonly, copy, nullable) NSGradient *textViewInsideGradientInactiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutsidePrimaryShadowColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutsidePrimaryShadowColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutsideSecondaryShadowColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *textViewOutsideSecondaryShadowColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *textViewFont;\n@property (readonly, copy, nullable) NSFont *textViewFontLarge;\n@property (readonly, copy, nullable) NSFont *textViewFontExtraLarge;\n@property (readonly, copy, nullable) NSFont *textViewFontHumongous;\n\n- (BOOL)preferredTextViewFontChanged;\n@property (readonly, copy, nullable) NSFont *textViewPreferredFont;\n@property (readonly) TVCMainWindowTextViewFontSize textViewPreferredFontSize; // not assigned until -preferredFont is called\n\n#pragma mark -\n#pragma mark Background View\n\n@property (readonly, copy, nullable) NSColor *backgroundViewBackgroundColor;\n@property (readonly, copy, nullable) NSColor *backgroundViewDividerColor;\n@property (readonly) CGFloat backgroundViewContentBorderPadding;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMemberList.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCChannelUser;\n\nTEXTUAL_EXTERN NSString * const TVCMemberListDragType;\n\n@interface TVCMemberList : NSTableView\n@property (nonatomic, assign) BOOL isHiddenByUser;\n\n- (void)refreshDrawingForMember:(IRCChannelUser *)cellItem;\n- (void)refreshDrawingForRow:(NSInteger)rowIndex;\n\n- (nullable id)itemAtRow:(NSInteger)row;\n- (NSInteger)rowForItem:(nullable id)item; // -1 = not found\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCMemberListAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelUser.h\"\n#import \"TVCMainWindowAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMemberListAppearance : TVCApplicationAppearance\n@property (readonly) CGFloat defaultWidth;\n@property (readonly) CGFloat minimumWidth;\n@property (readonly) CGFloat maximumWidth;\n\n@property (readonly, copy, nullable) NSColor *rowSelectionColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *rowSelectionColorInactiveWindow;\n\n#pragma mark -\n#pragma mark Member Cell\n\n@property (readonly) BOOL cellRowEmphasized;\n@property (readonly, copy, nullable) NSColor *cellTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *cellTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *cellAwayTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *cellAwayTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *cellSelectedTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *cellSelectedTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *cellFont;\n@property (readonly, copy, nullable) NSFont *cellFontSelected;\n\n#pragma mark -\n#pragma mark Mark Badge\n\n@property (readonly) CGFloat markBadgeLeftMargin;\n@property (readonly, copy, nullable) NSColor *markBadgeBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeSelectedBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeSelectedBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeSelectedTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *markBadgeSelectedTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *markBadgeFont;\n@property (readonly, copy, nullable) NSFont *markBadgeFontSelected;\n\n#pragma mark -\n#pragma mark Mark Badge Modes\n\n/* These will never be nil because default is stored in preferences. */\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_Y;\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_A;\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_H;\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_O;\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_Q;\n@property (readonly, copy) NSColor *markBadgeBackgroundColor_V;\n\n/* -markBadgeBackgroundColorByUser is the no mode (\"x\") background color\n defined by user. This value can be nil. Use the activeWindow or inactiveWindow\n background colors defined above when this is nil. */\n@property (readonly, copy, nullable) NSColor *markBadgeBackgroundColorByUser;\n\n#pragma mark -\n#pragma mark Accessors\n\n- (nullable NSImage *)cachedUserMarkBadgeForSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank;\n- (void)cacheUserMarkBadge:(NSImage *)badgeImage forSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank;\n\n- (void)invalidateUserMarkBadgeCacheForSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank;\n- (void)invalidateUserMarkBadgeCaches;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCServerList.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCTreeItem;\n\nTEXTUAL_EXTERN NSString * const TVCServerListDragType;\n\n@interface TVCServerList : NSOutlineView\n- (void)refreshDrawingForItem:(IRCTreeItem *)cellItem;\n- (void)refreshDrawingForRow:(NSInteger)rowIndex;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCServerListAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindowAppearance.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCServerListAppearance : TVCApplicationAppearance\n@property (readonly) CGFloat defaultWidth;\n@property (readonly) CGFloat minimumWidth;\n@property (readonly) CGFloat maximumWidth;\n\n@property (readonly, copy, nullable) NSColor *rowSelectionColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *rowSelectionColorInactiveWindow;\n\n#pragma mark -\n#pragma mark Server Cell\n\n@property (readonly) BOOL serverRowEmphasized;\n@property (readonly) CGFloat serverLabelLeftMargin;\n@property (readonly, copy, nullable) NSColor *serverTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *serverTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *serverDisabledTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *serverDisabledTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *serverSelectedTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *serverSelectedTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *serverFont;\n@property (readonly, copy, nullable) NSFont *serverFontSelected;\n\n#pragma mark -\n#pragma mark Channel Cell\n\n@property (readonly) BOOL channelRowEmphasized;\n@property (readonly, copy, nullable) NSColor *channelTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *channelDisabledTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelDisabledTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *channelSelectedTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelSelectedTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *channelErroneousTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelErroneousTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *channelHighlightTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *channelHighlightTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *channelFont;\n@property (readonly, copy, nullable) NSFont *channelFontSelected;\n\n#pragma mark -\n#pragma mark Message Count Badge\n\n@property (readonly, copy, nullable) NSColor *unreadBadgeBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeSelectedBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeSelectedBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeHighlightBackgroundColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeHighlightBackgroundColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeHighlightBackgroundColorByUser;\n@property (readonly, copy, nullable) NSColor *unreadBadgeTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeSelectedTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeSelectedTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeHighlightTextColorActiveWindow;\n@property (readonly, copy, nullable) NSColor *unreadBadgeHighlightTextColorInactiveWindow;\n@property (readonly, copy, nullable) NSFont *unreadBadgeFont;\n@property (readonly, copy, nullable) NSFont *unreadBadgeFontSelected;\n@property (readonly) CGFloat unreadBadgeMinimumWidth;\n@property (readonly) CGFloat unreadBadgeHeight;\n@property (readonly) CGFloat unreadBadgePadding;\n\n#pragma mark -\n#pragma mark Accessors\n\n- (nullable NSString *)statusIconForActiveChannel:(BOOL)isActive\n\t\t\t\t\t\t\t\t\t\t selected:(BOOL)isSelected\n\t\t\t\t\t\t\t\t\t activeWindow:(BOOL)isActiveWindow\n\t\t\t\t\t\t\t\t  treatAsTemplate:(BOOL *)treatAsTemplate;\n\n- (nullable NSString *)statusIconForActiveQuery:(BOOL)isActive\n\t\t\t\t\t\t\t\t\t   selected:(BOOL)isSelected\n\t\t\t\t\t\t\t\t   activeWindow:(BOOL)isActiveWindow\n\t\t\t\t\t\t\t\ttreatAsTemplate:(BOOL *)treatAsTemplate;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCTextViewWithIRCFormatter.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOKeyEventHandler.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TVCTextViewCaretLocation)\n{\n\tTVCTextViewCaretLocationOnlyLine, // There isn't more than one line\n\tTVCTextViewCaretLocationFirstLine,\n\tTVCTextViewCaretLocationMiddle,\n\tTVCTextViewCaretLocationLastLine,\n};\n\n@interface TVCTextViewWithIRCFormatter : NSTextView <NSTextDelegate, TLOKeyEventHandlerPrototype>\n@property (readonly) TVCTextViewCaretLocation caretLocation;\n\n- (CGFloat)highestHeightBelowHeight:(CGFloat)maximumHeight withPadding:(CGFloat)valuePadding;\n\n@property (readonly) NSRect selectedRect;\n\n@property (nonatomic, copy) NSString *stringValue;\n@property (nonatomic, copy) NSString *stringValueWithIRCFormatting;\n\n@property (nonatomic, copy) NSAttributedString *attributedStringValue;\n\n- (void)resetFontInRange:(NSRange)range;\n- (void)resetFontColorInRange:(NSRange)range;\n\n- (void)resetTypeSetterAttributes;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCValidatedComboBox.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCValidatedTextField.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCValidatedComboBox : NSComboBox\n@property (nonatomic, copy, nullable) TVCValidatedTextFieldValidationBlock validationBlock;\n@property (nonatomic, assign) BOOL stringValueUsesOnlyFirstToken; // Only use everything before first space (\" \") as value.\n@property (nonatomic, assign) BOOL stringValueIsTrimmed; // -stringValueUsesOnlyFirstToken returns a trimmed value of newlines and spaces. However, if you want more than first token, then specify this.\n@property (nonatomic, assign) BOOL stringValueIsInvalidOnEmpty; // Is an empty string considered invalid?\n@property (nonatomic, assign) BOOL performValidationWhenEmpty;\n@property (nonatomic, weak) id textDidChangeCallback; // Calls method \"-(void)validatedTextFieldTextDidChange:(id)sender\" whereas \"sender\" is the text field.\n@property (nonatomic, assign) BOOL caseInsensitiveComplete; // Whether completions are case insensitive. Default NO.\n@property (nonatomic, copy, nullable) NSString *defaultValue; // A value to return from -value if the text field is empty. Only used if stringValueIsInvalidOnEmpty = NO\n\n@property (readonly, copy) NSString *value; /* The current value. */\n@property (readonly, copy) NSString *lowercaseValue;\n@property (readonly, copy) NSString *uppercaseValue;\n\n@property (readonly) BOOL valueIsEmpty;\n@property (readonly) BOOL valueIsValid;\n@property (readonly) BOOL valueIsPredefined;\n\n@property (readonly, copy, nullable) NSString *lastValidationErrorDescription;\n\n- (BOOL)showValidationErrorPopover;\n- (void)closeValidationErrorPopover;\n\n- (void)performValidation; /* Force the text field to clear cache and validate value */\n@end\n\n@interface TVCValidatedComboBoxCell : NSComboBoxCell\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TVCValidatedTextField.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Keep the validation block as fast as possible as it is called every time \n that the value of the text field is changed. */\n/* Validation block returns nil on success or a string that can be presented\n to the user as an error description. */\ntypedef NSString * _Nullable (^TVCValidatedTextFieldValidationBlock)(NSString *currentValue);\n\n@interface TVCValidatedTextField : NSTextField\n@property (nonatomic, copy, nullable) TVCValidatedTextFieldValidationBlock validationBlock;\n@property (nonatomic, assign) BOOL stringValueUsesOnlyFirstToken; // Only use everything before first space (\" \") as value.\n@property (nonatomic, assign) BOOL stringValueIsTrimmed; // Returned value is trimmed of whitespaces and newlines when returned. The value is returned trimmed by -value. It is also sent to the validation block as trimmed.\n@property (nonatomic, assign) BOOL stringValueIsInvalidOnEmpty; // Is an empty string considered invalid?\n@property (nonatomic, assign) BOOL performValidationWhenEmpty;\n@property (nonatomic, weak) id textDidChangeCallback; // Calls method \"-(void)validatedTextFieldTextDidChange:(id)sender\" whereas \"sender\" is the text field.\n@property (nonatomic, copy, nullable) NSString *defaultValue; // A value to return from -value if the text field is empty. Only used if stringValueIsInvalidOnEmpty = NO\n\n@property (readonly, copy) NSString *value; /* The current value. */\n@property (readonly, copy) NSString *lowercaseValue;\n@property (readonly, copy) NSString *uppercaseValue;\n\n@property (readonly) BOOL valueIsEmpty;\n@property (readonly) BOOL valueIsValid;\n\n@property (readonly, copy, nullable) NSString *lastValidationErrorDescription;\n\n- (BOOL)showValidationErrorPopover;\n- (void)closeValidationErrorPopover;\n\n- (void)performValidation; /* Force the text field to clear cache and validate value */\n@end\n\n@interface TVCValidatedTextFieldCell : NSTextFieldCell\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXAppearance.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TXAppearanceType)\n{\n\tTXAppearanceTypeBigSurLight,\n\tTXAppearanceTypeBigSurDark,\n};\n\n/* TXAppKitAppearanceTarget defines which items the NSAppearance\n object returned by -appKitAppearance should be assigned to. */\ntypedef NS_ENUM(NSUInteger, TXAppKitAppearanceTarget)\n{\n\t/* The NSAppearance object should be assigned to the window. */\n\tTXAppKitAppearanceTargetWindow,\n\n\t/* The NSAppearance object shouldn't be assigned to anything. */\n\tTXAppKitAppearanceTargetNone\n};\n\n/* None of these properties are observable.\n See -[TXAppearance properties] for information about observing. */\n@protocol TXAppearanceProperties <NSObject>\n@property (readonly, copy) NSString *appearanceName;\n\n@property (readonly) TXAppearanceType appearanceType;\n\n@property (readonly, copy) NSString *shortAppearanceDescription; // e.g. \"light\", \"dark\"\n\n@property (readonly) BOOL isDarkAppearance;\n\n@property (readonly) TXAppKitAppearanceTarget appKitAppearanceTarget;\n@property (readonly, nullable) NSAppearance *appKitAppearance; // nil when -appKitAppearanceTarget = none\n@end\n\n@interface TXAppearancePropertyCollection : NSObject <TXAppearanceProperties>\n@property (readonly, class) BOOL systemWideDarkModeEnabled;\n\n@property (readonly, class, nullable) NSAppearance *appKitLightAppearance;\n@property (readonly, class, nullable) NSAppearance *appKitDarkAppearance;\n@end\n\n/* Access through +[TXSharedApplication sharedAppearance] */\n@interface TXAppearance : NSObject\n/* TXAppearance replaces the property collection object whenever the\n appearance changes so that there is no delay from when one property\n is set and another is set. Observe changes to the properties collection\n object and not an individual property. Latter will not work. */\n@property (readonly, strong) TXAppearancePropertyCollection *properties;\n@end\n\nTEXTUAL_EXTERN NSNotificationName const TXApplicationAppearanceChangedNotification;\nTEXTUAL_EXTERN NSNotificationName const TXSystemAppearanceChangedNotification;\n\nNS_ASSUME_NONNULL_END\n\n#import \"TXAppearanceHelper.h\"\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXAppearanceHelper.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *     Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSView (TXAppearance)\n/* Posted when the application appearance changes */\n/* The default implementation does nothing nor is super required */\n- (void)applicationAppearanceChanged;\n\n/* Can return YES to change default implementation of\n -applicationAppearanceChanged to set needsDisplay to YES. */\n@property (readonly) BOOL needsDisplayWhenApplicationAppearanceChanges;\n\n/* Returns YES by default. If NO, -applicationAppearanceChanged\n will not be sent beyond the view that returned NO. */\n@property (readonly) BOOL sendApplicationAppearanceChangedToSubviews;\n\n/* Performs -applicationAppearanceChanged on view and all subviews\n if -sendApplicationAppearanceChangedToSubviews doesn't return NO. */\n- (void)notifyApplicationAppearanceChanged;\n\n/* Posted when the system appearance changes */\n/* The default implementation does nothing nor is super required */\n- (void)systemAppearanceChanged;\n\n/* Can return YES to change default implementation of\n -systemAppearanceChanged to set needsDisplay to YES. */\n@property (readonly) BOOL needsDisplayWhenSystemAppearanceChanges;\n\n/* Returns YES by default. If NO, -systemAppearanceChanged\n will not be sent beyond the view that returned NO. */\n@property (readonly) BOOL sendSystemAppearanceChangedToSubviews;\n\n/* Performs -systemAppearanceChanged on view and all subviews\n if -sendSystemAppearanceChangedToSubviews doesn't return NO. */\n- (void)notifySystemAppearanceChanged;\n@end\n\n@interface NSWindow (TXApplication)\n/* Performs -applicationAppearanceChanged on window beginning\n with the window frame which contains title and content view. */\n- (void)notifyApplicationAppearanceChanged;\n\n/* Performs -systemAppearanceChanged on window beginning\n with the window frame which contains title and content view. */\n- (void)notifySystemAppearanceChanged;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXGlobalModels.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Time */\nTEXTUAL_EXTERN NSString * _Nullable TXFormattedTimestamp(NSDate *date, NSString *format);\n\nTEXTUAL_EXTERN NSString * _Nullable TXHumanReadableTimeInterval(NSTimeInterval dateInterval, BOOL shortValue, NSCalendarUnit orderMatrix);\n\nTEXTUAL_EXTERN NSString * _Nullable TXFormatDate(id dateObject, NSDateFormatterStyle dateStyle, NSDateFormatterStyle timeStyle, BOOL relativeOutput);\nTEXTUAL_EXTERN NSString * _Nullable TXFormatDateLongStyle(id dateObject, BOOL relativeOutput);\n\n/* Everything else */\nTEXTUAL_EXTERN NSString *TXFormattedNumber(NSInteger number);\n\nTEXTUAL_EXTERN NSUInteger TXRandomNumber(u_int32_t maximum);\n\nTEXTUAL_EXTERN NSComparator NSDefaultComparator;\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXMasterController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCWorld, TVCMainWindow, TXMenuController;\n\n@interface TXMasterController : NSObject\n@property (readonly) BOOL debugModeIsOn;\n@property (readonly) BOOL ghostModeIsOn;\n\n@property (readonly) BOOL applicationIsActive;\n@property (readonly) BOOL applicationIsChangingActiveState;\n\n@property (readonly) BOOL applicationIsLaunched;\n@property (readonly) BOOL applicationIsTerminating;\n\n@property (readonly) IRCWorld *world;\n\n@property (readonly) TVCMainWindow *mainWindow;\n\n@property (readonly, weak) TXMenuController *menuController;\n\n@property (nonatomic, assign) BOOL skipTerminateSave;\n@end\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n@class SPUStandardUpdaterController;\n\n@interface TXMasterController (Sparkle)\n@property (readonly) SPUStandardUpdaterController *updateController;\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXMenuController.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCClient, IRCChannel, IRCChannelUser;\n\n/* MT = Menu Tags.\n Each enum holds integers for different menu items so\n that they can be referenced programatically. */\n/* For submenu tags, we take the tag of the parent,\n add four zeros to the end, then start from there. */\nenum\n{\n\t/* Main menu */\n\tMTMainMenuApp = 1,\n\tMTMainMenuFile = 2,\n\tMTMainMenuEdit = 3,\n\tMTMainMenuView = 4,\n\tMTMainMenuServer = 5,\n\tMTMainMenuChannel = 6,\n\tMTMainMenuQuery = 7,\n\tMTMainMenuNavigate = 8,\n\tMTMainMenuWindow = 9,\n\tMTMainMenuHelp = 10,\n\n\t/* Main menu - App menu */\n\tMTMMAppAboutApp = 100, // \"About Textual\"\n\tMTMMAppAboutAppSeparator = 101, // \"-\"\n\tMTMMAppPreferences = 102, // \"Preferences…\"\n\tMTMMAppManageLicense = 103, // \"Manage license…\"\n//\tMTMMAppInAppPurchase = 104, // \"In-app Purchase…\"\n\tMTMMAppCheckForUpdates = 105, // \"Check for updates…\"\n\tMTMMAppCheckForUpdatesSeparator = 106, // \"-\"\n\tMTMMAppServices = 107, // \"Services\"\n\tMTMMAppServicesSeparator = 108, // \"-\"\n\tMTMMAppHideApp = 109, // \"Hide Textual\"\n\tMTMMAppHideOthers = 110, // \"Hide Others\"\n\tMTMMAppShowAll = 111, // \"Show All\"\n\tMTMMAppShowAllSeparator = 112, // \"-\"\n\tMTMMAppQuitApp = 113, // \"Quit Textual & IRC\"\n\n\t/* Main menu - File menu */\n\tMTMMFileDisableAllNotifications = 200, // \"Disable All Notifications\"\n\tMTMMFileDisableAllNotificationSounds = 201, // \"Disable All Notification Sounds\"\n\tMTMMFileDisableAllNotificationSoundsSeparator = 202, // \"-\"\n\tMTMMFilePrint = 203, // \"Print\"\n\tMTMMFilePrintSeparator = 204, // \"-\"\n\tMTMMFileCloseWindow = 205, // \"Close Window\"\n\n\t/* Main menu - Edit menu */\n\tMTMMEditUndo = 300, // \"Undo\"\n\tMTMMEditRedo = 301, // \"Redo\"\n\tMTMMEditRedoSeparator = 302, // \"-\"\n\tMTMMEditCut = 303, // \"Cut\"\n\tMTMMEditCopy = 304, // \"Copy\"\n\tMTMMEditPaste = 305, // \"Paste\"\n\tMTMMEditDelete = 306, // \"Delete\"\n\tMTMMEditSelectAll = 307, // \"Select All\"\n\tMTMMEditSelectAllSeparator = 308, // \"-\"\n\tMTMMEditFindMenu = 309, // \"Find\"\n\tMTMMEditFindMenuFind = 3090000, // \"Find…\"\n\tMTMMEditFindMenuFindNext = 3090001, // \"Find Next\"\n\tMTMMEditFindMenuFindPrevious = 3090002, // \"Find Previous\"\n\n\t/* Main menu - View menu */\n\tMTMMViewMarkScrollback = 400, // \"Mark Scrollback\"\n\tMTMMViewScrollbackMarker = 401, // \"Scrollback Marker\"\n\tMTMMViewScrollbackMarkerSeparator = 402, // \"-\"\n\tMTMMViewMarkAllAsRead = 403, // \"Mark All as Read\"\n\tMTMMViewClearScrollback = 404, // \"Clear Scrollback\"\n\tMTMMViewClearScrollbackSeparator = 405, // \"-\"\n\tMTMMViewIncreaseFontSize = 406, // \"Increase Font Size\"\n\tMTMMViewDecreaseFontSize = 407, // \"Decrease Font Size\"\n\tMTMMViewDecreaseFontSizeSeparator = 408, // \"-\"\n\tMTMMViewToggleFullscreen = 409, // \"Toggle Fullscreen\"\n\n\t/* Main menu - Server menu */\n\tMTMMServerConnect = 500, // \"Connect\"\n\tMTMMServerConnectWithoutProxy = 501, // \"Connect Without Proxy\"\n\tMTMMServerDisconnect = 502, // \"Disconnect\"\n\tMTMMServerCancelReconnect = 503, // \"Cancel Reconnect\"\n\tMTMMServerCancelReconnectSeparator = 504, // \"-\"\n\tMTMMServerChannelList = 505, // \"Channel List…\"\n\tMTMMServerChangeNickname = 506, // \"Change Nickname…\"\n\tMTMMServerChangeNicknameSeparator = 507, // \"-\"\n\tMTMMServerAddServer = 508, // \"Add Server…\"\n\tMTMMServerDuplicateServer = 509, // \"Duplicate Server\"\n\tMTMMServerDeleteServer = 510, // \"Delete Server…\"\n\tMTMMServerDeleteServerSeparator = 511, // \"-\"\n\tMTMMServerAddChannel = 512, // \"Add Channel…\"\n\tMTMMServerAddChannelSeparator = 513, // \"-\"\n\tMTMMServerServerProperties = 514, // \"Server Properties…\"\n\n\t/* Main menu - Channel menu */\n\tMTMMChannelJoinChannel = 600, // \"Join Channel\"\n\tMTMMChannelLeaveChannel = 601, // \"Leave Channel\"\n\tMTMMChannelLeaveChannelSeparator = 602, // \"-\"\n\tMTMMChannelAddChannel = 603, // \"Add Channel…\"\n\tMTMMChannelDeleteChannel = 604, // \"Delete Channel\"\n\tMTMMChannelDeleteChannelSeparator = 605, // \"-\"\n\tMTMMChannelViewLogs = 606, // \"View Logs\"\n\tMTMMChannelViewLogsSeparator = 607, // \"-\"\n\tMTMMChannelModifyTopic = 608, // \"Modify Topic\"\n\tMTMMChannelModesMenu = 609, // \"Modes\"\n\tMTMMChannelModesMenuAddModerated = 6090000, // \"Moderated (+m)\"\n\tMTMMChannelModesMenuRemoveModerated = 6090001, // \"Unmoderated (-m)\"\n\tMTMMChannelModesMenuAddInviteOnly = 6090002, // \"Invite Only (+i)\"\n\tMTMMChannelModesMenuRemoveInviteOnly = 6090003, // \"Anyone Can Join (-i)\"\n\tMTMMChannelModesMenuManageAllModes = 6090004, // \"Manage All Modes\"\n\tMTMMChannelModesMenuSeparator = 610, // \"-\"\n\tMTMMChannelListOfBans = 611, // \"List of Bans\"\n\tMTMMChannelListOfBanExceptions = 612, // \"List of Ban Exceptions\"\n\tMTMMChannelListOfInviteExceptions = 613, // \"List of Invite Exceptions\"\n\tMTMMChannelListOfQuiets = 614, // \"List of Quiets\"\n\tMTMMChannelListOfQuietsSeparator = 615, // \"-\"\n\tMTMMChannelChannelProperties = 616, // \"Channel Properties…\"\n\tMTMMChannelChannelPropertiesSeparator = 617, // \"-\"\n\tMTMMChannelCopyUniqueIdentifier = 618, //\n\n\t/* Main menu - Query menu */\n\tMTMMQueryCloseQuery = 1800, // \"Close Query\"\n\tMTMMQueryCloseQuerySeparator = 1801, // \"-\"\n\tMTMMQueryQueryLogs = 1802, // \"Query Logs\"\n\n\t/* Main menu - Navigation menu */\n\tMTMMNavigationServersMenu = 700, // \"Servers\"\n\tMTMMNavigationServersMenuNextServer = 7000000, // \"Next Server\"\n\tMTMMNavigationServersMenuPreviousServer = 7000001, // \"Previous Server\"\n\tMTMMNavigationServersMenuPreviousServerSeparator = 7000002, // \"-\"\n\tMTMMNavigationServersMenuNextActiveServer = 7000003, // \"Next Active Server\"\n\tMTMMNavigationServersMenuPreviousActiveServer = 7000004, // \"Previous Active Server\"\n\tMTMMNavigationChannelsMenu = 701, // \"Channels\"\n\tMTMMNavigationChannelsMenuNextChannel = 7010000, // \"Next Channel\"\n\tMTMMNavigationChannelsMenuPreviousChannel = 7010001, // \"Previous Channel\"\n\tMTMMNavigationChannelsMenuPreviousChannelSeparator = 7010002, // \"-\"\n\tMTMMNavigationChannelsMenuNextActiveChannel = 7010003, // \"Next Active Channel\"\n\tMTMMNavigationChannelsMenuPreviousActiveChannel = 7010004, // \"Previous Active Channel\"\n\tMTMMNavigationChannelsMenuPreviousActiveChannelSeparator = 7010005, // \"-\"\n\tMTMMNavigationChannelsMenuNextUnreadChannel = 7010006, // \"Next Unread Channel\"\n\tMTMMNavigationChannelsMenuPreviousUnreadChannel = 7010007, // \"Previous Unread Channel\"\n\tMTMMNavigationChannelsMenuSeparator = 702, // \"-\"\n\tMTMMNavigationMoveBackward = 703, // \"Move Backward\"\n\tMTMMNavigationMoveForward = 704, // \"Move Forward\"\n\tMTMMNavigationMoveForwardSeparator = 705, // \"-\"\n\tMTMMNavigationPreviousSelection = 706, // \"Previous Selection\"\n\tMTMMNavigationPreviousSelectionSeparator = 707, // \"-\"\n\tMTMMNavigationNextHighlight = 708, // \"Next Highlight\"\n\tMTMMNavigationPreviousHighlight = 709, // \"Previous Highlight\"\n\tMTMMNavigationPreviousHighlightSeparator = 710, // \"-\"\n\tMTMMNavigationJumpToCurrentSession = 711, // \"Jump to Current Session\"\n\tMTMMNavigationJumpToPresent = 712, // \"Jump to Present\"\n\tMTMMNavigationJumpToPresentSeparator = 713, // \"-\"\n\tMTMMNavigationChannelList = 714, // \"Channel List…\"\n\tMTMMNavigationChannelListSeparator = 715, // \"-\"\n\tMTMMNavigationSearchChannels = 716, // \"Search channels…\"\n\n\t/* Main menu - Window menu */\n\tMTMMWindowMinimize = 800, // \"Minimize\"\n\tMTMMWindowZoom = 801, // \"Zoom\"\n\tMTMMWindowZoomSeparator = 802, // \"-\"\n\tMTMMWindowToggleVisibilityOfMemberList = 803, // \"Toggle Visibility of Member List\"\n\tMTMMWindowToggleVisibilityOfServerList = 804, // \"Toggle Visibility of Server List\"\n\tMTMMWindowToggleWindowAppearance = 805, // \"Toggle Window Appearance\"\n\tMTMMWindowToggleWindowAppearanceSeparator = 806, // \"-\"\n\tMTMMWindowSortChannelList = 807, // \"Sort Channel List\"\n\tMTMMWindowSortChannelListSeparator = 808, // \"-\"\n\tMTMMWindowCenterWindow = 809, // \"Center Window\"\n\tMTMMWindowResetWindowToDefaultSize = 810, // \"Reset Window to Default Size\"\n\tMTMMWindowResetWindowToDefaultSizeSeparator = 811, // \"-\"\n\tMTMMWindowMainWindow = 812, // \"Main Window\"\n\tMTMMWindowAddressBook = 813, // \"Address Book\"\n\tMTMMWindowIgnoreList = 814, // \"Ignore List\"\n\tMTMMWindowViewLogs = 815, // \"View Logs\"\n\tMTMMWindowHighlightList = 816, // \"Highlight List\"\n\tMTMMWindowFileTransfers = 817, // \"File Transfers\"\n\tMTMMWindowFileTransfersSeparator = 818, // \"-\"\n\tMTMMWindowBrightAllToFront = 819, // \"Bring All to Front\"\n\n\t/* Main menu - Help menu */\n\tMTMMHelpAcknowledgements = 900, // \"Acknowledgements\"\n\tMTMMHelpLicenseAgreement = 901, // \"License Agreement\"\n\tMTMMHelpPrivacyPolicy = 902, // \"Privacy Policy\"\n\tMTMMHelpPrivacyPolicySeparator = 903, // \"-\"\n\tMTMMHelpFrequentlyAskedQuestions = 904, // \"Frequently Asked Questions\"\n\tMTMMHelpKnowledgeBaseMenu = 905, // \"Knowledge Base\"\n\t/* Highest: 9050016 */\n\tMTMMHelpKBMenuKnowledgeBaseHome = 9050000, // \"Knowledge Base Home\"\n\tMTMMHelpKBMenuKnowledgeBaseHomeSeparator = 9050001, // \"-\"\n\tMTMMHelpKBMenuChatEncryption = 9050004, // \"Chat Encryption\"\n\tMTMMHelpKBMenuCommandReference = 9050005, // \"Command Reference\"\n\tMTMMHelpKBMenuFeatureRequests = 9050006, // \"Feature Requests\"\n\tMTMMHelpKBMenuKeyboardShortcuts = 9050007, // \"Keyboard Shortcuts\"\n\tMTMMHelpKBMenuMemoryManagement = 9050008, // \"Memory Management\"\n\tMTMMHelpKBMenuNetworkTimeouts = 9050016, // \"Network Timeouts\"\n\tMTMMHelpKBMenuTextFormatting = 9050009, // \"Text Formatting\"\n\tMTMMHelpKBMenuStylingInformation = 9050010, // \"Styling Information\"\n\tMTMMHelpKBMenuStylingInformationSeparator = 9050011, // \"-\"\n\tMTMMHelpKBMenuConnectingWithCertificate = 9050012, // \"Connecting with Certificate\"\n\tMTMMHelpKBMenuConnectingToBouncer = 9050013, // \"Connecting to a ZNC Bouncer\"\n\tMTMMHelpKBMenuConnectingToBouncerSeparator = 9050014, // \"-\"\n\tMTMMHelpKBMenuDCCFileTransferInformation = 9050015, // \"DCC File Transfer Information\"\n\tMTMMHelpKnowledgeBaseMenuSeparator = 906, // \"-\"\n\tMTMMHelpConnectToHelpChannel = 907, // \"Connect to Help Channel\"\n\tMTMMHelpConnectToTestingChannel = 908, // \"Connect to Testing Channel\"\n\tMTMMHelpConnectToTestingChannelSeparator = 909, // \"-\"\n\tMTMMHelpAdvancedMenu = 910, // \"Advanced\"\n\tMTMMHelpAdvancedMenuEnableDeveloperMode = 9100000, // \"Enable Developer Mode\"\n\tMTMMHelpAdvancedMenuEnableDeveloperModeSeparator = 9100001, // \"-\"\n\tMTMMHelpAdvancedMenuHiddenPreferences = 9100002, // \"Hidden Preferences…\"\n\tMTMMHelpAdvancedMenuHiddenPreferencesSeparator = 9100003, // \"-\"\n\tMTMMHelpAdvancedMenuExportPreferences = 9100004, // \"Export Preferences\"\n\tMTMMHelpAdvancedMenuImportPreferences = 9100005, // \"Import Preferences\"\n\tMTMMHelpAdvancedMenuImportPreferencesSeparator = 9100006, // \"-\"\n\tMTMMHelpAdvancedMenuResetDontAskMeWarnings = 9100007, // \"Reset 'Don't Ask Me' Warnings\"\n\n\t/* WebKit channel name menu */\n\tMTWKChannelNameJoinChannel = 1000, // \"Join Channel\"\n\n\t/* WebKit URL menu */\n\tMTWKURLCopyURL = 1100, // \"Copy URL\"\n\n\t/* WebKit general menu */\n\tMTWKGeneralChangeNickname = 1200, // \"Change Nickname…\"\n\tMTWKGeneralChangeNicknameSeparator = 1201, // \"-\"\n\tMTWKGeneralSearchWithGoogle = 1202, // \"Search With Google\"\n\tMTWKGeneralLookUpInDictionary = 1203, // \"Look Up In Dictionary\"\n\tMTWKGeneralLookUpInDictionarySeparator = 1204, // \"-\"\n\tMTWKGeneralCopy = 1205, // \"Copy\"\n\tMTWKGeneralPaste = 1206, // \"Paste\"\n\tMTWKGeneralPasteSeparator = 1207, // \"-\"\n\tMTWKGeneralQueryLogs = 1208, // \"Query Logs\"\n\tMTWKGeneralChannelMenu = 1209, // \"Channel\"\n\n\t/* Main window segmented controller */\n\tMTMainWindowSegmentedControllerAddServer = 1300, // \"Add Server…\"\n\tMTMainWindowSegmentedControllerAddServerSeparator = 1301, // \"-\"\n\tMTMainWindowSegmentedControllerAddChannel = 1302, // \"Add Channel…\"\n\n\t/* Empty server list menu */\n\tMTMainWindowServerListAddServer = 1400, // \"Add Server…\"\n\n\t/* Off-the-Record Messaging status button */\n\tMTOTRStatusButtonWhatIsThis = 1500, // \"What is this?\"\n\tMTOTRStatusButtonWhatIsThisSeparator = 1501, // \"-\"\n\tMTOTRStatusButtonStartPrivateConversation = 1502, // \"Start Private Conversation\"\n\tMTOTRStatusButtonRefreshPrivateConversation = 1503, // \"Refresh Private Conversation\"\n\tMTOTRStatusButtonEndPrivateConversation = 1504, // \"End Private Conversation\"\n\tMTOTRStatusButtonEndPrivateConversationSeparator = 1505, // \"-\"\n\tMTOTRStatusButtonAuthenticateChatPartner = 1506, // \"Authenticate Chat Partner\"\n\tMTOTRStatusButtonAuthenticateChatPartnerSeparator = 1507, // \"-\"\n\tMTOTRStatusButtonViewListOfFingerprints = 1508, // \"View List of Fingerprints\"\n\n\t/* User context menu */\n\tMTUserControlsLowestTag = 1600,\n\tMTUserControlsHighestTag = 1699,\n\n\tMTUserControlsAddIgnore = 1600, // \"Add Ignore\"\n\tMTUserControlsModifyIgnore = 1601, // \"Modify Ignore\"\n\tMTUserControlsRemoveIgnore = 1602, // \"Remove Ignore\"\n\tMTUserControlsRemoveIgnoreSeparator = 1603, // \"-\"\n\tMTUserControlsInviteTo = 1604, // \"Invite to…\"\n\tMTUserControlsInviteToSeparator = 1605, // \"-\"\n\tMTUserControlsGetInfo = 1606, // \"Get Info (Whois)\"\n\tMTUserControlsPrivateMessage = 1607, // \"Private Message (Query)\"\n\tMTUserControlsPrivateMessageSeparator = 1608, // \"-\"\n\tMTUserControlsGiveOp = 1609, // \"Give Op (+o)\"\n\tMTUserControlsGiveHalfop = 1610, // \"Give Halfop (+h)\"\n\tMTUserControlsGiveVoice = 1611, // \"Give Voice (+v)\"\n\tMTUserControlsAllModesGiven = 1612, // \"All Modes Given\"\n\tMTUserControlsAllModesGivenSeparator = 1613, // \"-\"\n\tMTUserControlsTakeOp = 1614, // \"Take Op (-o)\"\n\tMTUserControlsTakeHalfop = 1615, // \"Take Halfop (-h)\"\n\tMTUserControlsTakeVoice = 1616, // \"Take Voice (-v)\"\n\tMTUserControlsAllModesTaken = 1617, // \"All Modes Taken\"\n\tMTUserControlsAllModesTakenSeparator = 1618, // \"-\"\n\tMTUserControlsBan = 1619, // \"Ban\"\n\tMTUserControlsKick = 1620, // \"Kick\"\n\tMTUserControlsBanAndKick = 1621, // \"Ban and Kick\"\n\tMTUserControlsBanAndKickSeparator = 1622, // \"-\"\n\tMTUserControlsClientToClientMenu = 1623, // \"Client-to-Client\"\n\tMTUserControlsClientToClientMenuSendFile = 16230000, // \"Send file…\"\n\tMTUserControlsClientToClientMenuSendFileSeparator = 16230001, // \"-\"\n\tMTUserControlsClientToClientMenuLag = 16230002, // \"Lag (PING)\"\n\tMTUserControlsClientToClientMenuLocalTime = 16230003, // \"Local Time (TIME)\"\n\tMTUserControlsClientToClientMenuLocalTimeSeparator = 16230004, // \"-\"\n\tMTUserControlsClientToClientMenuClientInformation = 16230005, // \"Client Information (CLIENTINFO)\"\n\tMTUserControlsClientToClientMenuClientVersion = 16230006, // \"Client Version (VERSION)\"\n\tMTUserControlsClientToClientMenuClientVersionSeparator = 16230007, // \"-\"\n\tMTUserControlsClientToClientMenuUserInformationFinger = 16230008, // \"User Information (FINGER)\"\n\tMTUserControlsClientToClientMenuUserInformationUserinfo = 16230009, // \"User Information (USERINFO)\"\n\tMTUserControlsIRCOperatorMenu = 1624, // \"IRC Operator\"\n\tMTUserControlsIRCOperatorMenuSetVirtualHost = 16240000, // \"Set Virtual Host (vHost)\"\n\tMTUserControlsIRCOperatorMenuSetVirtualHostSeparator = 16240001, // \"-\"\n\tMTUserControlsIRCOperatorMenuKillFromServer = 16240002, // \"Kill from Server\"\n\tMTUserControlsIRCOperatorMenuShunOnServer = 16240003, // \"Shun on Server\"\n\tMTUserControlsIRCOperatorMenuBanFromServer = 16240004, // \"Ban from Server (G:Line)\"\n\n\t/* Dock menu */\n\tMTDockMenuDisableAllNotifications = 1700, // \"Disable All Notifications\"\n\tMTDockMenuDisableAllNotificationSounds = 1701, // \"Disable All Notification Sounds\"\n};\n\n@interface TXMenuController : NSObject\n@property (readonly, strong) NSMenu *channelViewChannelNameMenu;\n@property (readonly, strong) NSMenu *channelViewGeneralMenu;\n@property (readonly, strong) NSMenu *channelViewURLMenu;\n\n@property (readonly, strong) NSMenu *dockMenu;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@property (readonly,strong) NSMenu *encryptionManagerStatusMenu;\n#endif\n\n@property (readonly, weak) NSMenu *mainMenuNavigationChannelListMenu;\n@property (readonly, weak) NSMenu *mainMenuChannelMenu;\n@property (readonly, weak) NSMenu *mainMenuQueryMenu;\n@property (readonly, weak) NSMenuItem *mainMenuChannelMenuItem;\n@property (readonly, weak) NSMenuItem *mainMenuQueryMenuItem;\n@property (readonly, weak) NSMenuItem *mainMenuServerMenuItem;\n\n@property (readonly, strong) NSMenu *mainWindowSegmentedControllerCellMenu;\n\n@property (readonly, strong) NSMenu *serverListNoSelectionMenu;\n\n@property (readonly, strong) NSMenu *userControlMenu;\n\n@property (readonly, weak) IRCClient *selectedClient;\n@property (readonly, weak) IRCChannel *selectedChannel;\n\n- (NSArray<IRCChannelUser *> *)selectedMembers:(id)sender;\n- (NSArray<NSString *> *)selectedMembersNicknames:(id)sender;\n- (void)deselectMembers:(id)sender;\n\n- (IBAction)copy:(id)sender;\n- (IBAction)paste:(id)sender;\n\n- (IBAction)print:(id)sender;\n\n- (IBAction)closeWindow:(id)sender;\n\n- (IBAction)contactSupport:(id)sender;\n\n- (IBAction)addChannel:(id)sender;\n- (IBAction)deleteChannel:(id)sender;\n\n- (IBAction)addServer:(id)sender;\n- (IBAction)duplicateServer:(id)sender;\n- (IBAction)deleteServer:(id)sender;\n\n- (IBAction)joinChannel:(id)sender;\n- (IBAction)leaveChannel:(id)sender;\n\n- (IBAction)connect:(id)sender;\n- (IBAction)connectBypassingProxy:(id)sender;\n\n- (IBAction)connectToTextualHelpChannel:(id)sender;\n- (IBAction)connectToTextualTestingChannel:(id)sender;\n\n- (IBAction)disconnect:(id)sender;\n- (IBAction)cancelReconnection:(id)sender;\n\n- (IBAction)clearScrollback:(id)sender;\n\n- (IBAction)markAllAsRead:(id)sender;\n\n- (IBAction)decreaseLogFontSize:(id)sender;\n- (IBAction)increaseLogFontSize:(id)sender;\n\n- (IBAction)jumpToCurrentSession:(id)sender;\n- (IBAction)jumpToPresent:(id)sender;\n\n- (IBAction)gotoScrollbackMarker:(id)sender;\n- (IBAction)markScrollback:(id)sender;\n\n- (IBAction)exportPreferences:(id)sender;\n- (IBAction)importPreferences:(id)sender;\n\n- (IBAction)memberAddIgnore:(id)sender;\n- (IBAction)memberModifyIgnore:(id)sender;\n- (IBAction)memberRemoveIgnore:(id)sender;\n\n- (IBAction)memberBanFromChannel:(id)sender;\n- (IBAction)memberKickFromChannel:(id)sender;\n- (IBAction)memberKickbanFromChannel:(id)sender;\n\n- (IBAction)memberModeGiveHalfop:(id)sender;\n- (IBAction)memberModeGiveOp:(id)sender;\n- (IBAction)memberModeGiveVoice:(id)sender;\n- (IBAction)memberModeTakeHalfop:(id)sender;\n- (IBAction)memberModeTakeOp:(id)sender;\n- (IBAction)memberModeTakeVoice:(id)sender;\n\n- (IBAction)memberSendCTCPClientInfo:(id)sender;\n- (IBAction)memberSendCTCPFinger:(id)sender;\n- (IBAction)memberSendCTCPPing:(id)sender;\n- (IBAction)memberSendCTCPTime:(id)sender;\n- (IBAction)memberSendCTCPUserinfo:(id)sender;\n- (IBAction)memberSendCTCPVersion:(id)sender;\n\n- (IBAction)memberSendFileRequest:(id)sender;\n\n- (IBAction)memberSendInvite:(id)sender;\n- (IBAction)memberSendWhois:(id)sender;\n\n- (IBAction)memberBanFromServer:(id)sender;\n- (IBAction)memberKillFromServer:(id)sender;\n- (IBAction)memberShunOnServer:(id)sender;\n\n- (IBAction)memberStartPrivateMessage:(id)sender;\n\n- (IBAction)onNextHighlight:(id)sender;\n- (IBAction)onPreviousHighlight:(id)sender;\n\n- (IBAction)openStandaloneStoreWebpage:(id)sender;;\n\n- (IBAction)openChannelLogs:(id)sender;\n- (IBAction)openLogLocation:(id)sender;\n\n- (IBAction)centerMainWindow:(id)sender;\n- (IBAction)resetMainWindowFrame:(id)sender;\n\n- (IBAction)openAcknowledgements:(id)sender;\n\n- (IBAction)showAboutWindow:(id)sender;\n- (IBAction)showAddressBook:(id)sender;\n- (IBAction)showChannelBanExceptionList:(id)sender;\n- (IBAction)showChannelBanList:(id)sender;\n- (IBAction)showChannelInviteExceptionList:(id)sender;\n- (IBAction)showChannelQuietList:(id)sender;\n- (IBAction)showChannelModifyModesSheet:(id)sender;\n- (IBAction)showChannelModifyTopicSheet:(id)sender;\n- (IBAction)showChannelPropertiesSheet:(id)sender;\n- (IBAction)showChannelSpotlightWindow:(id)sender;\n- (IBAction)showFileTransfersWindow:(id)sender;\n- (IBAction)showFindPrompt:(id)sender;\n- (IBAction)showHiddenPreferences:(id)sender;\n- (IBAction)showIgnoreList:(id)sender;\n- (IBAction)showMainWindow:(id)sender;\n- (IBAction)showNotificationPreferences:(id)sender;\n- (IBAction)showPreferencesWindow:(id)sender;\n- (IBAction)showServerChangeNicknameSheet:(id)sender;\n- (IBAction)showServerChannelList:(id)sender;\n- (IBAction)showServerHighlightList:(id)sender;\n- (IBAction)showServerPropertiesSheet:(id)sender;\n- (IBAction)showSetVhostPrompt:(id)sender;\n- (IBAction)showStylePreferences:(id)sender;\n- (IBAction)showWelcomeSheet:(id)sender;\n\n- (IBAction)sortChannelListNames:(id)sender;\n\n- (IBAction)toggleChannelInviteMode:(id)sender;\n- (IBAction)toggleChannelModerationMode:(id)sender;\n\n- (IBAction)toggleFullscreen:(id)sender;\n\n- (IBAction)toggleMainWindowAppearance:(id)sender;\n- (IBAction)resetMainWindowAppearance:(id)sender;\n\n- (IBAction)toggleDeveloperMode:(id)sender;\n\n- (IBAction)toggleServerListVisibility:(id)sender;\n- (IBAction)toggleMemberListVisibility:(id)sender;\n\n- (IBAction)toggleMuteOnNotifications:(id)sender;\n- (IBAction)toggleMuteOnNotificationSounds:(id)sender;\n\n- (IBAction)manageLicense:(id)sender;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (IBAction)encryptionWhatIsThisInformation:(id)sender;\n- (IBAction)encryptionStartPrivateConversation:(id)sender;\n- (IBAction)encryptionRefreshPrivateConversation:(id)sender;\n- (IBAction)encryptionEndPrivateConversation:(id)sender;\n- (IBAction)encryptionAuthenticateChatPartner:(id)sender;\n- (IBAction)encryptionListFingerprints:(id)sender;\n#endif\n\n- (IBAction)copyUniqueIdentifier:(id)sender;\n\n- (IBAction)copyUrl:(id)sender;\n\n- (IBAction)lookUpInDictionary:(id)sender;\n- (IBAction)searchGoogle:(id)sender;\n- (IBAction)copyLogAsHtml:(id)sender;\n- (IBAction)forceReloadTheme:(id)sender;\n- (IBAction)openWebInspector:(id)sender;\n\n- (IBAction)checkForUpdates:(id)sender;\n\n- (IBAction)resetDoNotAskMePopupWarnings:(id)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TXSharedApplication.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TXAppearance, TXMasterController, TPCThemeController;\n\n#define masterController()\t\t\t[self masterController]\n#define menuController()\t\t\t[masterController() menuController]\n#define worldController()\t\t\t[masterController() world]\n\n#define mainWindow()\t\t\t\t[masterController() mainWindow]\n\n#define mainWindowLoadingScreen()\t[mainWindow() loadingScreen]\n#define mainWindowServerList()\t\t[mainWindow() serverList]\n#define mainWindowMemberList()\t\t[mainWindow() memberList]\n#define mainWindowTextField()\t\t[mainWindow() inputTextField]\n\n#define themeController()\t\t\t[TXSharedApplication sharedThemeController]\n#define theme()\t\t\t\t\t\t[themeController() theme]\n#define themeSettings()\t\t\t\t[themeController() settings]\n\nTEXTUAL_EXTERN NSErrorDomain const TXErrorDomain;\n\n@interface TXSharedApplication : NSObject\n+ (TXAppearance *)sharedAppearance;\n+ (TPCThemeController *)sharedThemeController;\n@end\n\n@interface NSObject (TXSharedApplicationObjectExtension)\n- (TXMasterController *)masterController;\n+ (TXMasterController *)masterController;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Headers/Textual.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#ifdef __OBJC__\n\t/* Cocoa Extensions imports Cocoa for us */\n\t#import <CocoaExtensions/CocoaExtensions.h>\n\n\t/* Static Definitions */\n\t#import \"StaticDefinitions.h\"\n\n\t/* IRC Controllers — Core */\n\t#import \"IRC.h\"\n\t#import \"IRCAddressBook.h\"\n\t#import \"IRCAddressBookUserTracking.h\"\n\t#import \"IRCChannel.h\"\n\t#import \"IRCChannelConfig.h\"\n\t#import \"IRCChannelMode.h\"\n\t#import \"IRCChannelUser.h\"\n\t#import \"IRCClient.h\"\n\t#import \"IRCClientConfig.h\"\n\t#import \"IRCColorFormat.h\"\n\t#import \"IRCCommandIndex.h\"\n\t#import \"IRCConnection.h\"\n\t#import \"IRCConnectionConfig.h\"\n\t#import \"IRCConnectionErrors.h\"\n\t#import \"IRCHighlightLogEntry.h\"\n\t#import \"IRCHighlightMatchCondition.h\"\n\t#import \"IRCISupportInfo.h\"\n\t#import \"IRCMessage.h\"\n\t#import \"IRCModeInfo.h\"\n\t#import \"IRCNetworkList.h\"\n\t#import \"IRCPrefix.h\"\n\t#import \"IRCSendingMessage.h\"\n\t#import \"IRCServer.h\"\n\t#import \"IRCTreeItem.h\"\n\t#import \"IRCUser.h\"\n\t#import \"IRCUserRelations.h\"\n\t#import \"IRCWorld.h\"\n\n\t/* Framework Extensions (Helpers) */\n\t#import \"NSColorHelper.h\"\n\t#import \"NSStringHelper.h\"\n\t#import \"NSViewHelper.h\"\n\n\t/* Dialogs */\n\t#import \"TDCAlert.h\"\n\t#import \"TDCInputPrompt.h\"\n\t#import \"TDCSheetBase.h\"\n\t#import \"TDCWindowBase.h\"\n\n\t/* Helpers */\n\t#import \"THOPluginProtocol.h\"\n\t#import \"THOUnicodeHelper.h\"\n\n\t/* Library */\n\t#import \"TLOEncryptionManager.h\"\n\t#import \"TLONotificationController.h\"\n\t#import \"TLOInternetAddressLookup.h\"\n\t#import \"TLOKeyEventHandler.h\"\n\t#import \"TLOLinkParser.h\"\n\t#import \"TLOLocalization.h\"\n\t#import \"TLOSoundPlayer.h\"\n\t#import \"TLOTimer.h\"\n\t#import \"TLOpenLink.h\"\n\n\t/* Preferences */\n\t#import \"TPCApplicationInfo.h\"\n\t#import \"TPCPathInfo.h\"\n\t#import \"TPCPreferencesImportExport.h\"\n\t#import \"TPCPreferencesLocal.h\"\n\t#import \"TPCPreferencesReload.h\"\n\t#import \"TPCPreferencesUserDefaultsLocal.h\"\n\t#import \"TPCResourceManager.h\"\n\t#import \"TPCThemeController.h\"\n\t#import \"TPCTheme.h\"\n\n\t/* View Controllers */\n\t#import \"TVCAlert.h\"\n\t#import \"TVCAppearance.h\"\n\t#import \"TVCAutoExpandingTextField.h\"\n\t#import \"TVCAutoExpandingTokenField.h\"\n\t#import \"TVCBasicTableView.h\"\n\t#import \"TVCChannelSelectionViewController.h\"\n\t#import \"TVCLogController.h\"\n\t#import \"TVCLogLine.h\"\n\t#import \"TVCLogRenderer.h\"\n\t#import \"TVCLogView.h\"\n\t#import \"TVCMainWindow.h\"\n\t#import \"TVCMainWindowLoadingScreen.h\"\n\t#import \"TVCMainWindowSplitView.h\"\n\t#import \"TVCMainWindowTextView.h\"\n\t#import \"TVCMemberList.h\"\n\t#import \"TVCServerList.h\"\n\t#import \"TVCValidatedComboBox.h\"\n\t#import \"TVCValidatedTextField.h\"\n\t#import \"TVCTextViewWithIRCFormatter.h\"\n\n\t/* Master Controllers — Root */\n\t#import \"TXAppearance.h\"\n\t#import \"TXGlobalModels.h\"\n\t#import \"TXMasterController.h\"\n\t#import \"TXMenuController.h\"\n\t#import \"TXSharedApplication.h\"\n#endif\n\n/* @end */\n"
  },
  {
    "path": "Sources/App/Classes/Headers/TextualApplication.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#warning \"TextualApplication.h\" is old header file. Please use \"Textual.h\"\n\n#import \"Textual.h\"\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Cocoa (Objective-C)/NSColorHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define TXCalibratedRGBColor(r, g, b)\t\t([NSColor calibratedColorWithRed:r green:g blue:b alpha:1.0])\n\n@implementation NSColor (TXColorHelper)\n\n#pragma mark -\n#pragma mark IRC Text Formatting Color Codes\n\n+ (NSArray<NSColor *> *)formatterColors\n{\n\tstatic NSArray<NSColor *> *colors = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcolors = @[\n\t\t\t/* 0 */  [NSColor formatterWhiteColor],\n\t\t\t/* 1 */  [NSColor formatterBlackColor],\n\t\t\t/* 2 */  [NSColor formatterNavyBlueColor],\n\t\t\t/* 3 */  [NSColor formatterDarkGreenColor],\n\t\t\t/* 4 */  [NSColor formatterRedColor],\n\t\t\t/* 5 */  [NSColor formatterBrownColor],\n\t\t\t/* 6 */  [NSColor formatterPurpleColor],\n\t\t\t/* 7 */  [NSColor formatterOrangeColor],\n\t\t\t/* 8 */  [NSColor formatterYellowColor],\n\t\t\t/* 9 */  [NSColor formatterLimeGreenColor],\n\t\t\t/* 10 */ [NSColor formatterTealColor],\n\t\t\t/* 11 */ [NSColor formatterAquaCyanColor],\n\t\t\t/* 12 */ [NSColor formatterLightBlueColor],\n\t\t\t/* 13 */ [NSColor formatterFuchsiaPinkColor],\n\t\t\t/* 14 */ [NSColor formatterNormalGrayColor],\n\t\t\t/* 15 */ [NSColor formatterLightGrayColor],\n\t\t\t/* 16 */ [NSColor colorWithHexadecimalValue:@\"#470000\"],\n\t\t\t/* 17 */ [NSColor colorWithHexadecimalValue:@\"#472100\"],\n\t\t\t/* 18 */ [NSColor colorWithHexadecimalValue:@\"#474700\"],\n\t\t\t/* 19 */ [NSColor colorWithHexadecimalValue:@\"#324700\"],\n\t\t\t/* 20 */ [NSColor colorWithHexadecimalValue:@\"#004700\"],\n\t\t\t/* 21 */ [NSColor colorWithHexadecimalValue:@\"#00472c\"],\n\t\t\t/* 22 */ [NSColor colorWithHexadecimalValue:@\"#004747\"],\n\t\t\t/* 23 */ [NSColor colorWithHexadecimalValue:@\"#002747\"],\n\t\t\t/* 24 */ [NSColor colorWithHexadecimalValue:@\"#000047\"],\n\t\t\t/* 25 */ [NSColor colorWithHexadecimalValue:@\"#2e0047\"],\n\t\t\t/* 26 */ [NSColor colorWithHexadecimalValue:@\"#470047\"],\n\t\t\t/* 27 */ [NSColor colorWithHexadecimalValue:@\"#47002a\"],\n\t\t\t/* 28 */ [NSColor colorWithHexadecimalValue:@\"#740000\"],\n\t\t\t/* 29 */ [NSColor colorWithHexadecimalValue:@\"#743a00\"],\n\t\t\t/* 30 */ [NSColor colorWithHexadecimalValue:@\"#747400\"],\n\t\t\t/* 31 */ [NSColor colorWithHexadecimalValue:@\"#517400\"],\n\t\t\t/* 32 */ [NSColor colorWithHexadecimalValue:@\"#007400\"],\n\t\t\t/* 33 */ [NSColor colorWithHexadecimalValue:@\"#007449\"],\n\t\t\t/* 34 */ [NSColor colorWithHexadecimalValue:@\"#007474\"],\n\t\t\t/* 35 */ [NSColor colorWithHexadecimalValue:@\"#004074\"],\n\t\t\t/* 36 */ [NSColor colorWithHexadecimalValue:@\"#000074\"],\n\t\t\t/* 37 */ [NSColor colorWithHexadecimalValue:@\"#4b0074\"],\n\t\t\t/* 38 */ [NSColor colorWithHexadecimalValue:@\"#740074\"],\n\t\t\t/* 39 */ [NSColor colorWithHexadecimalValue:@\"#740045\"],\n\t\t\t/* 40 */ [NSColor colorWithHexadecimalValue:@\"#b50000\"],\n\t\t\t/* 41 */ [NSColor colorWithHexadecimalValue:@\"#b56300\"],\n\t\t\t/* 42 */ [NSColor colorWithHexadecimalValue:@\"#b5b500\"],\n\t\t\t/* 43 */ [NSColor colorWithHexadecimalValue:@\"#7db500\"],\n\t\t\t/* 44 */ [NSColor colorWithHexadecimalValue:@\"#00b500\"],\n\t\t\t/* 45 */ [NSColor colorWithHexadecimalValue:@\"#00b571\"],\n\t\t\t/* 46 */ [NSColor colorWithHexadecimalValue:@\"#00b5b5\"],\n\t\t\t/* 47 */ [NSColor colorWithHexadecimalValue:@\"#0063b5\"],\n\t\t\t/* 48 */ [NSColor colorWithHexadecimalValue:@\"#0000b5\"],\n\t\t\t/* 49 */ [NSColor colorWithHexadecimalValue:@\"#7500b5\"],\n\t\t\t/* 50 */ [NSColor colorWithHexadecimalValue:@\"#b500b5\"],\n\t\t\t/* 51 */ [NSColor colorWithHexadecimalValue:@\"#b5006b\"],\n\t\t\t/* 52 */ [NSColor colorWithHexadecimalValue:@\"#ff0000\"],\n\t\t\t/* 53 */ [NSColor colorWithHexadecimalValue:@\"#ff8c00\"],\n\t\t\t/* 54 */ [NSColor colorWithHexadecimalValue:@\"#ffff00\"],\n\t\t\t/* 55 */ [NSColor colorWithHexadecimalValue:@\"#b2ff00\"],\n\t\t\t/* 56 */ [NSColor colorWithHexadecimalValue:@\"#00ff00\"],\n\t\t\t/* 57 */ [NSColor colorWithHexadecimalValue:@\"#00ffa0\"],\n\t\t\t/* 58 */ [NSColor colorWithHexadecimalValue:@\"#00ffff\"],\n\t\t\t/* 59 */ [NSColor colorWithHexadecimalValue:@\"#008cff\"],\n\t\t\t/* 60 */ [NSColor colorWithHexadecimalValue:@\"#0000ff\"],\n\t\t\t/* 61 */ [NSColor colorWithHexadecimalValue:@\"#a500ff\"],\n\t\t\t/* 62 */ [NSColor colorWithHexadecimalValue:@\"#ff00ff\"],\n\t\t\t/* 63 */ [NSColor colorWithHexadecimalValue:@\"#ff0098\"],\n\t\t\t/* 64 */ [NSColor colorWithHexadecimalValue:@\"#ff5959\"],\n\t\t\t/* 65 */ [NSColor colorWithHexadecimalValue:@\"#ffb459\"],\n\t\t\t/* 66 */ [NSColor colorWithHexadecimalValue:@\"#ffff71\"],\n\t\t\t/* 67 */ [NSColor colorWithHexadecimalValue:@\"#cfff60\"],\n\t\t\t/* 68 */ [NSColor colorWithHexadecimalValue:@\"#6fff6f\"],\n\t\t\t/* 69 */ [NSColor colorWithHexadecimalValue:@\"#65ffc9\"],\n\t\t\t/* 70 */ [NSColor colorWithHexadecimalValue:@\"#6dffff\"],\n\t\t\t/* 71 */ [NSColor colorWithHexadecimalValue:@\"#59b4ff\"],\n\t\t\t/* 72 */ [NSColor colorWithHexadecimalValue:@\"#5959ff\"],\n\t\t\t/* 73 */ [NSColor colorWithHexadecimalValue:@\"#c459ff\"],\n\t\t\t/* 74 */ [NSColor colorWithHexadecimalValue:@\"#ff66ff\"],\n\t\t\t/* 75 */ [NSColor colorWithHexadecimalValue:@\"#ff59bc\"],\n\t\t\t/* 76 */ [NSColor colorWithHexadecimalValue:@\"#ff9c9c\"],\n\t\t\t/* 77 */ [NSColor colorWithHexadecimalValue:@\"#ffd39c\"],\n\t\t\t/* 78 */ [NSColor colorWithHexadecimalValue:@\"#ffff9c\"],\n\t\t\t/* 79 */ [NSColor colorWithHexadecimalValue:@\"#e2ff9c\"],\n\t\t\t/* 80 */ [NSColor colorWithHexadecimalValue:@\"#9cff9c\"],\n\t\t\t/* 81 */ [NSColor colorWithHexadecimalValue:@\"#9cffdb\"],\n\t\t\t/* 82 */ [NSColor colorWithHexadecimalValue:@\"#9cffff\"],\n\t\t\t/* 83 */ [NSColor colorWithHexadecimalValue:@\"#9cd3ff\"],\n\t\t\t/* 84 */ [NSColor colorWithHexadecimalValue:@\"#9c9cff\"],\n\t\t\t/* 85 */ [NSColor colorWithHexadecimalValue:@\"#dc9cff\"],\n\t\t\t/* 86 */ [NSColor colorWithHexadecimalValue:@\"#ff9cff\"],\n\t\t\t/* 87 */ [NSColor colorWithHexadecimalValue:@\"#ff94d3\"],\n\t\t\t/* 88 */ [NSColor colorWithHexadecimalValue:@\"#000000\"],\n\t\t\t/* 89 */ [NSColor colorWithHexadecimalValue:@\"#131313\"],\n\t\t\t/* 90 */ [NSColor colorWithHexadecimalValue:@\"#282828\"],\n\t\t\t/* 91 */ [NSColor colorWithHexadecimalValue:@\"#363636\"],\n\t\t\t/* 92 */ [NSColor colorWithHexadecimalValue:@\"#4d4d4d\"],\n\t\t\t/* 93 */ [NSColor colorWithHexadecimalValue:@\"#656565\"],\n\t\t\t/* 94 */ [NSColor colorWithHexadecimalValue:@\"#818181\"],\n\t\t\t/* 95 */ [NSColor colorWithHexadecimalValue:@\"#9f9f9f\"],\n\t\t\t/* 96 */ [NSColor colorWithHexadecimalValue:@\"#bcbcbc\"],\n\t\t\t/* 97 */ [NSColor colorWithHexadecimalValue:@\"#e2e2e2\"],\n\t\t\t/* 98 */ [NSColor colorWithHexadecimalValue:@\"#ffffff\"],\n\t\t];\n\t});\n\n\treturn colors;\n}\n\n+ (NSColor *)formatterWhiteColor\n{\n\treturn TXCalibratedRGBColor(1.00, 1.00, 1.00);\n}\n\n+ (NSColor *)formatterBlackColor\n{\n\treturn TXCalibratedRGBColor(0.00, 0.00, 0.00);\n}\n\n+ (NSColor *)formatterNavyBlueColor\n{\n\treturn TXCalibratedRGBColor(0.04, 0.00, 0.52);\n}\n\n+ (NSColor *)formatterDarkGreenColor\n{\n\treturn TXCalibratedRGBColor(0.00, 0.54, 0.08);\n}\n\n+ (NSColor *)formatterRedColor\n{\n\treturn TXCalibratedRGBColor(1.00, 0.05, 0.04);\n}\n\n+ (NSColor *)formatterBrownColor\n{\n\treturn TXCalibratedRGBColor(0.55, 0.02, 0.02);\n}\n\n+ (NSColor *)formatterPurpleColor\n{\n\treturn TXCalibratedRGBColor(0.55, 0.00, 0.53);\n}\n\n+ (NSColor *)formatterOrangeColor\n{\n\treturn TXCalibratedRGBColor(1.00, 0.54, 0.09);\n}\n\n+ (NSColor *)formatterYellowColor\n{\n\treturn TXCalibratedRGBColor(1.00, 1.00, 0.15);\n}\n\n+ (NSColor *)formatterLimeGreenColor\n{\n\treturn TXCalibratedRGBColor(0.00, 1.00, 0.15);\n}\n\n+ (NSColor *)formatterTealColor\n{\n\treturn TXCalibratedRGBColor(0.00, 0.53, 0.53);\n}\n\n+ (NSColor *)formatterAquaCyanColor\n{\n\treturn TXCalibratedRGBColor(0.00, 1.00, 1.00);\n}\n\n+ (NSColor *)formatterLightBlueColor\n{\n\treturn TXCalibratedRGBColor(0.07, 0.00, 0.98);\n}\n\n+ (NSColor *)formatterFuchsiaPinkColor\n{\n\treturn TXCalibratedRGBColor(1.00, 0.00, 0.98);\n}\n\n+ (NSColor *)formatterNormalGrayColor\n{\n\treturn TXCalibratedRGBColor(0.53, 0.53, 0.53);\n}\n\n+ (NSColor *)formatterLightGrayColor\n{\n\treturn TXCalibratedRGBColor(0.80, 0.80, 0.80);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Cocoa (Objective-C)/NSStringHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRC.h\"\n#import \"IRCClient.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCColorFormat.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCLogRenderer.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSStringEncoding const TXDefaultPrimaryStringEncoding = NSUTF8StringEncoding;\nNSStringEncoding const TXDefaultFallbackStringEncoding = NSISOLatin1StringEncoding;\n\n@implementation NSString (TXStringHelper)\n\n- (BOOL)isValidInternetAddress\n{\n\tif (self.length == 0) {\n\t\treturn NO;\n\t}\n\n\tif (self.isIPAddress || [self isEqualToString:@\"localhost\"]) {\n\t\treturn YES;\n\t}\n\n\treturn [self onlyContainsCharactersFromCharacterSet:\n\t\t\t[NSCharacterSet Ato9UnderscoreDashPeriod]];\n}\n\n- (BOOL)isValidInternetPort\n{\n\tif (self.isNumericOnly == NO) {\n\t\treturn NO;\n\t}\n\n\tNSInteger selfInt = self.integerValue;\n\n\treturn (selfInt > 0 && selfInt <= TXMaximumTCPPort);\n}\n\n- (NSString *)stringByAppendingIRCFormattingStop\n{\n\treturn [self stringByAppendingFormat:@\"%C\", IRCTextFormatterTerminatingCharacter];\n}\n\n- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname username:(NSString * _Nullable * _Nullable)username address:(NSString * _Nullable * _Nullable)address\n{\n\treturn [self hostmaskComponents:nickname username:username address:address onClient:nil];\n}\n\n- (BOOL)hostmaskComponents:(NSString * _Nullable * _Nullable)nickname username:(NSString * _Nullable * _Nullable)username address:(NSString * _Nullable * _Nullable)address onClient:(nullable IRCClient *)client\n{\n\tif (self.length == 0) {\n\t\treturn NO;\n\t}\n\n\t/* Find first ! starting from left side of string */\n\tNSRange bang1pos = [self rangeOfString:@\"!\" options:NSLiteralSearch];\n\n\t/* Find first @ starting from the right side of string */\n\tNSRange bang2pos = [self rangeOfString:@\"@\" options:(NSLiteralSearch | NSBackwardsSearch)];\n\n\tif ((bang1pos.location == NSNotFound) ||\n\t\t(bang2pos.location == NSNotFound) ||\n\t\t(bang2pos.location <= bang1pos.location))\n\t{\n\t\treturn NO;\n\t}\n\n\tNSString *nicknameInt = [self substringToIndex:bang1pos.location];\n\n\tNSString *usernameInt = [self substringWithRange:\n\t\t\t\t\t\t\t NSMakeRange((bang1pos.location + 1),\n\t\t\t\t\t\t\t\t\t\t (bang2pos.location - (bang1pos.location + 1)))];\n\n\tNSString *addressInt = [self substringAfterIndex:bang2pos.location];\n\n\tif ([nicknameInt isHostmaskNicknameOn:client] == NO ||\n\t\t[usernameInt isHostmaskUsernameOn:client] == NO ||\n\t\t[addressInt isHostmaskAddressOn:client] == NO)\n\t{\n\t\treturn NO;\n\t}\n\n\tif ( nickname) {\n\t\t*nickname = nicknameInt;\n\t}\n\n\tif ( username) {\n\t\t*username = usernameInt;\n\t}\n\n\tif ( address) {\n\t\t*address = addressInt;\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)isHostmask\n{\n\treturn [self hostmaskComponents:nil username:nil address:nil];\n}\n\n- (BOOL)isHostmaskAddress\n{\n\treturn [self isHostmaskAddressOn:nil];\n}\n\n- (BOOL)isHostmaskAddressOn:(nullable IRCClient *)client\n{\n\treturn (self.length > 0 &&\n\t\t\t[self containsCharacters:@\"\\x021\\x040\\x000\\x020\\x00d\\x00a\"] == NO);\n}\n\n- (BOOL)isHostmaskUsername\n{\n\treturn [self isHostmaskUsernameOn:nil];\n}\n\n- (BOOL)isHostmaskUsernameOn:(nullable IRCClient *)client\n{\n\treturn (self.length > 0 &&\n\t\t\tself.length <= TXMaximumIRCUsernameLength &&\n\t\t\t[self containsCharacters:@\"\\x000\\x020\\x00d\\x00a\"] == NO);\n}\n\n- (BOOL)isHostmaskNickname\n{\n\treturn [self isHostmaskNicknameOn:nil];\n}\n\n- (BOOL)isHostmaskNicknameOn:(nullable IRCClient *)client\n{\n\tNSUInteger maximumLength = TXMaximumIRCNicknameLength;\n\n\tif (client) {\n\t\t/* At least one server has been found (gitter.im) has been found\n\t\t which does not send a configuration profile. They allow a \n\t\t nickname length larger than IRCISupportInfo uses as a default\n\t\t which means parsing will go wonky. */\n\t\t/* A smarter workaround would probably to check if specific \n\t\t configuration options were received (e.g. \"NICKLEN\"), but that \n\t\t has more overhead than using a boolean. */\n\n\t\tif (client.supportInfo.configurationReceived) {\n\t\t\tmaximumLength = client.supportInfo.maximumNicknameLength;\n\t\t} else {\n\t\t\tmaximumLength = 0;\n\t\t}\n\n\t\t/* If we are connected to ZNC, then do not enforce maximum \n\t\t nickname length. It is easier to disable this check than\n\t\t to check whether a nickname (e.g. *buffextras) should be\n\t\t handled differently. */\n\t\tif (client.isConnectedToZNC) {\n\t\t\tmaximumLength = 0;\n\t\t}\n\t}\n\n\tif (maximumLength == 0) {\n\t\tmaximumLength = TXMaximumIRCNicknameLength;\n\t}\n\n\treturn ([self isNotEqualTo:@\"*\"] &&\n\t\t\tself.length > 0 &&\n\t\t\tself.length <= maximumLength &&\n\t\t\t[self containsCharacters:@\"\\x021\\x040\\x000\\x020\\x00d\\x00a\"] == NO);\n}\n\n- (BOOL)isChannelNameOn:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif (self.length == 0) {\n\t\treturn NO;\n\t}\n\n\t/* A maximum length is not current imposed on channel names,\n\t even though we have that information, because -isChannelNameOn:\n\t is called in -[IRCClient sendCommand:...] to check whether the\n\t the input string for a command begins with a channel name before\n\t we perform tokenizing. During that time, the input string can be\n\t any possible length. We therefore only check if the string begins\n\t with known channel name prefixes and allow server to perform\n\t extensive validation on the channel name. */\n\tNSArray *channelNamePrefixes = client.supportInfo.channelNamePrefixes;\n\n\tif (self.length == 1) {\n\t\tNSString *character = [self stringCharacterAtIndex:0];\n\n\t\treturn [channelNamePrefixes containsObject:character];\n\t}\n\n\tNSString *character1 = [self stringCharacterAtIndex:0];\n\tNSString *character2 = [self stringCharacterAtIndex:1];\n\n\t/* The ~ prefix is considered special. It is used by the ZNC partyline plugin. */\n\tBOOL isPartyline = ([character1 isEqualToString:@\"~\"] && [character2 isEqualToString:@\"#\"]);\n\n\treturn (isPartyline || [channelNamePrefixes containsObject:character1]);\n}\n\n- (BOOL)isChannelName\n{\n\tif (self.length == 0) {\n\t\treturn NO;\n\t}\n\n\tUniChar c = [self characterAtIndex:0];\n\n\treturn (c == '#' ||\n\t\t\tc == '&' ||\n\t\t\tc == '+' ||\n\t\t\tc == '!' ||\n\t\t\tc == '~' ||\n\t\t\tc == '?');\n}\n\n- (nullable NSString *)channelNameWithoutBang\n{\n\tif (self.isChannelName == NO) {\n\t\treturn self;\n\t}\n\n\treturn [self substringFromIndex:1];\n}\n\n- (nullable NSString *)channelNameWithoutBangOn:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ([self isChannelNameOn:client] == NO) {\n\t\treturn self;\n\t}\n\n\tif (self.length < 2) { // Do not turn \"#\" into empty string\n\t\treturn self;\n\t}\n\n\tNSArray *channelNamePrefixes = client.supportInfo.channelNamePrefixes;\n\n\tNSString *character = [self stringCharacterAtIndex:0];\n\n\tif ([channelNamePrefixes containsObject:character]) {\n\t\treturn [self substringFromIndex:1];\n\t}\n\n\treturn self;\n}\n\n- (nullable NSString *)nicknameFromHostmask\n{\n\tNSString *nickname = nil;\n\n\tif ([self hostmaskComponents:&nickname username:nil address:nil]) {\n\t\treturn nickname;\n\t}\n\n\treturn self;\n}\n\n- (nullable NSString *)usernameFromHostmask\n{\n\tNSString *username = nil;\n\n\tif ([self hostmaskComponents:nil username:&username address:nil]) {\n\t\treturn username;\n\t}\n\n\treturn nil;\n}\n\n- (nullable NSString *)addressFromHostmask\n{\n\tNSString *address = nil;\n\n\tif ([self hostmaskComponents:nil username:nil address:&address]) {\n\t\treturn address;\n\t}\n\n\treturn nil;\n}\n\n- (nullable NSString *)stringWithValidURIScheme\n{\n\treturn [AHHyperlinkScanner URLWithProperScheme:self];\n}\n\n- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor honorFormattingPreference:(BOOL)formattingPreference\n{\n\tif (formattingPreference && [TPCPreferences removeAllFormatting]) {\n\t\tNSString *string = self.stripIRCEffects;\n\n\t\treturn [NSAttributedString attributedStringWithString:string];\n\t}\n\n\tNSMutableDictionary *attributes = [NSMutableDictionary dictionary];\n\n\tif (preferredFont) {\n\t\tattributes[TVCLogRendererConfigurationAttributedStringPreferredFontAttribute] = preferredFont;\n\t}\n\n\tif (preferredFontColor) {\n\t\tattributes[TVCLogRendererConfigurationAttributedStringPreferredFontColorAttribute] = preferredFontColor;\n\t}\n\n\treturn [TVCLogRenderer renderBodyAsAttributedString:self withAttributes:attributes];\n}\n\n- (nullable NSAttributedString *)attributedStringWithIRCFormatting:(NSFont *)preferredFont preferredFontColor:(nullable NSColor *)preferredFontColor\n{\n\treturn [self attributedStringWithIRCFormatting:preferredFont preferredFontColor:preferredFontColor honorFormattingPreference:NO];\n}\n\n- (NSString *)stripIRCEffects\n{\n\tNSUInteger stringLength = self.length;\n\n\tif (stringLength == 0) {\n\t\treturn self;\n\t}\n\n\tNSUInteger currentPosition = 0;\n\n\tNSUInteger bufferLength = (stringLength * sizeof(UniChar));\n\n\tUniChar *inputBuffer = alloca(bufferLength);\n\tUniChar *outputBuffer = alloca(bufferLength);\n\n\t[self getCharacters:inputBuffer range:self.range];\n\n\tfor (NSUInteger i = 0; i < stringLength; i++) {\n\t\tUniChar character = inputBuffer[i];\n\n\t\tswitch (character) {\n\t\t\tcase IRCTextFormatterEffectBoldCharacter:\n\t\t\tcase IRCTextFormatterEffectItalicCharacter:\n\t\t\tcase IRCTextFormatterEffectItalicCharacterOld:\n\t\t\tcase IRCTextFormatterEffectMonospaceCharacter:\n\t\t\tcase IRCTextFormatterEffectStrikethroughCharacter:\n\t\t\tcase IRCTextFormatterEffectUnderlineCharacter:\n\t\t\tcase IRCTextFormatterTerminatingCharacter:\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCTextFormatterEffectColorAsDigitCharacter:\n\t\t\tcase IRCTextFormatterEffectColorAsHexCharacter:\n\t\t\t{\n\t\t\t\t// One is subtracted because the for loop will increment by one for us\n\t\t\t\ti += ([self colorComponentsOfCharacter:character startingAt:i foregroundColor:NULL backgroundColor:NULL] - 1);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\toutputBuffer[currentPosition++] = character;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [NSString stringWithCharacters:outputBuffer length:currentPosition];\n}\n\n- (NSUInteger)colorComponentsOfCharacter:(UniChar)character startingAt:(NSUInteger)rangeStart foregroundColor:(id _Nullable * _Nullable)foregroundColor backgroundColor:(id _Nullable * _Nullable)backgroundColor\n{\n\tif (character == IRCTextFormatterEffectColorAsDigitCharacter) {\n\t\treturn [self colorAsDigitStartingAt:rangeStart foregroundColor:foregroundColor backgroundColor:backgroundColor];\n\t} else if (character == IRCTextFormatterEffectColorAsHexCharacter) {\n\t\treturn [self colorAsHexStartingAt:rangeStart foregroundColor:foregroundColor backgroundColor:backgroundColor];\n\t}\n\n\treturn 0;\n}\n\n- (NSUInteger)colorAsHexStartingAt:(NSUInteger)rangeStart foregroundColor:(NSColor * _Nullable * _Nullable)foregroundColor backgroundColor:(NSColor * _Nullable * _Nullable)backgroundColor\n{\n\tNSUInteger selfLength = self.length;\n\n\tNSParameterAssert(rangeStart < selfLength);\n\n\tNSUInteger currentPosition = rangeStart;\n\n\tNSString *m_foregroundColor = nil;\n\tNSString *m_backgroundColor = nil;\n\n\tBOOL commaEaten = NO;\n\n\t// ========================================== //\n\n\t/* Control character */\n\tcurrentPosition++;\n\n\t// ========================================== //\n\n\t/* Foreground hex color */\n\tif ((currentPosition + 6) > selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tm_foregroundColor = [self substringWithRange:NSMakeRange(currentPosition, 6)];\n\n\tif ([m_foregroundColor onlyContainsCharactersFromCharacterSet:[NSCharacterSet hexadecimalCharacterSet]]) {\n\t\tcurrentPosition += 6; // Eat foreground color\n\t} else {\n\t\tm_foregroundColor = nil;\n\n\t\tgoto return_method;\n\t}\n\n\t// ========================================== //\n\n\t/* Comma */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar a = [self characterAtIndex:currentPosition];\n\n\tif (a == ',') {\n\t\tcommaEaten = YES;\n\n\t\tcurrentPosition++; // Eat comma\n\t} else {\n\t\tgoto return_method;\n\t}\n\n\t// ========================================== //\n\n\t/* Background hex color */\n\tif ((currentPosition + 6) > selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tm_backgroundColor = [self substringWithRange:NSMakeRange(currentPosition, 6)];\n\n\tif ([m_backgroundColor onlyContainsCharactersFromCharacterSet:[NSCharacterSet hexadecimalCharacterSet]]) {\n\t\tcurrentPosition += 6; // Eat background color\n\t} else {\n\t\tm_backgroundColor = nil;\n\t}\n\n\t// ========================================== //\n\nreturn_method:\n\tif (m_backgroundColor == nil && commaEaten) {\n\t\tcurrentPosition -= 1;\n\t}\n\n\tif ( foregroundColor && m_foregroundColor != nil) {\n\t\t*foregroundColor = [NSColor colorWithHexadecimalValue:m_foregroundColor.uppercaseString];\n\t}\n\n\tif ( backgroundColor && m_backgroundColor != nil) {\n\t\t*backgroundColor = [NSColor colorWithHexadecimalValue:m_backgroundColor.uppercaseString];\n\t}\n\n\treturn (currentPosition - rangeStart);\n}\n\n- (NSUInteger)colorAsDigitStartingAt:(NSUInteger)rangeStart foregroundColor:(NSNumber * _Nullable * _Nullable)foregroundColor backgroundColor:(NSNumber * _Nullable * _Nullable)backgroundColor\n{\n\tNSUInteger selfLength = self.length;\n\n\tNSParameterAssert(rangeStart < selfLength);\n\n\tNSUInteger currentPosition = rangeStart;\n\n\tNSUInteger m_foregroundColor = NSNotFound;\n\tNSUInteger m_backgroundColor = NSNotFound;\n\n\tBOOL commaEaten = NO;\n\n\t// ========================================== //\n\n\t/* Control character */\n\tcurrentPosition++;\n\n\t// ========================================== //\n\n\t/* Foreground color first color number */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar a = [self characterAtIndex:currentPosition];\n\n\tif (CS_StringIsBase10Numeric(a) == NO) {\n\t\tgoto return_method;\n\t}\n\n\tm_foregroundColor = (a - '0');\n\n\tcurrentPosition++; // Eat first color number\n\n\t// ========================================== //\n\n\t/* Foreground color second color number */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar b = [self characterAtIndex:currentPosition];\n\n\tif (CS_StringIsBase10Numeric(b)) {\n\t\tm_foregroundColor = (m_foregroundColor * 10 + b - '0');\n\n\t\tcurrentPosition++; // Eat second color number\n\t}\n\n\t// ========================================== //\n\n\t/* Comma */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar c = [self characterAtIndex:currentPosition];\n\n\tif (c == ',') {\n\t\tcommaEaten = YES;\n\n\t\tcurrentPosition++; // Eat comma\n\t} else {\n\t\tgoto return_method;\n\t}\n\n\t// ========================================== //\n\n\t/* Background color first color number */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar d = [self characterAtIndex:currentPosition];\n\n\tif (CS_StringIsBase10Numeric(d) == NO) {\n\t\tgoto return_method;\n\t}\n\n\tm_backgroundColor = (d - '0');\n\n\tcurrentPosition++; // Eat first color number\n\n\t// ========================================== //\n\n\t/* Background color second color number */\n\tif (currentPosition >= selfLength) {\n\t\tgoto return_method;\n\t}\n\n\tUniChar e = [self characterAtIndex:currentPosition];\n\n\tif (CS_StringIsBase10Numeric(e) == NO) {\n\t\tgoto return_method;\n\t}\n\n\tm_backgroundColor = (m_backgroundColor * 10 + e - '0');\n\n\tcurrentPosition++; // Eat second color number\n\n\t// ========================================== //\n\nreturn_method:\n\tif (m_backgroundColor == NSNotFound && commaEaten) {\n\t\tcurrentPosition -= 1;\n\t}\n\n\tif (  foregroundColor &&\n\t\tm_foregroundColor != NSNotFound &&\n\t\tm_foregroundColor <= IRCTextFormatterEffectColorHighestDigit)\n\t{\n\t\t*foregroundColor = @(m_foregroundColor);\n\t}\n\n\tif (  backgroundColor &&\n\t\tm_backgroundColor != NSNotFound &&\n\t\tm_backgroundColor <= IRCTextFormatterEffectColorHighestDigit)\n\t{\n\t\t*backgroundColor = @(m_backgroundColor);\n\t}\n\n\treturn (currentPosition - rangeStart);\n}\n\n- (NSArray<NSString *> *)base64EncodingWithLineLength:(NSUInteger)lineLength\n{\n\tif (self.length == 0) {\n\t\treturn @[self];\n\t}\n\n\tNSData *selfData = [self dataUsingEncoding:NSUTF8StringEncoding];\n\n\tNSString *encodedString = [XRBase64Encoding encodeData:selfData];\n\n\treturn [encodedString splitWithMaximumLength:lineLength];\n}\n\n- (nullable NSString *)padNicknameWithCharacter:(UniChar)padCharacter maximumLength:(NSUInteger)maximumLength\n{\n\tNSParameterAssert(padCharacter != 0);\n\tNSParameterAssert(maximumLength > 0);\n\n\tNSString *padCharacterString = [NSString stringWithUniChar:padCharacter];\n\n\tif (self.length < maximumLength) {\n\t\treturn [self stringByAppendingString:padCharacterString];\n\t}\n\n\tNSString *substring = [self substringToIndex:maximumLength];\n\n\tfor (NSInteger i = (substring.length - 1); i >= 0; i--) {\n\t\tUniChar substringCharacter = [substring characterAtIndex:i];\n\n\t\tif (substringCharacter == padCharacter) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *stringHead = [substring substringToIndex:i];\n\n\t\tNSMutableString *stringHeadMutable = [stringHead mutableCopy];\n\n\t\tfor (NSUInteger j = i; j < substring.length; j++) {\n\t\t\t[stringHeadMutable appendString:@\"_\"];\n\t\t}\n\n\t\treturn [stringHeadMutable copy];\n\t}\n\n\treturn nil;\n}\n\n- (nullable NSString *)prettyLicenseKey\n{\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\tif (self.length == 0) {\n\t\treturn nil;\n\t}\n\n\tNSRange lastDashRange = [self rangeOfString:@\"-\" options:NSBackwardsSearch];\n\n\tif (lastDashRange.location == NSNotFound) {\n\t\treturn nil;\n\t}\n\n\t/* Go from dash outward by 5 */\n\tlastDashRange.length = (lastDashRange.location + 6); // 1 = dash, 5 = numbers (1+5)\n\tlastDashRange.location = 0;\n\n\tNSString *licenseKey = [self substringWithRange:lastDashRange];\n\n\treturn [licenseKey stringByAppendingString:@\"…\"];\n#else\n\treturn nil;\n#endif\n}\n\n/* Source: https://ircv3.net/specs/core/message-tags-3.2.html */\n- (NSString *)encodedMessageTagString\n{\n\tif (self.length == 0) {\n\t\treturn self;\n\t}\n\n\tNSMutableString *bob = [self mutableCopy];\n\t\n\t[bob replaceOccurrencesOfString:@\"\\\\\" withString:@\"\\\\\\\\\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\";\" withString:@\"\\\\:\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\" \" withString:@\"\\\\s\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\r\" withString:@\"\\\\r\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\n\" withString:@\"\\\\n\" options:0 range:bob.range];\n\t\n\treturn [bob copy];\n}\n\n- (NSString *)decodedMessageTagString\n{\n\tif (self.length == 0) {\n\t\treturn self;\n\t}\n\n\tNSMutableString *bob = [self mutableCopy];\n\t\n\tif ([bob hasSuffix:@\"\\\\\"]) {\n\t\t[bob deleteCharactersInRange:NSMakeRange((bob.length - 1), 1)];\n\t}\n\t\n\t[bob replaceOccurrencesOfString:@\"\\\\:\" withString:@\";\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\\\\\\\\" withString:@\"\\\\\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\\\s\" withString:@\" \" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\\\r\" withString:@\"\\r\" options:0 range:bob.range];\n\t[bob replaceOccurrencesOfString:@\"\\\\n\" withString:@\"\\n\" options:0 range:bob.range];\n\t\n\treturn [bob copy];\n}\n\n- (BOOL)isModeSymbol\n{\n\tif (self.length != 1) {\n\t\treturn NO;\n\t}\n\n\treturn [[NSCharacterSet AtoZCharacterSet] characterIsMember:[self characterAtIndex:0]];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Cocoa (Objective-C)/NSTableViewHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation NSTableView (TXTableViewHelper)\n\n+ (NSFont *)preferredGlobalTableViewFont\n{\n\treturn [NSFont systemFontOfSize:13.0];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Cocoa (Objective-C)/NSViewHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMainWindow.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation NSWindow (TXWindowHelper)\n\n- (void)changeFrameToMin\n{\n\t[self changeFrameToMinAndDisplay:YES animate:NO];\n}\n\n- (void)changeFrameToMinAndDisplay:(BOOL)display\n{\n\t[self changeFrameToMinAndDisplay:display animate:NO];\n}\n\n- (void)changeFrameToMinAndDisplay:(BOOL)display animate:(BOOL)animate\n{\n\tNSSize minSize = self.contentMinSize;\n\n\t[self changeFrameTo:minSize display:display animate:NO];\n}\n\n- (void)changeFrameTo:(NSSize)minSize display:(BOOL)display animate:(BOOL)animate\n{\n\tNSRect oldFrame = self.frame;\n\tNSRect newFrame = oldFrame;\n\n\tNSRect contentRect = [self contentRectForFrameRect:newFrame];\n\n\tfloat bezelHeight = (newFrame.size.height - contentRect.size.height);\n\n\tnewFrame.size.width = minSize.width;\n\tnewFrame.size.height = (bezelHeight + minSize.height);\n\n\tnewFrame.origin.y = (NSMaxY(oldFrame) - newFrame.size.height);\n\n\t[self setFrame:newFrame display:display animate:animate];\n}\n\n- (void)replaceContentView:(NSView *)withView\n{\n\tself.contentView = nil;\n\n\t[self changeFrameTo:withView.frame.size display:NO animate:NO];\n\n\tself.contentView = withView;\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSView (TXViewHelperPrivate)\n\n- (nullable TVCMainWindow *)mainWindow\n{\n\tNSWindow *window = self.window;\n\n\tif ([window isMemberOfClass:[TVCMainWindow class]] == NO) {\n\t\treturn nil;\n\t}\n\n\treturn (TVCMainWindow *)window;\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSView (TXViewHelper)\n\n- (void)addConstraintsToSuperviewToHugEdges\n{\n\tNSView *superview = self.superview;\n\n\tNSArray *constraints = @[\n\t [NSLayoutConstraint constraintWithItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeLeft\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:superview\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeLeft\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t [NSLayoutConstraint constraintWithItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeRight\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:superview\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeRight\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t [NSLayoutConstraint constraintWithItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:superview\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t [NSLayoutConstraint constraintWithItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeBottom\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:superview\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeBottom\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0]\n\t ];\n\n\t[superview addConstraints:constraints];\n}\n\n- (void)addConstraintsToSuperviewToEqualDimensions\n{\n\tNSView *superview = self.superview;\n\n\tNSMutableArray *constraints = [NSMutableArray array];\n\n\t[constraints addObjectsFromArray:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-0-[self(0@550)]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(self)]];\n\n\t[constraints addObjectsFromArray:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-0-[self(0@550)]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(self)]];\n\n\t[superview addConstraints:constraints];\n}\n\n- (void)replaceFirstSubview:(NSView *)withSubview\n{\n\tNSParameterAssert(withSubview != nil);\n\n\t/* Remove any views that may already be in place. */\n\t[self.subviews.firstObject removeFromSuperviewWithoutNeedingDisplay];\n\n\t/* Add subview. */\n\t[self addSubview:withSubview];\n\n\t/* Apply constraints. */\n\t[withSubview addConstraintsToSuperviewToHugEdges];\n\n\t[withSubview addConstraintsToSuperviewToEqualDimensions];\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSCell (TXCellHelperPrivate)\n\n- (nullable NSWindow *)window\n{\n\treturn self.controlView.window;\n}\n\n- (nullable TVCMainWindow *)mainWindow\n{\n\treturn self.controlView.mainWindow;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Cocoa (Objective-C)/TXAppearanceHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearanceHelper.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark NSView Category\n\n@implementation NSView (TXAppearance)\n\n- (BOOL)needsDisplayWhenApplicationAppearanceChanges\n{\n\treturn NO;\n}\n\n- (BOOL)needsDisplayWhenSystemAppearanceChanges\n{\n\treturn NO;\n}\n\n- (BOOL)sendApplicationAppearanceChangedToSubviews\n{\n\treturn YES;\n}\n\n- (BOOL)sendSystemAppearanceChangedToSubviews\n{\n\treturn YES;\n}\n\n- (void)applicationAppearanceChanged\n{\n\tif (self.needsDisplayWhenApplicationAppearanceChanges) {\n\t\tself.needsDisplay = YES;\n\t}\n}\n\n- (void)systemAppearanceChanged\n{\n\tif (self.needsDisplayWhenSystemAppearanceChanges) {\n\t\tself.needsDisplay = YES;\n\t}\n}\n\n- (void)notifyApplicationAppearanceChanged\n{\n\t[self applicationAppearanceChanged];\n\n\tif (self.sendApplicationAppearanceChangedToSubviews == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSView *view in self.subviews) {\n\t\t[view notifyApplicationAppearanceChanged];\n\t}\n}\n\n- (void)notifySystemAppearanceChanged\n{\n\t[self systemAppearanceChanged];\n\n\tif (self.sendSystemAppearanceChangedToSubviews == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSView *view in self.subviews) {\n\t\t[view notifySystemAppearanceChanged];\n\t}\n}\n\n@end\n\n#pragma mark -\n#pragma mark NSWindow Category\n\n@implementation NSWindow (TXApplication)\n\n- (void)notifyApplicationAppearanceChanged\n{\n\t[self.contentView.superview notifyApplicationAppearanceChanged];\n\n\tfor (NSTitlebarAccessoryViewController *viewController in self.titlebarAccessoryViewControllers) {\n\t\t[viewController.view notifyApplicationAppearanceChanged];\n\t}\n}\n\n- (void)notifySystemAppearanceChanged\n{\n\t[self.contentView.superview notifySystemAppearanceChanged];\n\n\tfor (NSTitlebarAccessoryViewController *viewController in self.titlebarAccessoryViewControllers) {\n\t\t[viewController.view notifySystemAppearanceChanged];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/External Libraries/Google/GTMEncodeHTML.m",
    "content": "//\n//  GTMNSString+HTML.m\n//  Dealing with NSStrings that contain HTML\n//\n//  Copyright 2006-2008 Google Inc.\n//\n//  Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n//  use this file except in compliance with the License.  You may obtain a copy\n//  of the License at\n//\n//  http://www.apache.org/licenses/LICENSE-2.0\n//\n//  Unless required by applicable law or agreed to in writing, software\n//  distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the\n//  License for the specific language governing permissions and limitations under\n//  the License.\n//\n\n#import \"GTMEncodeHTML.h\"\n\ntypedef struct {\n\tNSString *escapeSequence;\n\tunichar uchar;\n} HTMLEscapeMap;\n\n// Taken from http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters\n// Ordered by uchar lowest to highest for bsearching\nstatic HTMLEscapeMap gAsciiHTMLEscapeMap[] = {\n\t// A.2.2. Special characters\n\t{ @\"&quot;\", 34 },\n\t{ @\"&amp;\", 38 },\n\t{ @\"&apos;\", 39 },\n\t{ @\"&lt;\", 60 },\n\t{ @\"&gt;\", 62 },\n\n\t// A.2.1. Latin-1 characters\n\t{ @\"&nbsp;\", 160 },\n\t{ @\"&iexcl;\", 161 },\n\t{ @\"&cent;\", 162 },\n\t{ @\"&pound;\", 163 },\n\t{ @\"&curren;\", 164 },\n\t{ @\"&yen;\", 165 },\n\t{ @\"&brvbar;\", 166 },\n\t{ @\"&sect;\", 167 },\n\t{ @\"&uml;\", 168 },\n\t{ @\"&copy;\", 169 },\n\t{ @\"&ordf;\", 170 },\n\t{ @\"&laquo;\", 171 },\n\t{ @\"&not;\", 172 },\n\t{ @\"&shy;\", 173 },\n\t{ @\"&reg;\", 174 },\n\t{ @\"&macr;\", 175 },\n\t{ @\"&deg;\", 176 },\n\t{ @\"&plusmn;\", 177 },\n\t{ @\"&sup2;\", 178 },\n\t{ @\"&sup3;\", 179 },\n\t{ @\"&acute;\", 180 },\n\t{ @\"&micro;\", 181 },\n\t{ @\"&para;\", 182 },\n\t{ @\"&middot;\", 183 },\n\t{ @\"&cedil;\", 184 },\n\t{ @\"&sup1;\", 185 },\n\t{ @\"&ordm;\", 186 },\n\t{ @\"&raquo;\", 187 },\n\t{ @\"&frac14;\", 188 },\n\t{ @\"&frac12;\", 189 },\n\t{ @\"&frac34;\", 190 },\n\t{ @\"&iquest;\", 191 },\n\t{ @\"&Agrave;\", 192 },\n\t{ @\"&Aacute;\", 193 },\n\t{ @\"&Acirc;\", 194 },\n\t{ @\"&Atilde;\", 195 },\n\t{ @\"&Auml;\", 196 },\n\t{ @\"&Aring;\", 197 },\n\t{ @\"&AElig;\", 198 },\n\t{ @\"&Ccedil;\", 199 },\n\t{ @\"&Egrave;\", 200 },\n\t{ @\"&Eacute;\", 201 },\n\t{ @\"&Ecirc;\", 202 },\n\t{ @\"&Euml;\", 203 },\n\t{ @\"&Igrave;\", 204 },\n\t{ @\"&Iacute;\", 205 },\n\t{ @\"&Icirc;\", 206 },\n\t{ @\"&Iuml;\", 207 },\n\t{ @\"&ETH;\", 208 },\n\t{ @\"&Ntilde;\", 209 },\n\t{ @\"&Ograve;\", 210 },\n\t{ @\"&Oacute;\", 211 },\n\t{ @\"&Ocirc;\", 212 },\n\t{ @\"&Otilde;\", 213 },\n\t{ @\"&Ouml;\", 214 },\n\t{ @\"&times;\", 215 },\n\t{ @\"&Oslash;\", 216 },\n\t{ @\"&Ugrave;\", 217 },\n\t{ @\"&Uacute;\", 218 },\n\t{ @\"&Ucirc;\", 219 },\n\t{ @\"&Uuml;\", 220 },\n\t{ @\"&Yacute;\", 221 },\n\t{ @\"&THORN;\", 222 },\n\t{ @\"&szlig;\", 223 },\n\t{ @\"&agrave;\", 224 },\n\t{ @\"&aacute;\", 225 },\n\t{ @\"&acirc;\", 226 },\n\t{ @\"&atilde;\", 227 },\n\t{ @\"&auml;\", 228 },\n\t{ @\"&aring;\", 229 },\n\t{ @\"&aelig;\", 230 },\n\t{ @\"&ccedil;\", 231 },\n\t{ @\"&egrave;\", 232 },\n\t{ @\"&eacute;\", 233 },\n\t{ @\"&ecirc;\", 234 },\n\t{ @\"&euml;\", 235 },\n\t{ @\"&igrave;\", 236 },\n\t{ @\"&iacute;\", 237 },\n\t{ @\"&icirc;\", 238 },\n\t{ @\"&iuml;\", 239 },\n\t{ @\"&eth;\", 240 },\n\t{ @\"&ntilde;\", 241 },\n\t{ @\"&ograve;\", 242 },\n\t{ @\"&oacute;\", 243 },\n\t{ @\"&ocirc;\", 244 },\n\t{ @\"&otilde;\", 245 },\n\t{ @\"&ouml;\", 246 },\n\t{ @\"&divide;\", 247 },\n\t{ @\"&oslash;\", 248 },\n\t{ @\"&ugrave;\", 249 },\n\t{ @\"&uacute;\", 250 },\n\t{ @\"&ucirc;\", 251 },\n\t{ @\"&uuml;\", 252 },\n\t{ @\"&yacute;\", 253 },\n\t{ @\"&thorn;\", 254 },\n\t{ @\"&yuml;\", 255 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&OElig;\", 338 },\n\t{ @\"&oelig;\", 339 },\n\t{ @\"&Scaron;\", 352 },\n\t{ @\"&scaron;\", 353 },\n\t{ @\"&Yuml;\", 376 },\n\n\t// A.2.3. Symbols\n\t{ @\"&fnof;\", 402 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&circ;\", 710 },\n\t{ @\"&tilde;\", 732 },\n\n\t// A.2.3. Symbols cont'd\n\t{ @\"&Alpha;\", 913 },\n\t{ @\"&Beta;\", 914 },\n\t{ @\"&Gamma;\", 915 },\n\t{ @\"&Delta;\", 916 },\n\t{ @\"&Epsilon;\", 917 },\n\t{ @\"&Zeta;\", 918 },\n\t{ @\"&Eta;\", 919 },\n\t{ @\"&Theta;\", 920 },\n\t{ @\"&Iota;\", 921 },\n\t{ @\"&Kappa;\", 922 },\n\t{ @\"&Lambda;\", 923 },\n\t{ @\"&Mu;\", 924 },\n\t{ @\"&Nu;\", 925 },\n\t{ @\"&Xi;\", 926 },\n\t{ @\"&Omicron;\", 927 },\n\t{ @\"&Pi;\", 928 },\n\t{ @\"&Rho;\", 929 },\n\t{ @\"&Sigma;\", 931 },\n\t{ @\"&Tau;\", 932 },\n\t{ @\"&Upsilon;\", 933 },\n\t{ @\"&Phi;\", 934 },\n\t{ @\"&Chi;\", 935 },\n\t{ @\"&Psi;\", 936 },\n\t{ @\"&Omega;\", 937 },\n\t{ @\"&alpha;\", 945 },\n\t{ @\"&beta;\", 946 },\n\t{ @\"&gamma;\", 947 },\n\t{ @\"&delta;\", 948 },\n\t{ @\"&epsilon;\", 949 },\n\t{ @\"&zeta;\", 950 },\n\t{ @\"&eta;\", 951 },\n\t{ @\"&theta;\", 952 },\n\t{ @\"&iota;\", 953 },\n\t{ @\"&kappa;\", 954 },\n\t{ @\"&lambda;\", 955 },\n\t{ @\"&mu;\", 956 },\n\t{ @\"&nu;\", 957 },\n\t{ @\"&xi;\", 958 },\n\t{ @\"&omicron;\", 959 },\n\t{ @\"&pi;\", 960 },\n\t{ @\"&rho;\", 961 },\n\t{ @\"&sigmaf;\", 962 },\n\t{ @\"&sigma;\", 963 },\n\t{ @\"&tau;\", 964 },\n\t{ @\"&upsilon;\", 965 },\n\t{ @\"&phi;\", 966 },\n\t{ @\"&chi;\", 967 },\n\t{ @\"&psi;\", 968 },\n\t{ @\"&omega;\", 969 },\n\t{ @\"&thetasym;\", 977 },\n\t{ @\"&upsih;\", 978 },\n\t{ @\"&piv;\", 982 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&ensp;\", 8194 },\n\t{ @\"&emsp;\", 8195 },\n\t{ @\"&thinsp;\", 8201 },\n\t{ @\"&zwnj;\", 8204 },\n\t{ @\"&zwj;\", 8205 },\n\t{ @\"&lrm;\", 8206 },\n\t{ @\"&rlm;\", 8207 },\n\t{ @\"&ndash;\", 8211 },\n\t{ @\"&mdash;\", 8212 },\n\t{ @\"&lsquo;\", 8216 },\n\t{ @\"&rsquo;\", 8217 },\n\t{ @\"&sbquo;\", 8218 },\n\t{ @\"&ldquo;\", 8220 },\n\t{ @\"&rdquo;\", 8221 },\n\t{ @\"&bdquo;\", 8222 },\n\t{ @\"&dagger;\", 8224 },\n\t{ @\"&Dagger;\", 8225 },\n\t// A.2.3. Symbols cont'd\n\t{ @\"&bull;\", 8226 },\n\t{ @\"&hellip;\", 8230 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&permil;\", 8240 },\n\n\t// A.2.3. Symbols cont'd\n\t{ @\"&prime;\", 8242 },\n\t{ @\"&Prime;\", 8243 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&lsaquo;\", 8249 },\n\t{ @\"&rsaquo;\", 8250 },\n\n\t// A.2.3. Symbols cont'd\n\t{ @\"&oline;\", 8254 },\n\t{ @\"&frasl;\", 8260 },\n\n\t// A.2.2. Special characters cont'd\n\t{ @\"&euro;\", 8364 },\n\n\t// A.2.3. Symbols cont'd\n\t{ @\"&image;\", 8465 },\n\t{ @\"&weierp;\", 8472 },\n\t{ @\"&real;\", 8476 },\n\t{ @\"&trade;\", 8482 },\n\t{ @\"&alefsym;\", 8501 },\n\t{ @\"&larr;\", 8592 },\n\t{ @\"&uarr;\", 8593 },\n\t{ @\"&rarr;\", 8594 },\n\t{ @\"&darr;\", 8595 },\n\t{ @\"&harr;\", 8596 },\n\t{ @\"&crarr;\", 8629 },\n\t{ @\"&lArr;\", 8656 },\n\t{ @\"&uArr;\", 8657 },\n\t{ @\"&rArr;\", 8658 },\n\t{ @\"&dArr;\", 8659 },\n\t{ @\"&hArr;\", 8660 },\n\t{ @\"&forall;\", 8704 },\n\t{ @\"&part;\", 8706 },\n\t{ @\"&exist;\", 8707 },\n\t{ @\"&empty;\", 8709 },\n\t{ @\"&nabla;\", 8711 },\n\t{ @\"&isin;\", 8712 },\n\t{ @\"&notin;\", 8713 },\n\t{ @\"&ni;\", 8715 },\n\t{ @\"&prod;\", 8719 },\n\t{ @\"&sum;\", 8721 },\n\t{ @\"&minus;\", 8722 },\n\t{ @\"&lowast;\", 8727 },\n\t{ @\"&radic;\", 8730 },\n\t{ @\"&prop;\", 8733 },\n\t{ @\"&infin;\", 8734 },\n\t{ @\"&ang;\", 8736 },\n\t{ @\"&and;\", 8743 },\n\t{ @\"&or;\", 8744 },\n\t{ @\"&cap;\", 8745 },\n\t{ @\"&cup;\", 8746 },\n\t{ @\"&int;\", 8747 },\n\t{ @\"&there4;\", 8756 },\n\t{ @\"&sim;\", 8764 },\n\t{ @\"&cong;\", 8773 },\n\t{ @\"&asymp;\", 8776 },\n\t{ @\"&ne;\", 8800 },\n\t{ @\"&equiv;\", 8801 },\n\t{ @\"&le;\", 8804 },\n\t{ @\"&ge;\", 8805 },\n\t{ @\"&sub;\", 8834 },\n\t{ @\"&sup;\", 8835 },\n\t{ @\"&nsub;\", 8836 },\n\t{ @\"&sube;\", 8838 },\n\t{ @\"&supe;\", 8839 },\n\t{ @\"&oplus;\", 8853 },\n\t{ @\"&otimes;\", 8855 },\n\t{ @\"&perp;\", 8869 },\n\t{ @\"&sdot;\", 8901 },\n\t{ @\"&lceil;\", 8968 },\n\t{ @\"&rceil;\", 8969 },\n\t{ @\"&lfloor;\", 8970 },\n\t{ @\"&rfloor;\", 8971 },\n\t{ @\"&lang;\", 9001 },\n\t{ @\"&rang;\", 9002 },\n\t{ @\"&loz;\", 9674 },\n\t{ @\"&spades;\", 9824 },\n\t{ @\"&clubs;\", 9827 },\n\t{ @\"&hearts;\", 9829 },\n\t{ @\"&diams;\", 9830 }\n};\n\n// Taken from http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters\n// This is table A.2.2 Special Characters\nstatic HTMLEscapeMap gUnicodeHTMLEscapeMap[] = {\n\t// C0 Controls and Basic Latin\n\t{ @\"&quot;\", 34 },\n\t{ @\"&amp;\", 38 },\n\t{ @\"&apos;\", 39 },\n\t{ @\"&lt;\", 60 },\n\t{ @\"&gt;\", 62 },\n\n\t// Latin Extended-A\n\t{ @\"&OElig;\", 338 },\n\t{ @\"&oelig;\", 339 },\n\t{ @\"&Scaron;\", 352 },\n\t{ @\"&scaron;\", 353 },\n\t{ @\"&Yuml;\", 376 },\n\n\t// Spacing Modifier Letters\n\t{ @\"&circ;\", 710 },\n\t{ @\"&tilde;\", 732 },\n\n\t// General Punctuation\n\t{ @\"&ensp;\", 8194 },\n\t{ @\"&emsp;\", 8195 },\n\t{ @\"&thinsp;\", 8201 },\n\t{ @\"&zwnj;\", 8204 },\n\t{ @\"&zwj;\", 8205 },\n\t{ @\"&lrm;\", 8206 },\n\t{ @\"&rlm;\", 8207 },\n\t{ @\"&ndash;\", 8211 },\n\t{ @\"&mdash;\", 8212 },\n\t{ @\"&lsquo;\", 8216 },\n\t{ @\"&rsquo;\", 8217 },\n\t{ @\"&sbquo;\", 8218 },\n\t{ @\"&ldquo;\", 8220 },\n\t{ @\"&rdquo;\", 8221 },\n\t{ @\"&bdquo;\", 8222 },\n\t{ @\"&dagger;\", 8224 },\n\t{ @\"&Dagger;\", 8225 },\n\t{ @\"&permil;\", 8240 },\n\t{ @\"&lsaquo;\", 8249 },\n\t{ @\"&rsaquo;\", 8250 },\n\t{ @\"&euro;\", 8364 },\n};\n\n// Utility function for Bsearching table above\nstatic int EscapeMapCompare(const void *ucharVoid, const void *mapVoid) {\n\tconst unichar *uchar = (const unichar*)ucharVoid;\n\tconst HTMLEscapeMap *map = (const HTMLEscapeMap*)mapVoid;\n\tint val;\n\tif (*uchar > map->uchar) {\n\t\tval = 1;\n\t} else if (*uchar < map->uchar) {\n\t\tval = -1;\n\t} else {\n\t\tval = 0;\n\t}\n\treturn val;\n}\n\nstatic NSString *StringByEscapingHTMLUsingTable(NSString *src,\n\t\t\t\t\t\t\t\t\t\t\t\tHTMLEscapeMap* table,\n\t\t\t\t\t\t\t\t\t\t\t\tNSUInteger tableSize,\n\t\t\t\t\t\t\t\t\t\t\t\tBOOL escapeUnicode) {\n\tNSUInteger length = [src length];\n\tif (!length) {\n\t\treturn src;\n\t}\n\n\tNSMutableString *finalString = [NSMutableString string];\n\tNSMutableData *data2 = [NSMutableData dataWithCapacity:sizeof(unichar) * length];\n\n\t// this block is common between GTMNSString+HTML and GTMNSString+XML but\n\t// it's so short that it isn't really worth trying to share.\n\tconst unichar *buffer = CFStringGetCharactersPtr((CFStringRef)src);\n\tif (!buffer) {\n\t\t// We want this buffer to be autoreleased.\n\t\tNSMutableData *data = [NSMutableData dataWithLength:length * sizeof(UniChar)];\n\t\tif (!data) {\n\t\t\t// COV_NF_START  - Memory fail case\n\t\t\t// If we can't get enough memory for the buffer copy, odds are finalString\n\t\t\t// will also run out of memory, so just give up.\n\t\t\tNSCAssert(NO, @\"couldn't alloc buffer\");\n\t\t\t// COV_NF_END\n\t\t}\n\t\t[src getCharacters:[data mutableBytes]];\n\t\tbuffer = [data bytes];\n\t}\n\n\tif (!buffer || !data2) {\n\t\t// If we can't get enough memory for the buffer copy, odds are finalString\n\t\t// will also run out of memory, so just give up.\n\t\tNSCAssert(NO, @\"Unable to allocate buffer or data2\");\n\t}\n\n\tunichar *buffer2 = (unichar *)[data2 mutableBytes];\n\n\tNSUInteger buffer2Length = 0;\n\n\tfor (NSUInteger i = 0; i < length; ++i) {\n\t\tHTMLEscapeMap *val = bsearch(&buffer[i], table,\n\t\t\t\t\t\t\t\t\t tableSize / sizeof(HTMLEscapeMap),\n\t\t\t\t\t\t\t\t\t sizeof(HTMLEscapeMap), EscapeMapCompare);\n\t\tif (val || (escapeUnicode && buffer[i] > 127)) {\n\t\t\tif (buffer2Length) {\n\t\t\t\tCFStringAppendCharacters((CFMutableStringRef)finalString,\n\t\t\t\t\t\t\t\t\t\t buffer2,\n\t\t\t\t\t\t\t\t\t\t buffer2Length);\n\t\t\t\tbuffer2Length = 0;\n\t\t\t}\n\t\t\tif (val) {\n\t\t\t\t[finalString appendString:val->escapeSequence];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tNSCAssert((escapeUnicode && buffer[i] > 127), @\"Illegal Character\");\n\t\t\t\t[finalString appendFormat:@\"&#%d;\", buffer[i]];\n\t\t\t}\n\t\t} else {\n\t\t\tbuffer2[buffer2Length] = buffer[i];\n\t\t\tbuffer2Length += 1;\n\t\t}\n\t}\n\tif (buffer2Length) {\n\t\tCFStringAppendCharacters((CFMutableStringRef)finalString,\n\t\t\t\t\t\t\t\t buffer2,\n\t\t\t\t\t\t\t\t buffer2Length);\n\t}\n\treturn finalString;\n}\n\n@implementation NSString (GTMNSStringHTMLAdditions)\n\n- (NSString *)gtm_stringByEscapingForHTML {\n\treturn StringByEscapingHTMLUsingTable(self,\n\t\t\t\t\t\t\t\t\t\t  gUnicodeHTMLEscapeMap,\n\t\t\t\t\t\t\t\t\t\t  sizeof(gUnicodeHTMLEscapeMap),\n\t\t\t\t\t\t\t\t\t\t  /*escapingUnicode=*/NO);\n} // gtm_stringByEscapingHTML\n\n- (NSString *)gtm_stringByEscapingForAsciiHTML {\n\treturn StringByEscapingHTMLUsingTable(self,\n\t\t\t\t\t\t\t\t\t\t  gAsciiHTMLEscapeMap,\n\t\t\t\t\t\t\t\t\t\t  sizeof(gAsciiHTMLEscapeMap),\n\t\t\t\t\t\t\t\t\t\t  /*escapingUnicode=*/YES);\n} // gtm_stringByEscapingAsciiHTML\n\n- (NSString *)gtm_stringByUnescapingFromHTML {\n\tNSRange range = NSMakeRange(0, [self length]);\n\tNSRange subrange = [self rangeOfString:@\"&\" options:NSBackwardsSearch range:range];\n\n\t// if no ampersands, we've got a quick way out\n\tif (subrange.length == 0) return self;\n\tNSMutableString *finalString = [NSMutableString stringWithString:self];\n\tdo {\n\t\tNSRange semiColonRange = NSMakeRange(subrange.location, NSMaxRange(range) - subrange.location);\n\t\tsemiColonRange = [self rangeOfString:@\";\" options:0 range:semiColonRange];\n\t\trange = NSMakeRange(0, subrange.location);\n\t\t// if we don't find a semicolon in the range, we don't have a sequence\n\t\tif (semiColonRange.location == NSNotFound) {\n\t\t\tcontinue;\n\t\t}\n\t\tNSRange escapeRange = NSMakeRange(subrange.location, semiColonRange.location - subrange.location + 1);\n\t\tNSString *escapeString = [self substringWithRange:escapeRange];\n\t\tNSUInteger length = [escapeString length];\n\t\t// a squence must be longer than 3 (&lt;) and less than 11 (&thetasym;)\n\t\tif (length > 3 && length < 11) {\n\t\t\tif ([escapeString characterAtIndex:1] == '#') {\n\t\t\t\tunichar char2 = [escapeString characterAtIndex:2];\n\t\t\t\tif (char2 == 'x' || char2 == 'X') {\n\t\t\t\t\t// Hex escape squences &#xa3;\n\t\t\t\t\tNSString *hexSequence = [escapeString substringWithRange:NSMakeRange(3, length - 4)];\n\t\t\t\t\tNSScanner *scanner = [NSScanner scannerWithString:hexSequence];\n\t\t\t\t\tunsigned value;\n\t\t\t\t\tif ([scanner scanHexInt:&value] &&\n\t\t\t\t\t\tvalue > 0\n\t\t\t\t\t\t&& [scanner scanLocation] == length - 4) {\n\t\t\t\t\t\tif (value < USHRT_MAX) {\n\t\t\t\t\t\t\tunichar uchar = (unichar)value;\n\t\t\t\t\t\t\tNSString *charString = [NSString stringWithCharacters:&uchar length:1];\n\t\t\t\t\t\t\t[finalString replaceCharactersInRange:escapeRange withString:charString];\n\t\t\t\t\t\t} else if (value >= 0x10000 && value <= 0x10FFFF) {\n\t\t\t\t\t\t\t// code points in unicode supplementary planes\n\t\t\t\t\t\t\tint subtractedValue = value - 0x10000;\n\t\t\t\t\t\t\tunichar uchars[2];\n\t\t\t\t\t\t\tuchars[0] = 0xD800 + (subtractedValue >> 10);\n\t\t\t\t\t\t\tuchars[1] = 0xDC00 + (subtractedValue & 0x3FF);\n\t\t\t\t\t\t\tNSString *charString = [NSString stringWithCharacters:uchars length:2];\n\t\t\t\t\t\t\tif (charString) {\n\t\t\t\t\t\t\t\t[finalString replaceCharactersInRange:escapeRange withString:charString];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Decimal Sequences &#123;\n\t\t\t\t\tNSString *numberSequence = [escapeString substringWithRange:NSMakeRange(2, length - 3)];\n\t\t\t\t\tNSScanner *scanner = [NSScanner scannerWithString:numberSequence];\n\t\t\t\t\tint value;\n\t\t\t\t\tif ([scanner scanInt:&value] &&\n\t\t\t\t\t\tvalue > 0\n\t\t\t\t\t\t&& [scanner scanLocation] == length - 3) {\n\t\t\t\t\t\tif (value < USHRT_MAX) {\n\t\t\t\t\t\t\tunichar uchar = (unichar)value;\n\t\t\t\t\t\t\tNSString *charString = [NSString stringWithCharacters:&uchar length:1];\n\t\t\t\t\t\t\t[finalString replaceCharactersInRange:escapeRange withString:charString];\n\t\t\t\t\t\t} else if (value >= 0x10000 && value <= 0x10FFFF) {\n\t\t\t\t\t\t\t// code points in unicode supplementary planes\n\t\t\t\t\t\t\tint subtractedValue = value - 0x10000;\n\t\t\t\t\t\t\tunichar uchars[2];\n\t\t\t\t\t\t\tuchars[0] = 0xD800 + (subtractedValue >> 10);\n\t\t\t\t\t\t\tuchars[1] = 0xDC00 + (subtractedValue & 0x3FF);\n\t\t\t\t\t\t\tNSString *charString = [NSString stringWithCharacters:uchars length:2];\n\t\t\t\t\t\t\tif (charString) {\n\t\t\t\t\t\t\t\t[finalString replaceCharactersInRange:escapeRange withString:charString];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// \"standard\" sequences\n\t\t\t\tfor (unsigned i = 0; i < sizeof(gAsciiHTMLEscapeMap) / sizeof(HTMLEscapeMap); ++i) {\n\t\t\t\t\tif ([escapeString isEqualToString:gAsciiHTMLEscapeMap[i].escapeSequence]) {\n\t\t\t\t\t\t[finalString replaceCharactersInRange:escapeRange withString:[NSString stringWithCharacters:&gAsciiHTMLEscapeMap[i].uchar length:1]];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} while ((subrange = [self rangeOfString:@\"&\" options:NSBackwardsSearch range:range]).length != 0);\n\treturn finalString;\n} // gtm_stringByUnescapingHTML\n\n@end\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/External Libraries/WebKit/WebScriptObjectHelper.m",
    "content": "/* *********************************************************************\n\n        Copyright (c) 2010 - 2018 Codeux Software, LLC\n     Please see ACKNOWLEDGEMENT for additional information.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions\n are met:\n\n * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n * Neither the name of \"Codeux Software, LLC\", nor the names of its \n   contributors may be used to endorse or promote products derived \n   from this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n SUCH DAMAGE.\n\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\n#import \"WebScriptObjectHelperPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation WebScriptObject (TXWebScriptObjectHelper)\n\n- (nullable id)toCommonInContext:(JSContextRef)jsContextRef\n{\n\tNSParameterAssert(jsContextRef != NULL);\n\n\tJSObjectRef jsObjectRef = [self JSObject];\n\n\t/* The object is useless if it is a function */\n\tif (JSObjectIsFunction(jsContextRef, jsObjectRef)) {\n\t\tLogToConsoleDebug(\"Ignoring a JSObject that is a function\");\n\n\t\treturn nil;\n\t}\n\n\t/* If the object is an array, then parse it as such */\n\tif ([WebScriptObject jsObjectIsArray:jsObjectRef inContext:jsContextRef]) {\n\t\tNSNumber *arrayLengthObject = [self valueForKey:@\"length\"];\n\n\t\tNSUInteger arrayLength = arrayLengthObject.unsignedIntegerValue;\n\n\t\tNSMutableArray *scriptArray = [NSMutableArray arrayWithCapacity:arrayLength];\n\n\t\tfor (NSUInteger i = 0; i < arrayLength; i++) {\n\t\t\tid item = [self webScriptValueAtIndex:(unsigned)i];\n\n\t\t\tif ([item isKindOfClass:[WebScriptObject class]]) {\n\t\t\t\titem = [item toCommonInContext:jsContextRef];\n\t\t\t} else if ([item isKindOfClass:[WebUndefined class]]) {\n\t\t\t\titem = nil;\n\t\t\t}\n\n\t\t\tif (item) {\n\t\t\t\t[scriptArray addObject:item];\n\t\t\t} else {\n\t\t\t\t[scriptArray addObject:[NSNull null]];\n\t\t\t}\n\t\t}\n\n\t\treturn scriptArray;\n\t}\n\n\t/* If the object is an object (dictionary), then parse it as such */\n\tif ([WebScriptObject jsObjectIsObject:jsObjectRef inContext:jsContextRef]) {\n\t\tJSPropertyNameArrayRef objectProperties = JSObjectCopyPropertyNames(jsContextRef, jsObjectRef);\n\n\t\tsize_t objectPropertiesCount = JSPropertyNameArrayGetCount(objectProperties);\n\n\t\tNSMutableDictionary *scriptDictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)objectPropertiesCount];\n\n\t\tfor (NSUInteger i = 0; i < objectPropertiesCount; i++) {\n\t\t\tJSStringRef propertyName = JSPropertyNameArrayGetNameAtIndex(objectProperties, i);\n\n\t\t\tNSString *propertyNameCocoa = (__bridge_transfer NSString *)JSStringCopyCFString(kCFAllocatorDefault, propertyName);\n\n\t\t\tid item = [self valueForKey:propertyNameCocoa];\n\n\t\t\tif ([item isKindOfClass:[WebScriptObject class]]) {\n\t\t\t\titem = [item toCommonInContext:jsContextRef];\n\t\t\t} else if ([item isKindOfClass:[WebUndefined class]]) {\n\t\t\t\titem = nil;\n\t\t\t}\n\n\t\t\tif (item) {\n\t\t\t\tscriptDictionary[propertyNameCocoa] = item;\n\t\t\t} else {\n\t\t\t\tscriptDictionary[propertyNameCocoa] = [NSNull null];\n\t\t\t}\n\t\t}\n\n\t\treturn scriptDictionary;\n\t}\n\n\treturn nil;\n}\n\n+ (BOOL)jsObjectIsArray:(JSObjectRef)jsObjectRef inContext:(JSContextRef)jsContextRef\n{\n\tNSParameterAssert(jsObjectRef != NULL);\n\tNSParameterAssert(jsContextRef != NULL);\n\n\tJSObjectRef jsGlobalObjectRef = JSContextGetGlobalObject(jsContextRef);\n\n\tJSStringRef arrayString = JSStringCreateWithUTF8CString(\"Array\");\n\n\tJSObjectRef arrayPrototype = (JSObjectRef)JSObjectGetProperty(jsContextRef, jsGlobalObjectRef, arrayString, NULL);\n\n\tJSStringRelease(arrayString);\n\n\treturn JSValueIsInstanceOfConstructor(jsContextRef, jsObjectRef, arrayPrototype, NULL);\n}\n\n+ (BOOL)jsObjectIsObject:(JSObjectRef)jsObjectRef inContext:(JSContextRef)jsContextRef\n{\n\tNSParameterAssert(jsObjectRef != NULL);\n\tNSParameterAssert(jsContextRef != NULL);\n\n\tJSObjectRef jsGlobalObjectRef = JSContextGetGlobalObject(jsContextRef);\n\n\tJSStringRef objectString = JSStringCreateWithUTF8CString(\"Object\");\n\n\tJSObjectRef objectPrototype = (JSObjectRef)JSObjectGetProperty(jsContextRef, jsGlobalObjectRef, objectString, NULL);\n\n\tJSStringRelease(objectString);\n\n\treturn JSValueIsInstanceOfConstructor(jsContextRef, jsObjectRef, objectPrototype, NULL);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Plugin Architecture/THOPluginDispatcher.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClient.h\"\n#import \"IRCMessage.h\"\n#import \"THOPluginItemPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"THOPluginProtocolPrivate.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const THOPluginProtocolCompatibilityMinimumVersion = @\"7.2.4\";\n\n@interface IRCMessage (IRCMessagePluginExtension)\n- (THOPluginDidReceiveServerInputConcreteObject *)didReceiveServerInputConcreteObject;\n@end\n\n@implementation THOPluginDispatcher\n\n+ (dispatch_queue_t)dispatchQueue\n{\n\tstatic dispatch_queue_t dispatchQueue = NULL;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdispatchQueue =\n\t\tXRCreateDispatchQueueWithPriority(\"Textual.THOPluginDispatcher.PluginManagerDispatchQueue\", DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);\n\t});\n\n\treturn dispatchQueue;\n}\n\n+ (BOOL)receivedCommand:(NSString *)command withText:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt referenceMessage:(nullable IRCMessage *)referenceMessage\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(receivedAt != nil);\n\n\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t{\n\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureDidReceiveCommandEvent] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tBOOL returnedValue = [plugin.primaryClass receivedCommand:command withText:text authoredBy:textAuthor destinedFor:textDestination onClient:client receivedAt:receivedAt referenceMessage:referenceMessage];\n\n\t\tif (returnedValue == NO) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n+ (BOOL)receivedText:(NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination asLineType:(TVCLogLineType)lineType onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt wasEncrypted:(BOOL)wasEncrypted\n{\n\tNSParameterAssert(text != nil);\n\tNSParameterAssert(textAuthor != nil);\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(receivedAt != nil);\n\n\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t{\n\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tBOOL returnedValue = [plugin.primaryClass receivedText:text authoredBy:textAuthor destinedFor:textDestination asLineType:lineType onClient:client receivedAt:receivedAt wasEncrypted:wasEncrypted];\n\n\t\tif (returnedValue == NO) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n+ (nullable IRCMessage *)interceptServerInput:(IRCMessage *)inputObject for:(IRCClient *)client\n{\n\tNSParameterAssert(inputObject != nil);\n\tNSParameterAssert(client != nil);\n\n\tIRCMessage *returnValue = inputObject;\n\n\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t{\n\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureServerInputDataInterception] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tIRCMessage *returnedValue = [plugin.primaryClass interceptServerInput:returnValue for:client];\n\n\t\tif (returnedValue == nil) {\n\t\t\treturn nil;\n\t\t} else if (returnedValue != returnValue) {\n\t\t\tif ([returnedValue isKindOfClass:[IRCMessageMutable class]]) {\n\t\t\t\treturnValue = [returnedValue copy];\n\t\t\t} else {\n\t\t\t\treturnValue = returnedValue;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn returnValue;\n}\n\n+ (nullable id)interceptUserInput:(id)inputObject command:(IRCRemoteCommand)commandString\n{\n\tNSParameterAssert(inputObject != nil);\n\n\tid returnValue = inputObject;\n\n\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t{\n\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureUserInputDataInterception] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tid returnedValue = [plugin.primaryClass interceptUserInput:returnValue command:commandString];\n\n\t\tif (returnedValue == nil) {\n\t\t\treturn nil;\n\t\t} else if ([returnedValue isEqual:returnValue] == NO &&\n\t\t\t\t   ([returnedValue isKindOfClass:[NSString class]] ||\n\t\t\t\t\t[returnedValue isKindOfClass:[NSAttributedString class]]))\n\t\t{\n\t\t\tif ([returnedValue isKindOfClass:[NSMutableString class]] ||\n\t\t\t\t[returnedValue isKindOfClass:[NSMutableAttributedString class]])\n\t\t\t{\n\t\t\t\treturnValue = [returnedValue copy];\n\t\t\t} else {\n\t\t\t\treturnValue = returnedValue;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn returnValue;\n}\n\n+ (NSString *)willRenderMessage:(NSString *)newMessage forViewController:(TVCLogController *)viewController lineType:(TVCLogLineType)lineType memberType:(TVCLogLineMemberType)memberType\n{\n\tNSParameterAssert(newMessage != nil);\n\tNSParameterAssert(viewController != nil);\n\n\tNSString *returnValue = newMessage;\n\n\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t{\n\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureWillRenderMessageEvent] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *returnedValue = [plugin.primaryClass willRenderMessage:returnValue forViewController:viewController lineType:lineType memberType:memberType];\n\n\t\tif (returnedValue.length == 0) {\n\t\t\tcontinue;\n\t\t} else if ([returnedValue isEqualToString:returnValue]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\treturnValue = [returnedValue copy];\n\t}\n\n\treturn returnValue;\n}\n\n+ (void)userInputCommandInvokedOnClient:(IRCClient *)client commandString:(NSString *)commandString messageString:(NSString *)messageString\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(commandString != nil);\n\tNSParameterAssert(messageString != nil);\n\n\tXRPerformBlockAsynchronouslyOnQueue([self dispatchQueue], ^{\n\t\tNSString *lowercaseCommand = commandString.lowercaseString;\n\n\t\tNSString *uppercaseCommand = commandString.uppercaseString;\n\n\t\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t\t{\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureSubscribedUserInputCommands] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([plugin.supportedUserInputCommands containsObject:lowercaseCommand] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[plugin.primaryClass userInputCommandInvokedOnClient:client commandString:uppercaseCommand messageString:messageString];\n\t\t}\n\t});\n}\n\n+ (void)didReceiveJavaScriptPayload:(THOPluginWebViewJavaScriptPayloadConcreteObject *)payloadObject fromViewController:(TVCLogController *)viewController\n{\n\tNSParameterAssert(payloadObject != nil);\n\tNSParameterAssert(viewController != nil);\n\n\tXRPerformBlockAsynchronouslyOnQueue([self dispatchQueue], ^{\n\t\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t\t{\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureWebViewJavaScriptPayloads] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[plugin.primaryClass didReceiveJavaScriptPayload:payloadObject fromViewController:viewController];\n\t\t}\n\t});\n}\n\n+ (void)didReceiveServerInput:(IRCMessage *)inputObject onClient:(IRCClient *)client\n{\n\tNSParameterAssert(inputObject != nil);\n\tNSParameterAssert(client != nil);\n\n\tXRPerformBlockAsynchronouslyOnQueue([self dispatchQueue], ^{\n\t\tTHOPluginDidReceiveServerInputConcreteObject *messageObject =\n\t\tinputObject.didReceiveServerInputConcreteObject;\n\n\t\tmessageObject.networkAddress = client.serverAddress;\n\t\tmessageObject.networkName = client.networkName;\n\n\t\tNSString *lowercaseCommand = inputObject.command.lowercaseString;\n\n\t\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t\t{\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureSubscribedServerInputCommands] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([plugin.supportedServerInputCommands containsObject:lowercaseCommand] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[plugin.primaryClass didReceiveServerInput:messageObject onClient:client];\n\t\t}\n\t});\n}\n\n+ (NSCache<NSString *, THOPluginDidPostNewMessageConcreteObject *> *)didPostNewMessageObjectCache\n{\n\tstatic NSCache *queue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tqueue = [NSCache new];\n\t});\n\n\treturn queue;\n}\n\n+ (void)enqueueDidPostNewMessage:(THOPluginDidPostNewMessageConcreteObject *)messageObject\n{\n\tNSParameterAssert(messageObject != nil);\n\n\t[[self didPostNewMessageObjectCache] setObject:messageObject forKey:messageObject.lineNumber];\n}\n\n+ (void)dequeueDidPostNewMessageWithLineNumber:(NSString *)messageLineNumber forViewController:(TVCLogController *)viewController\n{\n\tNSParameterAssert(messageLineNumber != nil);\n\tNSParameterAssert(viewController != nil);\n\n\tTHOPluginDidPostNewMessageConcreteObject *messageObject = [[self didPostNewMessageObjectCache] objectForKey:messageLineNumber];\n\n\tif (messageObject == nil) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockAsynchronouslyOnQueue([self dispatchQueue], ^{\n\t\tfor (THOPluginItem *plugin in sharedPluginManager().loadedPlugins)\n\t\t{\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureNewMessagePostedEvent] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[plugin.primaryClass didPostNewMessage:messageObject forViewController:viewController];\n\t\t}\n\t});\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCMessage (IRCMessagePluginExtension)\n\n- (THOPluginDidReceiveServerInputConcreteObject *)didReceiveServerInputConcreteObject\n{\n\t THOPluginDidReceiveServerInputConcreteObject *messageObject =\n\t[THOPluginDidReceiveServerInputConcreteObject new];\n\n\tmessageObject.senderIsServer = self.senderIsServer;\n\n\tmessageObject.senderNickname = self.senderNickname;\n\tmessageObject.senderUsername = self.senderUsername;\n\tmessageObject.senderAddress = self.senderAddress;\n\tmessageObject.senderHostmask = self.senderHostmask;\n\n\tmessageObject.receivedAt = self.receivedAt;\n\n\tmessageObject.messageParameters = self.params;\n\tmessageObject.messageParamaters = self.params;\n\tmessageObject.messageSequence = self.sequence;\n\n\tmessageObject.messageCommand = self.command;\n\tmessageObject.messageCommandNumeric = self.commandNumeric;\n\n\treturn messageObject;\n}\n\n@end\n\n#pragma mark -\n\n@implementation THOPluginDidPostNewMessageConcreteObject\n@end\n\n#pragma mark -\n\n@implementation THOPluginDidReceiveServerInputConcreteObject\n@end\n\n#pragma mark -\n\n@implementation THOPluginWebViewJavaScriptPayloadConcreteObject\n@end\n\n#pragma mark -\n\n@implementation THOPluginOutputSuppressionRule\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Plugin Architecture/THOPluginItem.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"THOPluginProtocol.h\"\n#import \"THOPluginItemPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface THOPluginItem ()\n@property (nonatomic, strong, readwrite, nullable) NSBundle *bundle;\n@property (nonatomic, strong, readwrite, nullable) id primaryClass;\n@property (nonatomic, assign, readwrite) THOPluginItemSupportedFeature supportedFeatures;\n@property (nonatomic, copy, readwrite, nullable) NSArray<NSString *> *supportedUserInputCommands;\n@property (nonatomic, copy, readwrite, nullable) NSArray<NSString *> *supportedServerInputCommands;\n@property (nonatomic, copy, readwrite, nullable) NSArray<THOPluginOutputSuppressionRule *> *outputSuppressionRules;\n@property (nonatomic, copy, readwrite, nullable) NSString *pluginPreferencesPaneMenuItemTitle;\n@property (nonatomic, strong, readwrite, nullable) NSView *pluginPreferencesPaneView;\n@end\n\n@implementation THOPluginItem\n\n#define _isClass(o, t)\t\t\t\t [o isKindOfClass:[t class]]\n#define _isNotEmptyArray(o)\t\t\t([o isKindOfClass:[NSArray class]] && [(NSArray *)o count] > 0)\n#define _isNotEmptyString(o)\t\t([o isKindOfClass:[NSString class]] && [(NSString *)o length] > 0)\n\n- (BOOL)loadBundle:(NSBundle *)bundle\n{\n\tNSParameterAssert(bundle != nil);\n\n\t/* Initialize the principal class */\n\tClass principalClass = bundle.principalClass;\n\n\tif (principalClass == nil) {\n\t\treturn NO;\n\t}\n\n\tid <THOPluginProtocol> primaryClass = [[principalClass alloc] init];\n\n\tif ([primaryClass respondsToSelector:@selector(pluginLoadedIntoMemory)]) {\n\t\t[primaryClass pluginLoadedIntoMemory];\n\t}\n\n\t/* Build list of supported features */\n\tTHOPluginItemSupportedFeature supportedFeatures = 0;\n\n\t/* Process server output suppression rules */\n\tif ([primaryClass respondsToSelector:@selector(pluginOutputSuppressionRules)])\n\t{\n\t\tid outputRules = primaryClass.pluginOutputSuppressionRules;\n\n\t\tif (_isNotEmptyArray(outputRules)) {\n\t\t\tNSMutableArray *sharedRules = [NSMutableArray array];\n\n\t\t\tfor (id outputRule in outputRules) {\n\t\t\t\tif (_isClass(outputRule, THOPluginOutputSuppressionRule) == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[sharedRules addObject:outputRule];\n\t\t\t}\n\n\t\t\tself.outputSuppressionRules = sharedRules;\n\n\t\t\tsupportedFeatures |= THOPluginItemSupportedFeatureOutputSuppressionRules;\n\t\t}\n\t}\n\n\t/* Does the bundle have a preference pane?... */\n\tif ([primaryClass respondsToSelector:@selector(pluginPreferencesPaneMenuItemName)] &&\n\t\t[primaryClass respondsToSelector:@selector(pluginPreferencesPaneView)])\n\t{\n\t\tid itemTitle = primaryClass.pluginPreferencesPaneMenuItemName;\n\t\tid itemView = primaryClass.pluginPreferencesPaneView;\n\n\t\tif (_isNotEmptyString(itemTitle) && _isClass(itemView, NSView)) {\n\t\t\tself.pluginPreferencesPaneMenuItemTitle = itemTitle;\n\t\t\tself.pluginPreferencesPaneView = itemView;\n\n\t\t\tsupportedFeatures |= THOPluginItemSupportedFeaturePreferencePane;\n\t\t}\n\t}\n\n\t/* Process user input commands */\n\tif ([primaryClass respondsToSelector:@selector(subscribedUserInputCommands)] &&\n\t\t[primaryClass respondsToSelector:@selector(userInputCommandInvokedOnClient:commandString:messageString:)])\n\t{\n\t\tid subscribedCommands = primaryClass.subscribedUserInputCommands;\n\n\t\tif (_isNotEmptyArray(subscribedCommands)) {\n\t\t\tNSMutableArray *supportedCommands = [NSMutableArray array];\n\n\t\t\tfor (id command in subscribedCommands) {\n\t\t\t\tif (_isNotEmptyString(command) == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[supportedCommands addObject:[command lowercaseString]];\n\t\t\t}\n\n\t\t\tself.supportedUserInputCommands = supportedCommands;\n\n\t\t\tsupportedFeatures |= THOPluginItemSupportedFeatureSubscribedUserInputCommands;\n\t\t}\n\t}\n\n\t/* Process server input commands */\n\tif ([primaryClass respondsToSelector:@selector(subscribedServerInputCommands)] &&\n\t\t[primaryClass respondsToSelector:@selector(didReceiveServerInput:onClient:)])\n\t{\n\t\tid subscribedCommands = primaryClass.subscribedServerInputCommands;\n\n\t\tif (_isNotEmptyArray(subscribedCommands)) {\n\t\t\tNSMutableArray *supportedCommands = [NSMutableArray array];\n\n\t\t\tfor (id command in subscribedCommands) {\n\t\t\t\tif (_isNotEmptyString(command) == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[supportedCommands addObject:[command lowercaseString]];\n\t\t\t}\n\n\t\t\tself.supportedServerInputCommands = supportedCommands;\n\n\t\t\tsupportedFeatures |= THOPluginItemSupportedFeatureSubscribedServerInputCommands;\n\t\t}\n\t}\n\n\t/* Check whether plugin supports certain events so we do not have\n\t to ask if it responds to the selector every time we call it. */\n\n\t/* Renderer events */\n\tif ([primaryClass respondsToSelector:@selector(didPostNewMessage:forViewController:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureNewMessagePostedEvent;\n\t}\n\n\tif ([primaryClass respondsToSelector:@selector(willRenderMessage:forViewController:lineType:memberType:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureWillRenderMessageEvent;\n\t}\n\n\tif ([primaryClass respondsToSelector:@selector(didReceiveJavaScriptPayload:fromViewController:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureWebViewJavaScriptPayloads;\n\t}\n\n\t/* Data interception */\n\tif ([primaryClass respondsToSelector:@selector(interceptServerInput:for:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureServerInputDataInterception;\n\t}\n\n\tif ([primaryClass respondsToSelector:@selector(interceptUserInput:command:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureUserInputDataInterception;\n\t}\n\n\tif ([primaryClass respondsToSelector:@selector(receivedText:authoredBy:destinedFor:asLineType:onClient:receivedAt:wasEncrypted:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent;\n\t}\n\n\tif ([primaryClass respondsToSelector:@selector(receivedCommand:withText:authoredBy:destinedFor:onClient:receivedAt:referenceMessage:)]) {\n\t\tsupportedFeatures |= THOPluginItemSupportedFeatureDidReceiveCommandEvent;\n\t}\n\n\t/* Finish up */\n\tself.bundle = bundle;\n\n\tself.supportedFeatures = supportedFeatures;\n\n\tself.primaryClass = primaryClass;\n\n\treturn YES;\n}\n\n- (void)unloadBundle\n{\n\tif (self.primaryClass == nil) {\n\t\treturn;\n\t}\n\n\tif ([self.primaryClass respondsToSelector:@selector(pluginWillBeUnloadedFromMemory)]) {\n\t\t[self.primaryClass pluginWillBeUnloadedFromMemory];\n\t}\n\n\tself.primaryClass = nil;\n\n\tself.bundle = nil;\n}\n\n- (BOOL)supportsFeature:(THOPluginItemSupportedFeature)feature\n{\n\treturn ((self->_supportedFeatures & feature) == feature);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Plugin Architecture/THOPluginItemLogging.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *   Copyright (c) 2024 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BuildConfig.h\"\n#import \"THOPluginManager.h\"\n\nos_log_t _THOPluginLoggingSubsystemForBundle(NSBundle *bundle)\n{\n\t__block NSCache<NSString *, os_log_t> *subsystems = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsubsystems = [NSCache new];\n\t});\n\n\t@synchronized (subsystems) {\n\t\tNSString *identifier = bundle.bundleIdentifier;\n\t\t\n\t\tos_log_t subsystem = [subsystems objectForKey:identifier];\n\t\t\n\t\tif (subsystem == nil) {\n\t\t\tNSString *category = [NSString stringWithFormat:@\"Extension['%@']\", bundle.displayName];\n\t\t\t\n\t\t\t/* There was some debate whether to make the bundle identifier\n\t\t\t the identifier of the logging system instead of having the\n\t\t\t name in the category. Chose not to do that because seeing as\n\t\t\t the plugins are loaded as part of Textual and are not running\n\t\t\t in a separate process, it just makes more sense to filter. */\n\t\t\tsubsystem = os_log_create(TXBundleBuildProductIdentifierCString, category.UTF8String);\n\t\t\t\n\t\t\t[subsystems setObject:subsystem forKey:identifier];\n\t\t}\n\t\t\n\t\treturn subsystem;\n\t}\n}\n\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/Plugin Architecture/THOPluginManager.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXGlobalModels.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCResourceManager.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"THOPluginItemPrivate.h\"\n#import \"THOPluginProtocol.h\"\n#import \"THOPluginManagerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _extrasInstallerExtensionUpdateCheckInterval\t\t\t345600\n\nNSString * const THOPluginManagerFinishedLoadingPluginsNotification = @\"THOPluginManagerFinishedLoadingPluginsNotification\";\n\n@interface THOPluginManager ()\n@property (nonatomic, assign, readwrite) BOOL pluginsLoaded;\n@property (nonatomic, copy, readwrite, nullable) NSArray<THOPluginItem *> *loadedPlugins;\n@property (nonatomic, copy, nullable) NSArray<NSBundle *> *obsoleteBundles;\n@property (nonatomic, assign) THOPluginItemSupportedFeature supportedFeatures;\n@end\n\n@implementation THOPluginManager\n\n#pragma mark -\n#pragma mark Retain & Release\n\n- (void)loadPlugins\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tXRPerformBlockAsynchronouslyOnQueue([THOPluginDispatcher dispatchQueue], ^{\n\t\t\t[self _loadPlugins];\n\t\t});\n\t});\n}\n\n- (void)unloadPlugins\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tXRPerformBlockAsynchronouslyOnQueue([THOPluginDispatcher dispatchQueue], ^{\n\t\t\t[self _unloadPlugins];\n\t\t});\n\t});\n}\n\n- (void)_loadPlugins\n{\n\tNSArray *forbiddenPlugins = self.listOfForbiddenBundles;\n\n\tNSMutableArray<THOPluginItem *> *loadedPlugins = [NSMutableArray array];\n\tNSMutableArray<NSString *> *bundlesToLoad = [NSMutableArray array];\n\tNSMutableArray<NSString *> *loadedBundles = [NSMutableArray array];\n\tNSMutableArray<NSBundle *> *obsoleteBundles = [NSMutableArray array];\n\n\tNSArray *pathsToLoad =\n\t[RZFileManager() buildPathArray:\n\t\t[TPCPathInfo customExtensions],\n\t\t[TPCPathInfo bundledExtensions],\n\t\tnil];\n\n\tfor (NSString *path in pathsToLoad) {\n\t\tNSArray *pathFiles = [RZFileManager() contentsOfDirectoryAtPath:path error:NULL];\n\n\t\tif (pathFiles == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (NSString *file in pathFiles) {\n\t\t\tif ([file hasSuffix:TPCResourceManagerBundleDocumentTypeExtension] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tNSString *filePath = [path stringByAppendingPathComponent:file];\n\n\t\t\t[bundlesToLoad addObject:filePath];\n\t\t}\n\t}\n\n\tfor (NSString *bundlePath in bundlesToLoad) {\n\t\tNSBundle *bundle = [NSBundle bundleWithPath:bundlePath];\n\n\t\tif (bundle == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *bundleIdentifier = bundle.bundleIdentifier;\n\n\t\tif (bundleIdentifier == nil || [loadedBundles containsObject:bundleIdentifier]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* The list of forbidden bundles logic was added because a plugin previously\n\t\t bundled separately was not bundled with the app. This is a simple check to\n\t\t prevent the old plugin from loading and conflicting with built-in plugin.\n\t\t This is not designed as a security measure. */\n\t\tif ([forbiddenPlugins containsObject:bundleIdentifier]) {\n\t\t\tLogToConsoleFault(\"Forbidden loading of plugin '%{public}@'\", bundleIdentifier);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Begin version comparison */\n\t\tNSDictionary *infoDictionary = bundle.infoDictionary;\n\n\t\tNSString *comparisonVersion = infoDictionary[@\"MinimumTextualVersion\"];\n\n\t\tif (comparisonVersion == nil) {\n\t\t\t[obsoleteBundles addObject:bundle];\n\n\t\t\tNSLog(@\" ---------------------------- ERROR ---------------------------- \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"  Textual has failed to load the bundle at the following path    \");\n\t\t\tNSLog(@\"  which did not specify a minimum version:                       \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"     Bundle Path: %@\", bundle.bundlePath);\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"  Please add a key-value pair in the bundle's Info.plist file    \");\n\t\t\tNSLog(@\"  with the key name as \\\"MinimumTextualVersion\\\"                 \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"  For example, to support this version and later:                \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"     <key>MinimumTextualVersion</key>                            \");\n\t\t\tNSLog(@\"     <string>%@</string>\", THOPluginProtocolCompatibilityMinimumVersion);\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\" --------------------------------------------------------------- \");\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSComparisonResult comparisonResult =\n\t\t[comparisonVersion compare:THOPluginProtocolCompatibilityMinimumVersion options:NSNumericSearch];\n\n\t\tif (comparisonResult == NSOrderedAscending) {\n\t\t\t[obsoleteBundles addObject:bundle];\n\n\t\t\tNSLog(@\" ---------------------------- ERROR ---------------------------- \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"  Textual has failed to load the bundle at the following path    \");\n\t\t\tNSLog(@\"  because the specified minimum version is out of range:         \");\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"     Bundle Path: %@\", bundle.bundlePath);\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\"     Minimum version specified by bundle: %@\", comparisonVersion);\n\t\t\tNSLog(@\"     Version used by Textual for comparison: %@\", THOPluginProtocolCompatibilityMinimumVersion);\n\t\t\tNSLog(@\"                                                                 \");\n\t\t\tNSLog(@\" --------------------------------------------------------------- \");\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Load bundle as a plugin */\n\t\tTHOPluginItem *plugin = [THOPluginItem new];\n\n\t\tBOOL pluginLoaded = [plugin loadBundle:bundle];\n\n\t\tif (pluginLoaded == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[loadedPlugins addObject:plugin];\n\n\t\t[loadedBundles addObject:bundleIdentifier];\n\n\t\t[self updateSupportedFeaturesPropertyWithPlugin:plugin];\n\t}\n\n\tself.loadedPlugins = loadedPlugins;\n\n\tself.obsoleteBundles = obsoleteBundles;\n\n\tself.pluginsLoaded = YES;\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self checkForObsoleteBundlesOrUpdatesAvailable];\n\n\t\t[RZNotificationCenter() postNotificationName:THOPluginManagerFinishedLoadingPluginsNotification object:self];\n\t});\n}\n\n- (void)_unloadPlugins\n{\n\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\t[plugin unloadBundle];\n\t}\n\n\tself.loadedPlugins = nil;\n}\n\n#pragma mark -\n#pragma mark AppleScript Support\n\n- (NSArray<NSString *> *)supportedAppleScriptCommands\n{\n\treturn [self supportedAppleScriptCommands:NO];\n}\n\n- (NSDictionary<NSString *, NSString *> *)supportedAppleScriptCommandsAndPaths\n{\n\treturn [self supportedAppleScriptCommands:YES];\n}\n\n- (id)supportedAppleScriptCommands:(BOOL)returnPathInfo\n{\n\tNSArray *forbiddenCommands = self.listOfForbiddenCommandNames;\n\n\tNSArray *scriptPaths =\n\t[RZFileManager() buildPathArray:\n\t\t[TPCPathInfo customScripts],\n\t\t[TPCPathInfo bundledScripts],\n\t\tnil];\n\n\tid returnValue = nil;\n\n\tif (returnPathInfo) {\n\t\treturnValue = [NSMutableDictionary dictionary];\n\t} else {\n\t\treturnValue = [NSMutableArray array];\n\t}\n\n\tfor (NSString *path in scriptPaths) {\n\t\tNSArray *pathFiles = [RZFileManager() contentsOfDirectoryAtPath:path error:NULL];\n\n\t\tfor (NSString *file in pathFiles) {\n\t\t\tNSString *filePath = [path stringByAppendingPathComponent:file];\n\n\t\t\tNSString *fileExtension = file.pathExtension;\n\n\t\t\tNSString *fileWithoutExtension = file.stringByDeletingPathExtension;\n\n\t\t\tNSString *command = fileWithoutExtension.lowercaseString;\n\n\t\t\tBOOL executable = [RZFileManager() isExecutableFileAtPath:filePath];\n\n\t\t\tif (executable == NO && [fileExtension isEqualToString:TPCResourceManagerScriptDocumentTypeExtensionWithoutPeriod] == NO) {\n\t\t\t\tLogToConsoleInfo(\"WARNING: File “%{public}@“ found in unsupervised script folder but it isn't AppleScript or an executable. It will be ignored.\", file);\n\n\t\t\t\tcontinue;\n\t\t\t} else if ([forbiddenCommands containsObject:command]) {\n\t\t\t\tLogToConsoleInfo(\"WARNING: The command “%{public}@“ exists as a script file, but it is being ignored because the command name is forbidden.\", fileWithoutExtension);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (returnPathInfo) {\n\t\t\t\t[returnValue setObjectWithoutOverride:filePath forKey:command];\n\t\t\t} else {\n\t\t\t\t[returnValue addObjectWithoutDuplication:command];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn returnValue;\n}\n\n- (NSArray<NSString *> *)listOfForbiddenCommandNames\n{\n\t/* List of commands that cannot be used as the name of a script \n\t because they would conflict with the commands defined by one or\n\t more standard (RFC) */\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"THOPluginManager List of Forbidden Commands\"];\n}\n\n- (NSArray<NSString *> *)listOfForbiddenBundles\n{\n\t/* List of bundle identifiers that are not allowed to load. */\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"THOPluginManager List of Forbidden Extensions\"];\n}\n\n#pragma mark -\n#pragma mark Extras Installer\n\n- (void)checkForObsoleteBundlesOrUpdatesAvailable\n{\n\t/* This method will perform three actions:\n\t 1. It will notify user if they have any 3rd-party obsolete addons.\n\t\tThis will prompt them to contact the developer.\n\t 2. It will notify user if they have any obsolete extras installer\n\t\taddons that cannot be loaded. This will prompt to open installer.\n\t 3. It will notify the user if they have any extras installer addons\n\t\tthat have an update available.\n\n\t #3 allows the user to suppress the prompt until a later time.\n\t #2 and #1 are aggressive. The prompt will show each launch until the\n\t addon is updated or deleted.\n\n\t It is possible that multiple prompts will appear on the screen at\n\t once. This will be considered an acceptable behavior for now.\n\t Just make sure non-blocking alerts are used for this purpose. */\n\n\t[self checkForObsoleteBundles];\n\n\t[self extrasInstallerCheckForUpdates];\n}\n\n- (void)checkForObsoleteBundles\n{\n\tNSArray *obsoleteBundles = self.obsoleteBundles;\n\n\tif (obsoleteBundles.count == 0) {\n\t\treturn;\n\t}\n\n\tNSMutableArray<NSBundle *> *obsoleteExtras = [NSMutableArray array];\n\tNSMutableArray<NSBundle *> *obsoleteThirdParty = [NSMutableArray array];\n\n\tNSArray *extrasBundleIdentifiers = self.extrasInstallerBundleIdentifiers;\n\n\tfor (NSBundle *bundle in self.obsoleteBundles) {\n\t\tNSString *bundleIdentifier = bundle.bundleIdentifier;\n\n\t\tif ([extrasBundleIdentifiers containsObject:bundleIdentifier]) {\n\t\t\t[obsoleteExtras addObject:bundle];\n\t\t} else {\n\t\t\t[obsoleteThirdParty addObject:bundle];\n\t\t}\n\t}\n\n\tif (obsoleteExtras.count > 0) {\n\t\t[self _extrasInstallerInformUserAboutUpdateForBundles:[obsoleteExtras copy] updateOptional:NO];\n\t}\n\n\tif (obsoleteThirdParty.count == 0) {\n\t\treturn;\n\t}\n\n\tNSArray *thirdPartyBundles = [obsoleteThirdParty copy];\n\n\tNSString *bundlesName = [NSBundle formattedDisplayNamesForBundles:thirdPartyBundles];\n\n\tTVCAlert *alert =\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[45a-df]\", THOPluginProtocolCompatibilityMinimumVersion)\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[af6-45]\", bundlesName)\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[324-5d]\")\n\t\t\t   alternateButton:nil\n\t\t\t\t   otherButton:TXTLS(@\"Prompts[0ik-o9]\")];\n\n\t[alert setButtonClickedBlock:^BOOL(TVCAlert *sender, TVCAlertResponseButton buttonClicked) {\n\t\t[NSBundle openInstallationLocationsForBundles:thirdPartyBundles];\n\n\t\treturn NO;\n\t} forButton:TVCAlertResponseButtonThird];\n}\n\n- (void)extrasInstallerCheckForUpdates\n{\n\t/* Do not check for updates too often */\n#define _defaultsKey \t@\"THOPluginManager -> Extras Installer Last Check for Update Payload\"\n\n\tNSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];\n\n\tNSString *applicationVersion = [TPCApplicationInfo applicationVersion];\n\n\tNSDictionary<NSString *, id> *lastUpdatePayload = [RZUserDefaults() dictionaryForKey:_defaultsKey];\n\n\tif (lastUpdatePayload) {\n\t\tNSTimeInterval lastCheckTime = [lastUpdatePayload doubleForKey:@\"lastCheck\"];\n\n\t\tNSString *lastVersion = [lastUpdatePayload stringForKey:@\"lastVersion\"];\n\n\t\tif ((currentTime - lastCheckTime) < _extrasInstallerExtensionUpdateCheckInterval &&\n\t\t\t[lastVersion isEqualToString:applicationVersion])\n\t\t{\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Record the last time updates were checked for */\n\t[RZUserDefaults() setObject:@{\n\t\t@\"lastCheck\" : @(currentTime),\n\t\t@\"lastVersion\" : applicationVersion\n\t} forKey:_defaultsKey];\n\n\t/* Check for updates */\n\t[self _extrasInstallerCheckForUpdates];\n\n#undef _defaultsKey\n}\n\n- (void)_extrasInstallerCheckForUpdates\n{\n\t/* Perform update check */\n\tNSDictionary *latestVersions = self.extrasInstallerLatestBundleVersions;\n\n\tNSMutableArray<NSBundle *> *outdatedBundles = [NSMutableArray array];\n\n\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\tNSBundle *bundle = plugin.bundle;\n\n\t\tNSString *bundleIdentifier = bundle.bundleIdentifier;\n\n\t\tNSString *latestVersion = latestVersions[bundleIdentifier];\n\n\t\tif (latestVersion == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSDictionary *infoDictionary = bundle.infoDictionary;\n\n\t\tNSString *currentVersion = infoDictionary[@\"CFBundleVersion\"];\n\n\t\tNSComparisonResult comparisonResult = [currentVersion compare:latestVersion options:NSNumericSearch];\n\n\t\tif (comparisonResult == NSOrderedAscending) {\n\t\t\t[outdatedBundles addObject:bundle];\n\t\t}\n\t}\n\n\tif (outdatedBundles.count == 0) {\n\t\treturn;\n\t}\n\n\t[self _extrasInstallerInformUserAboutUpdateForBundles:[outdatedBundles copy] updateOptional:YES];\n}\n\n- (void)_extrasInstallerInformUserAboutUpdateForBundles:(NSArray<NSBundle *> *)bundles updateOptional:(BOOL)updateOptional\n{\n\tNSParameterAssert(bundles != nil);\n\n\t/* Append the current version to the suppression key so that updates \n\t aren't refused forever. Only until the next version of Textual is out. */\n\tNSString *suppressionKey = nil;\n\n\tif (updateOptional) {\n\t\tsuppressionKey =\n\t\t[@\"plugin_manager_extension_update_dialog_\"\n\t  stringByAppendingString:[TPCApplicationInfo applicationVersionShort]];\n\t}\n\n\tNSString *bundlesName = [NSBundle formattedDisplayNamesForBundles:bundles];\n\n\tNSString *promptTitle = ((updateOptional) ? @\"Prompts[9mb-o5]\" : @\"Prompts[ins-op]\");\n\tNSString *promptMessage = ((updateOptional) ? @\"Prompts[x4w-is]\" : @\"Prompts[34o-pk]\");\n\tNSString *promptDefaultButton = ((updateOptional) ? @\"Prompts[ece-dd]\" : @\"Prompts[hd0-bf]\");\n\tNSString *promptAlternateButton = ((updateOptional) ? @\"Prompts[ioq-nf]\" : @\"Prompts[467-5l]\");\n\tNSString *promptOtherButton = ((updateOptional) ? nil : TXTLS(@\"Prompts[h78-9e]\"));\n\n\tTVCAlert *alert =\n\t[TDCAlert alertWithMessage:TXTLS(promptMessage)\n\t\t\t\t\t\t title:TXTLS(promptTitle, bundlesName)\n\t\t\t\t defaultButton:TXTLS(promptDefaultButton)\n\t\t\t   alternateButton:TXTLS(promptAlternateButton)\n\t\t\t\t   otherButton:promptOtherButton\n\t\t\t\tsuppressionKey:suppressionKey\n\t\t\t   suppressionText:nil\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id  _Nullable underlyingAlert) {\n\t\t\t\t   if (buttonClicked == TDCAlertResponseAlternate) {\n\t\t\t\t\t   [self extrasInstallerLaunchInstaller];\n\t\t\t\t   }\n\t\t\t   }];\n\n\t[alert setButtonClickedBlock:^BOOL(TVCAlert *sender, TVCAlertResponseButton buttonClicked) {\n\t\t[NSBundle openInstallationLocationsForBundles:bundles];\n\n\t\treturn NO;\n\t} forButton:TVCAlertResponseButtonThird];\n}\n\n- (NSArray<NSString *> *)extrasInstallerBundleIdentifiers\n{\n\treturn self.extrasInstallerLatestBundleVersions.allKeys;\n}\n\n- (NSDictionary<NSString *, NSString *> *)extrasInstallerLatestBundleVersions\n{\n\t/* List of extra bundles and their latest version number. */\n\treturn [TPCResourceManager dictionaryFromResources:@\"StaticStore\" key:@\"THOPluginManager Extras Installer Latest Extension Versions\"];\n}\n\n- (NSArray<NSString *> *)extrasInstallerReservedCommands\n{\n\t/* List of scripts that are available as downloadable\n\t content from the www.codeux.com website. */\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"THOPluginManager List of Reserved Commands\"];\n}\n\n- (void)findHandlerForOutgoingCommand:(NSString *)command\n\t\t\t\t\t\t\t\t path:(NSString * _Nullable *)path\n\t\t\t\t\t\t   isReserved:(BOOL *)isReserved\n\t\t\t\t\t\t\t isScript:(BOOL *)isScript\n\t\t\t\t\t\t  isExtension:(BOOL *)isExtension\n{\n\tNSParameterAssert(command != nil);\n\n\t/* Reset context pointers */\n\tif ( path) {\n\t\t*path = nil;\n\t}\n\n\tif ( isReserved) {\n\t\t*isReserved = NO;\n\t}\n\n\tif ( isScript) {\n\t\t*isScript = NO;\n\t}\n\n\tif ( isExtension) {\n\t\t*isExtension = NO;\n\t}\n\n\t/* Find a script that matches this command */\n\tNSDictionary *scriptPaths = self.supportedAppleScriptCommandsAndPaths;\n\n\tfor (NSString *scriptCommand in scriptPaths) {\n\t\tif ([scriptCommand isEqualToString:command] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ( path) {\n\t\t\t*path = scriptPaths[scriptCommand];\n\t\t}\n\n\t\tif ( isScript) {\n\t\t\t*isScript = YES;\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Find an extension that matches this command */\n\tBOOL pluginFound = [self.supportedUserInputCommands containsObject:command];\n\n\tif (pluginFound) {\n\t\tif ( isExtension) {\n\t\t\t*isExtension = YES;\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Find a reserved command */\n\tNSArray *reservedCommands = self.extrasInstallerReservedCommands;\n\n\tif ( isReserved) {\n\t\t*isReserved = [reservedCommands containsObject:command];\n\t}\n}\n\n- (void)extrasInstallerAskUserIfTheyWantToInstallCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tBOOL download = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[bpb-vv]\")\n\t\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[o9p-4n]\", command)\n\t\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[6lr-02]\")\n\t\t\t\t\t\t\t\t\talternateButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t\t\t\t\t suppressionKey:@\"plugin_manager_reserved_command_dialog\"\n\t\t\t\t\t\t\t\t\tsuppressionText:nil];\n\n\tif (download) {\n\t\t[self extrasInstallerLaunchInstaller];\n\t}\n}\n\n- (void)extrasInstallerLaunchInstaller\n{\n\tNSURL *extrasURL = [RZMainBundle() URLForResource:@\"Textual-Extras\" withExtension:@\"pkg\"];\n\n\tNSURL *installerURL =\n\t[RZWorkspace() URLForApplicationWithBundleIdentifier:@\"com.apple.installer\"];\n\n\t[RZWorkspace() openURLs:@[extrasURL]\n\t   withApplicationAtURL:installerURL\n\t\t\t  configuration:[NSWorkspaceOpenConfiguration new]\n\t\t  completionHandler:nil];;\n}\n\n#pragma mark -\n#pragma mark Extension Information\n\n- (void)updateSupportedFeaturesPropertyWithPlugin:(THOPluginItem *)plugin\n{\n\tNSParameterAssert(plugin != nil);\n\n#define _ef(_feature)\t\tif ([plugin supportsFeature:(_feature)] && [self supportsFeature:(_feature)] == NO) {\t\t\\\n\t\t\t\t\t\t\t\tself->_supportedFeatures |= (_feature);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t}\n\n\t_ef(THOPluginItemSupportedFeatureDidReceiveCommandEvent)\n\t_ef(THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent)\n//\t_ef(THOPluginItemSupportedFeatureInlineMediaManipulation)\n\t_ef(THOPluginItemSupportedFeatureNewMessagePostedEvent)\n\t_ef(THOPluginItemSupportedFeatureOutputSuppressionRules)\n\t_ef(THOPluginItemSupportedFeaturePreferencePane)\n\t_ef(THOPluginItemSupportedFeatureServerInputDataInterception)\n\t_ef(THOPluginItemSupportedFeatureSubscribedServerInputCommands)\n\t_ef(THOPluginItemSupportedFeatureSubscribedUserInputCommands)\n\t_ef(THOPluginItemSupportedFeatureUserInputDataInterception)\n\t_ef(THOPluginItemSupportedFeatureWebViewJavaScriptPayloads)\n\t_ef(THOPluginItemSupportedFeatureWillRenderMessageEvent)\n\n#undef _ef\n}\n\n- (BOOL)supportsFeature:(THOPluginItemSupportedFeature)feature\n{\n\treturn ((self->_supportedFeatures & feature) == feature);\n}\n\n- (NSArray<THOPluginOutputSuppressionRule *> *)pluginOutputSuppressionRules\n{\n\tif (self.pluginsLoaded == NO) {\n\t\treturn @[];\n\t}\n\n\tstatic NSArray<THOPluginOutputSuppressionRule *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tNSMutableArray<THOPluginOutputSuppressionRule *> *allRules = [NSMutableArray array];\n\n\t\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureOutputSuppressionRules] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tNSArray *rules = plugin.outputSuppressionRules;\n\n\t\t\tif (rules) {\n\t\t\t\t[allRules addObjectsFromArray:rules];\n\t\t\t}\n\t\t}\n\n\t\tcachedValue = [allRules copy];\n\t});\n\n\treturn cachedValue;\n}\n\n- (NSArray<NSString *> *)supportedUserInputCommands\n{\n\tif (self.pluginsLoaded == NO) {\n\t\treturn @[];\n\t}\n\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tNSMutableArray<NSString *> *allCommands = [NSMutableArray array];\n\n\t\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureSubscribedUserInputCommands] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tNSArray *commands = plugin.supportedUserInputCommands;\n\n\t\t\tfor (NSString *command in commands) {\n\t\t\t\t[allCommands addObjectWithoutDuplication:command];\n\t\t\t}\n\t\t}\n\n\t\t[allCommands sortUsingComparator:NSDefaultComparator];\n\n\t\tcachedValue = [allCommands copy];\n\t});\n\n\treturn cachedValue;\n}\n\n- (NSArray<NSString *> *)supportedServerInputCommands\n{\n\tif (self.pluginsLoaded == NO) {\n\t\treturn @[];\n\t}\n\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tNSMutableArray<NSString *> *allCommands = [NSMutableArray array];\n\n\t\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeatureSubscribedServerInputCommands] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tNSArray *commands = plugin.supportedServerInputCommands;\n\n\t\t\tfor (NSString *command in commands) {\n\t\t\t\t[allCommands addObjectWithoutDuplication:command];\n\t\t\t}\n\t\t}\n\n\t\t[allCommands sortUsingComparator:NSDefaultComparator];\n\n\t\tcachedValue = [allCommands copy];\n\t});\n\n\treturn cachedValue;\n}\n\n- (NSArray<THOPluginItem *> *)pluginsWithPreferencePanes\n{\n\tif (self.pluginsLoaded == NO) {\n\t\treturn @[];\n\t}\n\n\tstatic NSArray<THOPluginItem *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tNSMutableArray<THOPluginItem *> *allExtensions = [NSMutableArray array];\n\n\t\tfor (THOPluginItem *plugin in self.loadedPlugins) {\n\t\t\tif ([plugin supportsFeature:THOPluginItemSupportedFeaturePreferencePane] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[allExtensions addObject:plugin];\n\t\t}\n\n\t\t[allExtensions sortUsingComparator:^NSComparisonResult(THOPluginItem *object1, THOPluginItem *object2) {\n\t\t\treturn [object1.pluginPreferencesPaneMenuItemTitle compare:\n\t\t\t\t\tobject2.pluginPreferencesPaneMenuItemTitle];\n\t\t}];\n\n\t\tcachedValue = [allExtensions copy];\n\t});\n\n\treturn cachedValue;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Helpers/THOUnicodeHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"THOUnicodeHelper.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSUInteger TABLE1[] = {\n\t9,\n\t0x00aa, 0x00aa,\n\t0x00b5, 0x00b5,\n\t0x00ba, 0x00ba,\n\t0x00c0, 0x00d6,\n\t0x00d8, 0x00f6,\n\t0x00f8, 0x02c1,\n\t0x02c6, 0x02d1,\n\t0x02e0, 0x02e4,\n\t0x02ee, 0x02ee,\n};\n\nstatic NSUInteger TABLE2[] = {\n\t134,\n\t0x037a, 0x037d,\n\t0x0386, 0x0386,\n\t0x0388, 0x038a,\n\t0x038c, 0x038c,\n\t0x038e, 0x03a1,\n\t0x03a3, 0x03ce,\n\t0x03d0, 0x03f5,\n\t0x03f7, 0x0481,\n\t0x048a, 0x0513,\n\t0x0531, 0x0556,\n\t0x0559, 0x0559,\n\t0x0561, 0x0587,\n\t0x05d0, 0x05ea,\n\t0x05f0, 0x05f2,\n\t0x0621, 0x063a,\n\t0x0640, 0x064a,\n\t0x066e, 0x066f,\n\t0x0671, 0x06d3,\n\t0x06d5, 0x06d5,\n\t0x06e5, 0x06e6,\n\t0x06ee, 0x06ef,\n\t0x06fa, 0x06fc,\n\t0x06ff, 0x06ff,\n\t0x0710, 0x0710,\n\t0x0712, 0x072f,\n\t0x074d, 0x076d,\n\t0x0780, 0x07a5,\n\t0x07b1, 0x07b1,\n\t0x07ca, 0x07ea,\n\t0x07f4, 0x07f5,\n\t0x07fa, 0x07fa,\n\t0x0904, 0x0939,\n\t0x093d, 0x093d,\n\t0x0950, 0x0950,\n\t0x0958, 0x0961,\n\t0x097b, 0x097f,\n\t0x0985, 0x098c,\n\t0x098f, 0x0990,\n\t0x0993, 0x09a8,\n\t0x09aa, 0x09b0,\n\t0x09b2, 0x09b2,\n\t0x09b6, 0x09b9,\n\t0x09bd, 0x09bd,\n\t0x09ce, 0x09ce,\n\t0x09dc, 0x09dd,\n\t0x09df, 0x09e1,\n\t0x09f0, 0x09f1,\n\t0x0a05, 0x0a0a,\n\t0x0a0f, 0x0a10,\n\t0x0a13, 0x0a28,\n\t0x0a2a, 0x0a30,\n\t0x0a32, 0x0a33,\n\t0x0a35, 0x0a36,\n\t0x0a38, 0x0a39,\n\t0x0a59, 0x0a5c,\n\t0x0a5e, 0x0a5e,\n\t0x0a72, 0x0a74,\n\t0x0a85, 0x0a8d,\n\t0x0a8f, 0x0a91,\n\t0x0a93, 0x0aa8,\n\t0x0aaa, 0x0ab0,\n\t0x0ab2, 0x0ab3,\n\t0x0ab5, 0x0ab9,\n\t0x0abd, 0x0abd,\n\t0x0ad0, 0x0ad0,\n\t0x0ae0, 0x0ae1,\n\t0x0b05, 0x0b0c,\n\t0x0b0f, 0x0b10,\n\t0x0b13, 0x0b28,\n\t0x0b2a, 0x0b30,\n\t0x0b32, 0x0b33,\n\t0x0b35, 0x0b39,\n\t0x0b3d, 0x0b3d,\n\t0x0b5c, 0x0b5d,\n\t0x0b5f, 0x0b61,\n\t0x0b71, 0x0b71,\n\t0x0b83, 0x0b83,\n\t0x0b85, 0x0b8a,\n\t0x0b8e, 0x0b90,\n\t0x0b92, 0x0b95,\n\t0x0b99, 0x0b9a,\n\t0x0b9c, 0x0b9c,\n\t0x0b9e, 0x0b9f,\n\t0x0ba3, 0x0ba4,\n\t0x0ba8, 0x0baa,\n\t0x0bae, 0x0bb9,\n\t0x0c05, 0x0c0c,\n\t0x0c0e, 0x0c10,\n\t0x0c12, 0x0c28,\n\t0x0c2a, 0x0c33,\n\t0x0c35, 0x0c39,\n\t0x0c60, 0x0c61,\n\t0x0c85, 0x0c8c,\n\t0x0c8e, 0x0c90,\n\t0x0c92, 0x0ca8,\n\t0x0caa, 0x0cb3,\n\t0x0cb5, 0x0cb9,\n\t0x0cbd, 0x0cbd,\n\t0x0cde, 0x0cde,\n\t0x0ce0, 0x0ce1,\n\t0x0d05, 0x0d0c,\n\t0x0d0e, 0x0d10,\n\t0x0d12, 0x0d28,\n\t0x0d2a, 0x0d39,\n\t0x0d60, 0x0d61,\n\t0x0d85, 0x0d96,\n\t0x0d9a, 0x0db1,\n\t0x0db3, 0x0dbb,\n\t0x0dbd, 0x0dbd,\n\t0x0dc0, 0x0dc6,\n\t0x0e01, 0x0e30,\n\t0x0e32, 0x0e33,\n\t0x0e40, 0x0e46,\n\t0x0e81, 0x0e82,\n\t0x0e84, 0x0e84,\n\t0x0e87, 0x0e88,\n\t0x0e8a, 0x0e8a,\n\t0x0e8d, 0x0e8d,\n\t0x0e94, 0x0e97,\n\t0x0e99, 0x0e9f,\n\t0x0ea1, 0x0ea3,\n\t0x0ea5, 0x0ea5,\n\t0x0ea7, 0x0ea7,\n\t0x0eaa, 0x0eab,\n\t0x0ead, 0x0eb0,\n\t0x0eb2, 0x0eb3,\n\t0x0ebd, 0x0ebd,\n\t0x0ec0, 0x0ec4,\n\t0x0ec6, 0x0ec6,\n\t0x0edc, 0x0edd,\n\t0x0f00, 0x0f00,\n\t0x0f40, 0x0f47,\n\t0x0f49, 0x0f6a,\n\t0x0f88, 0x0f8b,\n};\n\nstatic NSUInteger TABLE3[] = {\n\t70,\n\t0x1000, 0x1021,\n\t0x1023, 0x1027,\n\t0x1029, 0x102a,\n\t0x1050, 0x1055,\n\t0x10a0, 0x10c5,\n\t0x10d0, 0x10fa,\n\t0x10fc, 0x10fc,\n\t0x1200, 0x1248,\n\t0x124a, 0x124d,\n\t0x1250, 0x1256,\n\t0x1258, 0x1258,\n\t0x125a, 0x125d,\n\t0x1260, 0x1288,\n\t0x128a, 0x128d,\n\t0x1290, 0x12b0,\n\t0x12b2, 0x12b5,\n\t0x12b8, 0x12be,\n\t0x12c0, 0x12c0,\n\t0x12c2, 0x12c5,\n\t0x12c8, 0x12d6,\n\t0x12d8, 0x1310,\n\t0x1312, 0x1315,\n\t0x1318, 0x135a,\n\t0x1380, 0x138f,\n\t0x13a0, 0x13f4,\n\t0x1401, 0x166c,\n\t0x166f, 0x1676,\n\t0x1681, 0x169a,\n\t0x16a0, 0x16ea,\n\t0x1700, 0x170c,\n\t0x170e, 0x1711,\n\t0x1720, 0x1731,\n\t0x1740, 0x1751,\n\t0x1760, 0x176c,\n\t0x176e, 0x1770,\n\t0x1780, 0x17b3,\n\t0x17d7, 0x17d7,\n\t0x17dc, 0x17dc,\n\t0x1820, 0x1877,\n\t0x1880, 0x18a8,\n\t0x1900, 0x191c,\n\t0x1950, 0x196d,\n\t0x1970, 0x1974,\n\t0x1980, 0x19a9,\n\t0x19c1, 0x19c7,\n\t0x1a00, 0x1a16,\n\t0x1b05, 0x1b33,\n\t0x1b45, 0x1b4b,\n\t0x1d00, 0x1dbf,\n\t0x1e00, 0x1e9b,\n\t0x1ea0, 0x1ef9,\n\t0x1f00, 0x1f15,\n\t0x1f18, 0x1f1d,\n\t0x1f20, 0x1f45,\n\t0x1f48, 0x1f4d,\n\t0x1f50, 0x1f57,\n\t0x1f59, 0x1f59,\n\t0x1f5b, 0x1f5b,\n\t0x1f5d, 0x1f5d,\n\t0x1f5f, 0x1f7d,\n\t0x1f80, 0x1fb4,\n\t0x1fb6, 0x1fbc,\n\t0x1fbe, 0x1fbe,\n\t0x1fc2, 0x1fc4,\n\t0x1fc6, 0x1fcc,\n\t0x1fd0, 0x1fd3,\n\t0x1fd6, 0x1fdb,\n\t0x1fe0, 0x1fec,\n\t0x1ff2, 0x1ff4,\n\t0x1ff6, 0x1ffc,\n};\n\nstatic NSUInteger TABLE4[] = {\n\t34,\n\t0x2071, 0x2071,\n\t0x207f, 0x207f,\n\t0x2090, 0x2094,\n\t0x2102, 0x2102,\n\t0x2107, 0x2107,\n\t0x210a, 0x2113,\n\t0x2115, 0x2115,\n\t0x2119, 0x211d,\n\t0x2124, 0x2124,\n\t0x2126, 0x2126,\n\t0x2128, 0x2128,\n\t0x212a, 0x212d,\n\t0x212f, 0x2139,\n\t0x213c, 0x213f,\n\t0x2145, 0x2149,\n\t0x214e, 0x214e,\n\t0x2183, 0x2184,\n\t0x2c00, 0x2c2e,\n\t0x2c30, 0x2c5e,\n\t0x2c60, 0x2c6c,\n\t0x2c74, 0x2c77,\n\t0x2c80, 0x2ce4,\n\t0x2d00, 0x2d25,\n\t0x2d30, 0x2d65,\n\t0x2d6f, 0x2d6f,\n\t0x2d80, 0x2d96,\n\t0x2da0, 0x2da6,\n\t0x2da8, 0x2dae,\n\t0x2db0, 0x2db6,\n\t0x2db8, 0x2dbe,\n\t0x2dc0, 0x2dc6,\n\t0x2dc8, 0x2dce,\n\t0x2dd0, 0x2dd6,\n\t0x2dd8, 0x2dde,\n};\n\nstatic NSUInteger TABLE5[] = {\n\t7,\n\t0xa000, 0xa48c,\n\t0xa717, 0xa71a,\n\t0xa800, 0xa801,\n\t0xa803, 0xa805,\n\t0xa807, 0xa80a,\n\t0xa80c, 0xa822,\n\t0xa840, 0xa873,\n};\n\nstatic NSUInteger TABLE6[] = {\n\t18,\n\t0xfb00, 0xfb06,\n\t0xfb13, 0xfb17,\n\t0xfb1d, 0xfb1d,\n\t0xfb1f, 0xfb28,\n\t0xfb2a, 0xfb36,\n\t0xfb38, 0xfb3c,\n\t0xfb3e, 0xfb3e,\n\t0xfb40, 0xfb41,\n\t0xfb43, 0xfb44,\n\t0xfb46, 0xfbb1,\n\t0xfbd3, 0xfd3d,\n\t0xfd50, 0xfd8f,\n\t0xfd92, 0xfdc7,\n\t0xfdf0, 0xfdfb,\n\t0xfe70, 0xfe74,\n\t0xfe76, 0xfefc,\n\t0xff21, 0xff3a,\n\t0xff41, 0xff5a,\n};\n\nstatic NSUInteger OTHERS_TABLE[] = {\n\t56,\n\t0x10000, 0x1000b,\n\t0x1000d, 0x10026,\n\t0x10028, 0x1003a,\n\t0x1003c, 0x1003d,\n\t0x1003f, 0x1004d,\n\t0x10050, 0x1005d,\n\t0x10080, 0x100fa,\n\t0x10300, 0x1031e,\n\t0x10330, 0x10340,\n\t0x10342, 0x10349,\n\t0x10380, 0x1039d,\n\t0x103a0, 0x103c3,\n\t0x103c8, 0x103cf,\n\t0x10400, 0x1049d,\n\t0x10800, 0x10805,\n\t0x10808, 0x10808,\n\t0x1080a, 0x10835,\n\t0x10837, 0x10838,\n\t0x1083c, 0x1083c,\n\t0x1083f, 0x1083f,\n\t0x10900, 0x10915,\n\t0x10a00, 0x10a00,\n\t0x10a10, 0x10a13,\n\t0x10a15, 0x10a17,\n\t0x10a19, 0x10a33,\n\t0x12000, 0x1236e,\n\t0x1d400, 0x1d454,\n\t0x1d456, 0x1d49c,\n\t0x1d49e, 0x1d49f,\n\t0x1d4a2, 0x1d4a2,\n\t0x1d4a5, 0x1d4a6,\n\t0x1d4a9, 0x1d4ac,\n\t0x1d4ae, 0x1d4b9,\n\t0x1d4bb, 0x1d4bb,\n\t0x1d4bd, 0x1d4c3,\n\t0x1d4c5, 0x1d505,\n\t0x1d507, 0x1d50a,\n\t0x1d50d, 0x1d514,\n\t0x1d516, 0x1d51c,\n\t0x1d51e, 0x1d539,\n\t0x1d53b, 0x1d53e,\n\t0x1d540, 0x1d544,\n\t0x1d546, 0x1d546,\n\t0x1d54a, 0x1d550,\n\t0x1d552, 0x1d6a5,\n\t0x1d6a8, 0x1d6c0,\n\t0x1d6c2, 0x1d6da,\n\t0x1d6dc, 0x1d6fa,\n\t0x1d6fc, 0x1d714,\n\t0x1d716, 0x1d734,\n\t0x1d736, 0x1d74e,\n\t0x1d750, 0x1d76e,\n\t0x1d770, 0x1d788,\n\t0x1d78a, 0x1d7a8,\n\t0x1d7aa, 0x1d7c2,\n\t0x1d7c4, 0x1d7cb,\n};\n\n@implementation THOUnicodeHelper\n\n+ (BOOL)isPrivate:(UniChar)c\n{\n\treturn (0xe000 <= c && c <= 0xf8ff);\n}\n\n+ (BOOL)isIdeographic:(UniChar)c\n{\n\treturn ((0x2e80 <= c && c <= 0x9fff) ||\n\t\t\t(0xa000 <= c && c <= 0xa4cf) ||\n\t\t\t(0xf900 <= c && c <= 0xfaff) ||\n\t\t\t(0xfe30 <= c && c <= 0xfe4f) ||\n\t\t\t(0xff00 <= c && c <= 0xffef));\n}\n\n+ (BOOL)isIdeographicOrPrivate:(UniChar)c\n{\n\treturn ((0x2e80 <= c && c <= 0x9fff) ||\n\t\t\t(0xa000 <= c && c <= 0xa4cf) ||\n\t\t\t(0xe000 <= c && c <= 0xfaff) ||\n\t\t\t(0xfe30 <= c && c <= 0xfe4f) ||\n\t\t\t(0xff00 <= c && c <= 0xffef));\n}\n\n+ (BOOL)isAlphabeticalCodePoint:(NSInteger)c\n{\n\tNSUInteger *T = 0;\n\n\tif (c <= 0x7f) {\n\t\treturn ((0x41 <= c && c <= 0x5a) ||\n\t\t\t\t(0x61 <= c && c <= 0x7a));\n\t}\n\n\tif (0xaa <= c && c <= 0x2ee) {\n\t\tT = TABLE1;\n\t} else if (0x37a <= c && c <= 0xf8b) {\n\t\tT = TABLE2;\n\t} else if (0x1000 <= c && c <= 0x1ffc) {\n\t\tT = TABLE3;\n\t} else if (0x2071 <= c && c <= 0x2dde) {\n\t\tT = TABLE4;\n\t} else if (0xa000 <= c && c <= 0xa873) {\n\t\tT = TABLE5;\n\t} else if (0xfb00 <= c && c <= 0xff5a) {\n\t\tT = TABLE6;\n\t} else if (0x10000 <= c && c <= 0x1d7cb) {\n\t\tT = OTHERS_TABLE;\n\t}\n\n\tif (T == 0) {\n\t\treturn NO;\n\t}\n\n\tNSInteger count = *T;\n\n\tT++;\n\n\tNSInteger left = 0;\n\tNSInteger right = count;\n\n\twhile (left < right) {\n\t\tNSInteger center = ((left + right) / 2);\n\t\tNSInteger start = T[(center * 2)];\n\t\tNSInteger end = T[(center * 2 + 1)];\n\n\t\tif (start <= c && c <= end) {\n\t\t\treturn YES;\n\t\t}\n\n\t\tif (c < start) {\n\t\t\tright = center;\n\n\t\t\tcontinue;\n\t\t} else {\n\t\t\tleft = (center + 1);\n\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCAddressBook.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"IRCAddressBookInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCAddressBookEntry\n\n- (void)populateDefaultsPreflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tself->_defaults = @{\n\t\t@\"entryType\" : @(IRCAddressBookEntryTypeIgnore),\n\t\t@\"ignoreClientToClientProtocol\" : @(NO),\n\t\t@\"ignoreFileTransferRequests\"\t: @(NO),\n\t\t@\"ignoreGeneralEventMessages\"\t: @(NO),\n\t\t@\"ignoreInlineMedia\" : @(NO),\n\t\t@\"ignoreNoticeMessages\" : @(NO),\n\t\t@\"ignorePrivateMessageHighlights\" : @(NO),\n\t\t@\"ignorePrivateMessages\" : @(NO),\n\t\t@\"ignorePublicMessageHighlights\" : @(NO),\n\t\t@\"ignorePublicMessages\" : @(NO),\n\t\t@\"trackUserActivity\" : @(NO)\n\t};\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tSetVariableIfNil(self->_hostmask, @\"\")\n\tSetVariableIfNil(self->_hostmaskRegularExpression, @\"\")\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\t[self rebuildCache];\n}\n\n+ (instancetype)newIgnoreEntry\n{\n\treturn [self newIgnoreEntryForHostmask:nil];\n}\n\n+ (instancetype)newIgnoreEntryForHostmask:(nullable NSString *)hostmask\n{\n\tif (hostmask == nil) {\n\t\thostmask = @\"\";\n\t}\n\n\tNSDictionary *dic = @{\n\t\t@\"hostmask\" : hostmask,\n\t\t@\"entryType\" : @(IRCAddressBookEntryTypeIgnore),\n\t\t@\"ignoreClientToClientProtocol\" : @(YES),\n\t\t@\"ignoreFileTransferRequests\" : @(YES),\n\t\t@\"ignoreGeneralEventMessages\" : @(YES),\n\t\t@\"ignoreInlineMedia\" : @(YES),\n\t\t@\"ignoreNoticeMessages\" : @(YES),\n\t\t@\"ignorePrivateMessageHighlights\" : @(YES),\n\t\t@\"ignorePrivateMessages\" : @(YES),\n\t\t@\"ignorePublicMessageHighlights\" : @(YES),\n\t\t@\"ignorePublicMessages\" : @(YES)\n\t};\n\n\tIRCAddressBookEntry *object = [[self alloc] initWithDictionary:dic];\n\n\treturn object;\n}\n\n+ (instancetype)newUserTrackingEntry\n{\n\tNSDictionary *dic = @{\n\t\t@\"entryType\" : @(IRCAddressBookEntryTypeUserTracking),\n\t\t@\"trackUserActivity\" : @(YES)\n\t};\n\n\tIRCAddressBookEntry *object = [[self alloc] initWithDictionary:dic];\n\n\treturn object;\n}\n\n- (void)populateDictionaryValues:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tNSMutableDictionary<NSString *, id> *defaultsMutable = [self->_defaults mutableCopy];\n\n\t[defaultsMutable addEntriesFromDictionary:dic];\n\n\t[dic assignUnsignedIntegerTo:&self->_entryType forKey:@\"entryType\"];\n\n\tIRCAddressBookEntryType entryType = self->_entryType;\n\n\tif (entryType == IRCAddressBookEntryTypeIgnore ||\n\t\tentryType == IRCAddressBookEntryTypeMixed)\n\t{\n\t\t/* Load the newest set of keys */\n\t\t[dic assignBoolTo:&self->_ignoreClientToClientProtocol forKey:@\"ignoreClientToClientProtocol\"];\n\t\t[dic assignBoolTo:&self->_ignoreFileTransferRequests forKey:@\"ignoreFileTransferRequests\"];\n\t\t[dic assignBoolTo:&self->_ignoreGeneralEventMessages forKey:@\"ignoreGeneralEventMessages\"];\n\t\t[dic assignBoolTo:&self->_ignoreInlineMedia forKey:@\"ignoreInlineMedia\"];\n\t\t[dic assignBoolTo:&self->_ignoreNoticeMessages forKey:@\"ignoreNoticeMessages\"];\n\t\t[dic assignBoolTo:&self->_ignorePrivateMessageHighlights forKey:@\"ignorePrivateMessageHighlights\"];\n\t\t[dic assignBoolTo:&self->_ignorePrivateMessages forKey:@\"ignorePrivateMessages\"];\n\t\t[dic assignBoolTo:&self->_ignorePublicMessageHighlights forKey:@\"ignorePublicMessageHighlights\"];\n\t\t[dic assignBoolTo:&self->_ignorePublicMessages forKey:@\"ignorePublicMessages\"];\n\n\t\t/* Load legacy keys (if they exist) */\n\t\t[dic assignBoolTo:&self->_ignoreClientToClientProtocol forKey:@\"ignoreCTCP\"];\n\t\t[dic assignBoolTo:&self->_ignoreGeneralEventMessages forKey:@\"ignoreJPQE\"];\n\t\t[dic assignBoolTo:&self->_ignoreNoticeMessages forKey:@\"ignoreNotices\"];\n\t\t[dic assignBoolTo:&self->_ignorePrivateMessageHighlights forKey:@\"ignorePMHighlights\"];\n\t\t[dic assignBoolTo:&self->_ignorePrivateMessages forKey:@\"ignorePrivateMsg\"];\n\t\t[dic assignBoolTo:&self->_ignorePublicMessageHighlights forKey:@\"ignoreHighlights\"];\n\t\t[dic assignBoolTo:&self->_ignorePublicMessages forKey:@\"ignorePublicMsg\"];\n\t}\n\n\tif (entryType == IRCAddressBookEntryTypeUserTracking ||\n\t\tentryType == IRCAddressBookEntryTypeMixed)\n\t{\n\t\t/* Load the newest set of keys */\n\t\t[dic assignBoolTo:&self->_trackUserActivity forKey:@\"trackUserActivity\"];\n\n\t\t/* Load legacy keys (if they exist) */\n\t\t[dic assignBoolTo:&self->_trackUserActivity forKey:@\"notifyJoins\"];\n\t}\n\n\t[dic assignStringTo:&self->_hostmask forKey:@\"hostmask\"];\n\t[dic assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n}\n\n- (void)rebuildCache\n{\n\t[self rebuildHostmaskRegularExpression];\n\n\t[self rebuildTrackingNickname];\n}\n\n- (void)rebuildHostmaskRegularExpression\n{\n\tNSString *hostmask = self.hostmask;\n\n\tif (self.entryType == IRCAddressBookEntryTypeIgnore)\n\t{\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"\\\\\" withString:@\"\\\\\\\\\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"{\" withString:@\"\\\\{\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"}\" withString:@\"\\\\}\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\")\" withString:@\"\\\\)\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"(\" withString:@\"\\\\(\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"]\" withString:@\"\\\\]\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"[\" withString:@\"\\\\[\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"^\" withString:@\"\\\\^\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"|\" withString:@\"\\\\|\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"~\" withString:@\"\\\\~\"];\n\t\thostmask = [hostmask stringByReplacingOccurrencesOfString:@\"*\" withString:@\"(.*?)\"];\n\t}\n\telse if (self.entryType == IRCAddressBookEntryTypeUserTracking)\n\t{\n\t\thostmask = [NSString stringWithFormat:@\"^%@!(.*?)@(.*?)$\", hostmask];\n\t}\n\telse\n\t{\n\t\treturn;\n\t}\n\n\tself->_hostmaskRegularExpression = [hostmask copy];\n}\n\n- (void)rebuildTrackingNickname\n{\n\tif (self.entryType != IRCAddressBookEntryTypeUserTracking) {\n\t\treturn;\n\t}\n\n\tNSString *hostmask = self.hostmask;\n\n\thostmask = hostmask.nicknameFromHostmask;\n\n\tself->_trackingNickname = [hostmask copy];\n}\n\n- (BOOL)checkMatch:(NSString *)hostmask\n{\n\tNSParameterAssert(hostmask != nil);\n\n\treturn [XRRegularExpression string:hostmask isMatchedByRegex:self.hostmaskRegularExpression withoutCase:YES];\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t[dic maybeSetObject:self.hostmask forKey:@\"hostmask\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\tIRCAddressBookEntryType entryType = self.entryType;\n\n\tif (entryType == IRCAddressBookEntryTypeIgnore ||\n\t\tentryType == IRCAddressBookEntryTypeMixed)\n\t{\n\t\t[dic setBool:self.ignoreClientToClientProtocol forKey:@\"ignoreClientToClientProtocol\"];\n\t\t[dic setBool:self.ignoreFileTransferRequests forKey:@\"ignoreFileTransferRequests\"];\n\t\t[dic setBool:self.ignoreGeneralEventMessages forKey:@\"ignoreGeneralEventMessages\"];\n\t\t[dic setBool:self.ignoreInlineMedia forKey:@\"ignoreInlineMedia\"];\n\t\t[dic setBool:self.ignoreNoticeMessages forKey:@\"ignoreNoticeMessages\"];\n\t\t[dic setBool:self.ignorePrivateMessageHighlights forKey:@\"ignorePrivateMessageHighlights\"];\n\t\t[dic setBool:self.ignorePrivateMessages forKey:@\"ignorePrivateMessages\"];\n\t\t[dic setBool:self.ignorePublicMessageHighlights forKey:@\"ignorePublicMessageHighlights\"];\n\t\t[dic setBool:self.ignorePublicMessages forKey:@\"ignorePublicMessages\"];\n\t}\n\n\tif (entryType == IRCAddressBookEntryTypeUserTracking ||\n\t\tentryType == IRCAddressBookEntryTypeMixed)\n\t{\n\t\t[dic setBool:self.trackUserActivity forKey:@\"trackUserActivity\"];\n\t}\n\n\t[dic setUnsignedInteger:entryType forKey:@\"entryType\"];\n\n\tif (target == XRPortablePropertyDictTargetCopy ||\n\t\ttarget == XRPortablePropertyDictTargetMutableCopy)\n\t{\n\t\treturn [dic copy];\n\t}\n\n\treturn [dic dictionaryByRemovingDefaults:self->_defaults];\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCAddressBookEntry *config = [self allocForCopyAsMutable:mutableCopy];\n\n\tconfig->_defaults = self->_defaults;\n\n\tconfig->_hostmaskRegularExpression = self->_hostmaskRegularExpression;\n\tconfig->_trackingNickname = self->_trackingNickname;\n\n\tconfig->_parentEntries = self->_parentEntries;\n\n\tif (uniquing) {\n\t\tconfig->_uniqueIdentifier = [NSString stringWithUUID];\n\t}\n\n\treturn [config initWithDictionary:self.dictionaryValueForCopy];\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [IRCAddressBookEntryMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCAddressBookEntryMutable\n\n@dynamic entryType;\n@dynamic hostmask;\n@dynamic ignoreClientToClientProtocol;\n@dynamic ignoreFileTransferRequests;\n@dynamic ignoreGeneralEventMessages;\n@dynamic ignoreInlineMedia;\n@dynamic ignoreNoticeMessages;\n@dynamic ignorePrivateMessageHighlights;\n@dynamic ignorePrivateMessages;\n@dynamic ignorePublicMessageHighlights;\n@dynamic ignorePublicMessages;\n@dynamic trackUserActivity;\n@dynamic parentEntries;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [IRCAddressBookEntry self];\n}\n\n- (void)setEntryType:(IRCAddressBookEntryType)entryType\n{\n\tif (self->_entryType != entryType) {\n\t\tself->_entryType = entryType;\n\n\t\t[self rebuildCache];\n\t}\n}\n\n- (void)setHostmask:(NSString *)hostmask\n{\n\tNSParameterAssert(hostmask != nil);\n\n\tif (self->_hostmask != hostmask) {\n\t\tself->_hostmask = [hostmask copy];\n\n\t\t[self rebuildCache];\n\t}\n}\n\n- (void)setIgnoreClientToClientProtocol:(BOOL)ignoreClientToClientProtocol\n{\n\tif (self->_ignoreClientToClientProtocol != ignoreClientToClientProtocol) {\n\t\tself->_ignoreClientToClientProtocol = ignoreClientToClientProtocol;\n\t}\n}\n\n- (void)setIgnoreFileTransferRequests:(BOOL)ignoreFileTransferRequests\n{\n\tif (self->_ignoreFileTransferRequests != ignoreFileTransferRequests) {\n\t\tself->_ignoreFileTransferRequests = ignoreFileTransferRequests;\n\t}\n}\n\n- (void)setIgnoreGeneralEventMessages:(BOOL)ignoreGeneralEventMessages\n{\n\tif (self->_ignoreGeneralEventMessages != ignoreGeneralEventMessages) {\n\t\tself->_ignoreGeneralEventMessages = ignoreGeneralEventMessages;\n\t}\n}\n\n- (void)setIgnoreInlineMedia:(BOOL)ignoreInlineMedia\n{\n\tif (self->_ignoreInlineMedia != ignoreInlineMedia) {\n\t\tself->_ignoreInlineMedia = ignoreInlineMedia;\n\t}\n}\n\n- (void)setIgnoreNoticeMessages:(BOOL)ignoreNoticeMessages\n{\n\tif (self->_ignoreNoticeMessages != ignoreNoticeMessages) {\n\t\tself->_ignoreNoticeMessages = ignoreNoticeMessages;\n\t}\n}\n\n- (void)setIgnorePrivateMessageHighlights:(BOOL)ignorePrivateMessageHighlights\n{\n\tif (self->_ignorePrivateMessageHighlights != ignorePrivateMessageHighlights) {\n\t\tself->_ignorePrivateMessageHighlights = ignorePrivateMessageHighlights;\n\t}\n}\n\n- (void)setIgnorePrivateMessages:(BOOL)ignorePrivateMessages\n{\n\tif (self->_ignorePrivateMessages != ignorePrivateMessages) {\n\t\tself->_ignorePrivateMessages = ignorePrivateMessages;\n\t}\n}\n\n- (void)setIgnorePublicMessageHighlights:(BOOL)ignorePublicMessageHighlights\n{\n\tif (self->_ignorePublicMessageHighlights != ignorePublicMessageHighlights) {\n\t\tself->_ignorePublicMessageHighlights = ignorePublicMessageHighlights;\n\t}\n}\n\n- (void)setIgnorePublicMessages:(BOOL)ignorePublicMessages\n{\n\tif (self->_ignorePublicMessages != ignorePublicMessages) {\n\t\tself->_ignorePublicMessages = ignorePublicMessages;\n\t}\n}\n\n- (void)setTrackUserActivity:(BOOL)trackUserActivity\n{\n\tif (self->_trackUserActivity != trackUserActivity) {\n\t\tself->_trackUserActivity = trackUserActivity;\n\t}\n}\n\n- (void)setParentEntries:(nullable NSArray<IRCAddressBookEntry *> *)childrenEntries\n{\n\tif (self->_parentEntries != childrenEntries) {\n\t\tself->_parentEntries = [childrenEntries copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCAddressBookMatchCache.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClient.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCAddressBook.h\"\n#import \"IRCAddressBookMatchCachePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCAddressBookMatchCache ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, strong) NSCache<NSString *, id> *cachedMatchesInt;\n@end\n\n@implementation IRCAddressBookMatchCache\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tNSCache *cachedMatches = [NSCache new];\n\t\n\tcachedMatches.countLimit = 100;\n\n\tself.cachedMatchesInt = cachedMatches;\n}\n\n- (void)clearCachedMatches\n{\n\t[self.cachedMatchesInt removeAllObjects];\n}\n\n- (void)clearCachedMatchesForHostmask:(NSString *)hostmask\n{\n\tNSParameterAssert(hostmask != nil);\n\t\n\t[self.cachedMatchesInt removeObjectForKey:hostmask];\n}\n\n- (NSArray<IRCAddressBookEntry *> *)findIgnoresForHostmask:(NSString *)hostmask\n{\n\tIRCAddressBookEntry *match = [self findAddressBookEntryForHostmask:hostmask];\n\t\n\tif (match && match.entryType == IRCAddressBookEntryTypeIgnore) {\n\t\treturn @[match];\n\t}\n\n\tif (match && match.entryType == IRCAddressBookEntryTypeMixed) {\n\t\tNSArray *parentEntries = match.parentEntries;\n\t\t\n\t\treturn\n\t\t[parentEntries filteredArrayUsingPredicate:\n\t\t [NSPredicate predicateWithFormat:@\"entryType == %d\", IRCAddressBookEntryTypeIgnore]];\n\t}\n\t\n\treturn @[];\n}\n\n- (nullable IRCAddressBookEntry *)findAddressBookEntryForHostmask:(NSString *)hostmask\n{\n\tNSParameterAssert(hostmask != nil);\n\n\tIRCAddressBookEntry *cachedEntry = [self.cachedMatchesInt objectForKey:hostmask];\n\t\n\tif (cachedEntry) {\n\t\t/* We reset the cache when new items are added to the client\n\t\t which means we are perfectly fine keeping a cache of when\n\t\t there isn't result for a hostmask. Whatever is needed to\n\t\t gain a little bit more speed. */\n\t\tif ([cachedEntry isKindOfClass:[NSNull class]]) {\n\t\t\treturn nil;\n\t\t}\n\n\t\treturn cachedEntry;\n\t}\n\t\n\t/* A separate variable is used to store a single entry\n\t and multiple so that we don’t allocate an array when\n\t it is very infrequent for there to be multiple. */\n\tIRCAddressBookEntry *matchedEntry = nil;\n\n\tNSMutableArray <IRCAddressBookEntry *> *matchedEntries = nil;\n\n\tfor (IRCAddressBookEntry *entry in self.client.config.ignoreList) {\n\t\tif ([entry checkMatch:hostmask] == NO) {\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (matchedEntries) {\n\t\t\t[matchedEntries addObject:entry];\n\t\t} else if (matchedEntry) {\n\t\t\tmatchedEntries = [NSMutableArray array];\n\n\t\t\t[matchedEntries addObject:matchedEntry];\n\t\t\t\n\t\t\t[matchedEntries addObject:entry];\n\t\t\t\n\t\t\tmatchedEntry = nil;\n\t\t} else {\n\t\t\tmatchedEntry = entry;\n\t\t}\n\t}\n\n\t/* Combine multiple entries */\n\tif (matchedEntries) {\n\t\tIRCAddressBookEntryMutable *mixedEntry = [IRCAddressBookEntryMutable new];\n\t\t\n\t\tmixedEntry.entryType = IRCAddressBookEntryTypeMixed;\n\t\t\n\t\tmixedEntry.parentEntries = matchedEntries;\n\n\t\tfor (IRCAddressBookEntry *entry in matchedEntries) {\n\t\t\tmixedEntry.ignoreClientToClientProtocol = ((entry.ignoreClientToClientProtocol) ? YES : mixedEntry.ignoreClientToClientProtocol);\n\t\t\tmixedEntry.ignoreGeneralEventMessages = ((entry.ignoreGeneralEventMessages) ? YES : mixedEntry.ignoreGeneralEventMessages);\n\t\t\tmixedEntry.ignoreNoticeMessages = ((entry.ignoreNoticeMessages) ? YES : mixedEntry.ignoreNoticeMessages);\n\t\t\tmixedEntry.ignorePrivateMessageHighlights = ((entry.ignorePrivateMessageHighlights) ? YES : mixedEntry.ignorePrivateMessageHighlights);\n\t\t\tmixedEntry.ignorePrivateMessages = ((entry.ignorePrivateMessages) ? YES : mixedEntry.ignorePrivateMessages);\n\t\t\tmixedEntry.ignorePublicMessageHighlights = ((entry.ignorePublicMessageHighlights) ? YES : mixedEntry.ignorePublicMessageHighlights);\n\t\t\tmixedEntry.ignorePublicMessages = ((entry.ignorePublicMessages) ? YES : mixedEntry.ignorePublicMessages);\n\t\t\tmixedEntry.ignoreFileTransferRequests = ((entry.ignoreFileTransferRequests) ? YES : mixedEntry.ignoreFileTransferRequests);\n\t\t\tmixedEntry.ignoreInlineMedia = ((entry.ignoreInlineMedia) ? YES : mixedEntry.ignoreInlineMedia);\n\t\t\tmixedEntry.trackUserActivity = ((entry.trackUserActivity) ? YES : mixedEntry.trackUserActivity);\n\t\t}\n\t\t\n\t\tmatchedEntry = [mixedEntry copy];\n\t}\n\n\t/* Cache entry */\n\tif (matchedEntry) {\n\t\t[self.cachedMatchesInt setObject:matchedEntry forKey:hostmask];\n\t} else {\n\t\t[self.cachedMatchesInt setObject:[NSNull null] forKey:hostmask];\n\t}\n\t\n\treturn matchedEntry;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCAddressBookUserTracking.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClient.h\"\n#import \"IRCAddressBookUserTracking.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const IRCAddressBookUserTrackingStatusChangedNotification = @\"IRCAddressBookUserTrackingStatusChangedNotification\";\n\nNSString * const IRCAddressBookUserTrackingAddedTrackedUserNotification = @\"IRCAddressBookUserTrackingAddedTrackedUserNotification\";\n\nNSString * const IRCAddressBookUserTrackingRemovedTrackedUserNotification = @\"IRCAddressBookUserTrackingRemovedTrackedUserNotification\";\nNSString * const IRCAddressBookUserTrackingRemovedAllTrackedUsersNotification = @\"IRCAddressBookUserTrackingRemovedAllTrackedUsersNotification\";\n\n@interface IRCAddressBookUserTrackingContainer ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *trackedUsersInt;\n@end\n\n@implementation IRCAddressBookUserTrackingContainer\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.trackedUsersInt = [NSMutableDictionary dictionary];\n}\n\n- (void)addTrackedUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tNSString *trackingNickname = [self.trackedUsersInt keyIgnoringCase:nickname];\n\n\t\tif (trackingNickname != nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self _addTrackedUser:nickname];\n\t}\n}\n\n- (void)_addTrackedUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tself.trackedUsersInt[nickname] = @(NO);\n\n\t\t[RZNotificationCenter() postNotificationName:IRCAddressBookUserTrackingAddedTrackedUserNotification\n\t\t\t\t\t\t\t\t\t\t\t  object:self\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{@\"nickname\" : nickname}];\n\t}\n}\n\n- (void)removeTrackedUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tNSString *trackingNickname = [self.trackedUsersInt keyIgnoringCase:nickname];\n\n\t\tif (trackingNickname == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self _removeTrackedUser:trackingNickname];\n\t}\n}\n\n- (void)_removeTrackedUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\t[self.trackedUsersInt removeObjectForKey:nickname];\n\n\t\t[RZNotificationCenter() postNotificationName:IRCAddressBookUserTrackingRemovedTrackedUserNotification\n\t\t\t\t\t\t\t\t\t\t\t  object:self\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{@\"nickname\" : nickname}];\n\t}\n}\n\n- (void)clearTrackedUsers\n{\n\t@synchronized (self.trackedUsersInt) {\n\t\t[self.trackedUsersInt removeAllObjects];\n\n\t\t[RZNotificationCenter() postNotificationName:IRCAddressBookUserTrackingRemovedAllTrackedUsersNotification\n\t\t\t\t\t\t\t\t\t\t\t  object:self];\n\t}\n}\n\n- (IRCAddressBookUserTrackingStatus)statusOfUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tNSString *trackingNickname = [self.trackedUsersInt keyIgnoringCase:nickname];\n\n\t\tif (trackingNickname == nil) {\n\t\t\treturn IRCAddressBookUserTrackingStatusUnknown;\n\t\t}\n\n\t\treturn [self _statusOfUser:nickname];\n\t}\n}\n\n- (IRCAddressBookUserTrackingStatus)_statusOfUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tBOOL ison = self.trackedUsersInt[nickname].boolValue;\n\n\t\tif (ison) {\n\t\t\treturn IRCAddressBookUserTrackingStatusAvailable;\n\t\t} else {\n\t\t\treturn IRCAddressBookUserTrackingStatusNotAvailable;\n\t\t}\n\t}\n}\n\n- (IRCAddressBookUserTrackingStatus)statusOfEntry:(IRCAddressBookEntry *)addressBookEntry\n{\n\tNSParameterAssert(addressBookEntry != nil);\n\n\tNSString *trackingNickname = addressBookEntry.trackingNickname;\n\n\tif (trackingNickname == nil) {\n\t\treturn IRCAddressBookUserTrackingStatusUnknown;\n\t}\n\n\treturn [self statusOfUser:trackingNickname];\n}\n\n- (NSDictionary<NSString *, NSNumber *> *)trackedUsers\n{\n\t@synchronized (self.trackedUsersInt) {\n\t\treturn [self.trackedUsersInt copy];\n\t}\n}\n\n- (void)statusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (newStatus == IRCAddressBookUserTrackingStatusUnknown) {\n\t\treturn;\n\t}\n\n\t@synchronized (self.trackedUsersInt) {\n\t\tNSString *trackingNickname = [self.trackedUsersInt keyIgnoringCase:nickname];\n\n\t\tif (newStatus == IRCAddressBookUserTrackingStatusAvailable ||\n\t\t\tnewStatus == IRCAddressBookUserTrackingStatusSignedOn)\n\t\t{\n\t\t\tif (trackingNickname == nil) {\n\t\t\t\ttrackingNickname = nickname;\n\t\t\t}\n\n\t\t\tself.trackedUsersInt[trackingNickname] = @(YES);\n\t\t}\n\t\telse if (newStatus == IRCAddressBookUserTrackingStatusNotAvailable ||\n\t\t\t\t newStatus == IRCAddressBookUserTrackingStatusSignedOff)\n\t\t{\n\t\t\tif (trackingNickname == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tself.trackedUsersInt[trackingNickname] = @(NO);\n\t\t}\n\t\telse if (newStatus == IRCAddressBookUserTrackingStatusNotAway ||\n\t\t\t\t newStatus == IRCAddressBookUserTrackingStatusAway)\n\t\t{\n\t\t\tif (trackingNickname == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t[RZNotificationCenter() postNotificationName:IRCAddressBookUserTrackingStatusChangedNotification\n\t\t\t\t\t\t\t\t\t\t\t  object:self\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{@\"nickname\" : nickname,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   @\"status\" : @(newStatus)}];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCChannel.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#include <objc/message.h>\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TXWindowControllerPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMemberListAppearance.h\"\n#import \"TVCMemberListPrivate.h\"\n#import \"TVCMemberListCellPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TDCSharedProtocolDefinitionsPrivate.h\"\n#import \"TDCSheetBase.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOFileLoggerPrivate.h\"\n#import \"TLOInputHistoryPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelConfigPrivate.h\"\n#import \"IRCChannelModePrivate.h\"\n#import \"IRCChannelMemberListPrivate.h\"\n#import \"IRCChannelUserPrivate.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCTreeItemPrivate.h\"\n#import \"IRCUser.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const IRCChannelConfigurationWasUpdatedNotification = @\"IRCChannelConfigurationWasUpdatedNotification\";\n\n@interface IRCChannel ()\n@property (readonly) BOOL isSelectedChannel;\n@property (nonatomic, assign) BOOL statusChangedByAction;\n@property (nonatomic, copy, readwrite) IRCChannelConfig *config;\n@property (nonatomic, assign, readwrite) NSTimeInterval channelJoinTime;\n@property (nonatomic, strong, readwrite, nullable) IRCChannelMode *modeInfo;\n@property (nonatomic, strong, readwrite, nullable) IRCChannelMemberList *memberInfo;\n@property (nonatomic, strong, nullable) TLOFileLogger *logFile;\n@property (nonatomic, assign, readwrite) NSUInteger logFileSessionCount;\n@end\n\n@implementation IRCChannel\n\n@synthesize associatedClient = _associatedClient;\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfigDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tIRCChannelConfig *config = [[IRCChannelConfig alloc] initWithDictionary:dic];\n\n\treturn [self initWithConfig:config];\n}\n\n- (instancetype)initWithConfig:(IRCChannelConfig *)config\n{\n\tif ((self = [super init])) {\n\t\tself.config = config;\n\n\t\t[self.config writeSecretKeyToKeychain];\n\t}\n\n\treturn self;\n}\n\n- (void)updateConfig:(IRCChannelConfig *)config\n{\n\t[self updateConfig:config fireChangedNotification:YES updateStoredChannelList:YES];\n}\n\n- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification\n{\n\t[self updateConfig:config fireChangedNotification:fireChangedNotification updateStoredChannelList:YES];\n}\n\n- (void)updateConfig:(IRCChannelConfig *)config fireChangedNotification:(BOOL)fireChangedNotification updateStoredChannelList:(BOOL)updateStoredChannelList\n{\n\tNSParameterAssert(config != nil);\n\n\tIRCChannelConfig *currentConfig = self.config;\n\n\tif ([config isEqual:currentConfig]) {\n\t\treturn;\n\t}\n\n\tif (currentConfig.type != config.type ||\n\t\t[currentConfig.channelName isEqualToString:config.channelName] == NO ||\n\t\t[currentConfig.uniqueIdentifier isEqualToString:config.uniqueIdentifier] == NO)\n\t{\n\t\tLogToConsoleError(\"Tried to load configuration for incorrect channel\");\n\n\t\treturn;\n\t}\n\n\tself.config = config;\n\n\t[self.config writeSecretKeyToKeychain];\n\n\tif (updateStoredChannelList) {\n\t\t[self.associatedClient updateStoredChannelList];\n\t}\n\n\tif (fireChangedNotification) {\n\t\t[RZNotificationCenter() postNotificationName:IRCChannelConfigurationWasUpdatedNotification object:self];\n\t}\n}\n\n- (NSDictionary<NSString *, id> *)configurationDictionary\n{\n\treturn [self.config dictionaryValue];\n}\n\n- (id)copyWithZone:(nullable NSZone *)zone\n{\n\t/* Implement this method to allow channel to be \n\t used as a dictionary key. */\n\n\treturn self;\n}\n\n- (NSString *)description\n{\n\treturn [NSString stringWithFormat:@\"<IRCChannel [%@]: %@>\", self.associatedClient.description, self.name];\n}\n\n#pragma mark -\n#pragma mark Property Getter\n\n- (NSString *)uniqueIdentifier\n{\n\treturn self.config.uniqueIdentifier;\n}\n\n- (NSString *)name\n{\n\treturn self.config.channelName;\n}\n\n- (nullable NSString *)secretKey\n{\n\treturn self.config.secretKey;\n}\n\n- (BOOL)autoJoin\n{\n\treturn self.config.autoJoin;\n}\n\n- (BOOL)isChannel\n{\n\treturn (self.config.type == IRCChannelTypeChannel);\n}\n\n- (BOOL)isPrivateMessage\n{\n\treturn (self.config.type == IRCChannelTypePrivateMessage);\n}\n\n- (BOOL)isUtility\n{\n\treturn (self.config.type == IRCChannelTypeUtility);\n}\n\n- (BOOL)isPrivateMessageForZNCUser\n{\n\tif (self.isPrivateMessage == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCClient *client = self.associatedClient;\n\n\treturn [client nicknameIsZNCUser:self.name];\n}\n\n- (IRCChannelType)type\n{\n\treturn self.config.type;\n}\n\n- (NSString *)channelTypeString\n{\n\tswitch (self.config.type) {\n\t\tcase IRCChannelTypeChannel:\n\t\t{\n\t\t\treturn @\"channel\";\n\t\t}\n\t\tcase IRCChannelTypePrivateMessage:\n\t\t{\n\t\t\treturn @\"query\";\n\t\t}\n\t\tcase IRCChannelTypeUtility:\n\t\t{\n\t\t\treturn @\"utility\";\n\t\t}\n\t}\n}\n\n- (nullable NSURL *)logFilePath\n{\n\tNSString *writePath = [TLOFileLogger writePathForItem:self];\n\n\tif (writePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:writePath];\n}\n\n- (nullable TVCLogLine *)lastLine\n{\n\treturn self.viewController.lastLine;\n}\n\n#pragma mark -\n#pragma mark Property Setter\n\n- (void)setAutoJoin:(BOOL)autoJoin\n{\n\tif (self.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tif (self.autoJoin == autoJoin) {\n\t\treturn;\n\t}\n\n\tIRCChannelConfigMutable *mutableConfig = [self.config mutableCopy];\n\n\tmutableConfig.autoJoin = autoJoin;\n\n\tself.config = mutableConfig;\n}\n\n- (void)setName:(NSString *)name\n{\n\tNSParameterAssert(name != nil);\n\n\tif (self.isChannel) {\n\t\treturn;\n\t}\n\n\tif ([self.name isEqualToString:name]) {\n\t\treturn;\n\t}\n\n\tIRCChannelConfigMutable *mutableConfig = [self.config mutableCopy];\n\n\tmutableConfig.channelName = name;\n\n\tself.config = mutableConfig;\n}\n\n- (void)setTopic:(nullable NSString *)topic\n{\n\tif (self->_topic != topic) {\n\t\tself->_topic = [topic copy];\n\n\t\t[self.viewController setTopic:self->_topic];\n\t}\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)preferencesChanged\n{\n\tif ([TPCPreferences displayPublicMessageCountOnDockBadge] == NO) {\n\t\tif (self.isChannel) {\n\t\t\tself.dockUnreadCount = 0;\n\t\t}\n\t}\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (OTRKitMessageState)encryptionState\n{\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\treturn OTRKitMessageStatePlaintext;\n\t}\n\n\tif (self.isPrivateMessage == NO) {\n\t\treturn OTRKitMessageStatePlaintext;\n\t}\n\n\tIRCClient *client = self.associatedClient;\n\n\treturn [sharedEncryptionManager() messageStateFor:[client encryptionAccountNameForUser:self.name]\n\t\t\t\t\t\t\t\t\t\t\t\t from:[client encryptionAccountNameForLocalUser]];\n}\n\n- (BOOL)encryptionStateIsEncrypted\n{\n\treturn ([self encryptionState] == OTRKitMessageStateEncrypted);\n}\n\n- (void)noteEncryptionStateDidChange\n{\n\tself.viewController.encrypted = self.encryptionStateIsEncrypted;\n\n\t[mainWindow() updateTitleFor:self];\n}\n\n- (void)closeOpenEncryptionSessions\n{\n\tif (self.encryptionStateIsEncrypted == NO) {\n\t\treturn;\n\t}\n\n\tIRCClient *client = self.associatedClient;\n\n\t[sharedEncryptionManager() endConversationWith:[client encryptionAccountNameForUser:self.name]\n\t\t\t\t\t\t\t\t\t\t\t  from:[client encryptionAccountNameForLocalUser]];\n}\n#endif\n\n#pragma mark -\n#pragma mark Channel Status\n\n- (void)setStatus:(IRCChannelStatus)status\n{\n\tif (self->_status != status) {\n\t\tself->_status = status;\n\n\t\t[self performActionOnStatusChange];\n\t}\n}\n\n- (void)performActionOnStatusChange\n{\n\tif (self.statusChangedByAction) {\n\t\tself.statusChangedByAction = NO;\n\n\t\treturn;\n\t}\n\n\tif (self.status == IRCChannelStatusJoined) {\n\t\t[self activate];\n\t} else if (self.status == IRCChannelStatusParted) {\n\t\t[self deactivate];\n\t}\n}\n\n- (void)resetStatus:(IRCChannelStatus)toStatus\n{\n\tif (toStatus == IRCChannelStatusJoining) {\n\t\treturn;\n\t}\n\n\tself.channelModesReceived = NO;\n\tself.channelNamesReceived = NO;\n\tself.errorOnLastJoinAttempt = NO;\n\tself.sentInitialWhoRequest = NO;\n\n\tself.channelJoinTime = 0;\n\n\tself.modeInfo = nil;\n\n\tself.status = toStatus;\n\n\tself.topic = nil;\n\n\t/* Clearing members, instead of just declaring memberInfo nil,\n\t is important so that all users can be properly disassociated\n\t with this channel. There are many relations. */\n\t[self clearMembers];\n\n\tself.memberInfo = nil;\n}\n\n- (void)activate\n{\n\tself.statusChangedByAction = YES;\n\n\t[self resetStatus:IRCChannelStatusJoined];\n\n\tIRCClient *client = self.associatedClient;\n\n\tif (self.isUtility == NO) {\n\t\tself.memberInfo = [[IRCChannelMemberList alloc] initWithChannel:self];\n\n\t\t/* A channel is only assigned by TVCMainWindow when it's switched to.\n\t\t Because of that we have to assign it here as the user already has\n\t\t the channel selected, but it was never assigned because the member\n\t\t list did not exist up to this point. */\n\t\tif (self.isSelectedChannel) {\n\t\t\t[mainWindowMemberList() assignToChannel:self];\n\t\t}\n\t}\n\n\tif (self.isChannel) {\n\t\t[client postEventToViewController:@\"channelJoined\" forChannel:self];\n\n\t\tself.modeInfo = [[IRCChannelMode alloc] initWithChannel:self];\n\t}\n\n\tif (self.isPrivateMessage) {\n\t\tIRCUser *user1 = [self.associatedClient findUserOrCreate:self.name];\n\n\t\t[self addUser:user1];\n\n\t\tIRCUser *user2 = [self.associatedClient findUserOrCreate:client.userNickname];\n\n\t\t[self addUser:user2];\n\t}\n\n\tself.channelJoinTime = [NSDate timeIntervalSince1970];\n}\n\n- (void)deactivate\n{\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tif (self.isPrivateMessage) {\n\t\t[self closeOpenEncryptionSessions];\n\t}\n#endif\n\n\tself.statusChangedByAction = YES;\n\n\t[self resetStatus:IRCChannelStatusParted];\n\n\tif (self.isChannel) {\n\t\t[self.associatedClient postEventToViewController:@\"channelParted\" forChannel:self];\n\t}\n}\n\n- (void)prepareForPermanentDestruction\n{\n\tself.statusChangedByAction = YES;\n\n\t[self resetStatus:IRCChannelStatusTerminated];\n\n\t[self closeLogFile];\n\n\t[self.config destroySecretKeyKeychainItem];\n\n\tNSArray *openWindows = [windowController()\n\t\t\t\t\t\t\twindowsFromWindowList:@[@\"TDCChannelPropertiesSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCChannelModifyTopicSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCChannelModifyModesSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCChannelBanListSheet\"]];\n\n\tfor (TDCSheetBase <TDCChannelPrototype> *windowObject in openWindows) {\n\t\tif ([windowObject.channelId isEqualToString:self.uniqueIdentifier]) {\n\t\t\t[windowObject close];\n\t\t}\n\t}\n\n\t[[mainWindow() inputHistoryManager] destroy:self];\n\n\t[self.viewController prepareForPermanentDestruction];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing channel: <%{public}@>\", self.uniqueIdentifier);\n\n\tself.statusChangedByAction = YES;\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Resetting status to terminated\", self.uniqueIdentifier);\n\n\t[self resetStatus:IRCChannelStatusTerminated];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Closing log file\", self.uniqueIdentifier);\n\n\t[self closeLogFile];\n\n\tif (self.isPrivateMessage) {\n\t\tLogToConsoleTerminationProgress(\"[%{public}@] Destroying keychain items for private message\", self.uniqueIdentifier);\n\n\t\t[self.config destroySecretKeyKeychainItem];\n\t}\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Preparing view controller: <%{public}@>\", self.uniqueIdentifier, self.viewController.uniqueIdentifier);\n\n\t[self.viewController prepareForApplicationTermination];\n}\n\n#pragma mark -\n#pragma mark Log File\n\n- (void)reopenLogFileIfNeeded\n{\n\tif ([TPCPreferences logToDiskIsEnabled] && self.isUtility == NO) {\n\t\tif ( self.logFile) {\n\t\t\t[self.logFile reopenIfNeeded];\n\t\t}\n\t} else {\n\t\t[self closeLogFile];\n\t}\n}\n\n- (void)closeLogFile\n{\n\tif (self.logFile == nil) {\n\t\treturn;\n\t}\n\n\t[self.logFile close];\n}\n\n- (void)logFileWriteSessionBegin\n{\n\t[self.associatedClient logFileRecordSessionChanged:YES inChannel:self];\n}\n\n- (void)logFileWriteSessionEnd\n{\n\t[self.associatedClient logFileRecordSessionChanged:NO inChannel:self];\n\n\tself.logFileSessionCount = 0;\n}\n\n#pragma mark -\n#pragma mark Printing\n\n- (void)writeToLogLineToLogFile:(TVCLogLine *)logLine\n{\n\tNSParameterAssert(logLine != nil);\n\n\tif (self.isUtility || [TPCPreferences logToDiskIsEnabled] == NO) {\n\t\treturn;\n\t}\n\n\t// Perform addition before if statement to avoid infinite loop\n\tself.logFileSessionCount += 1;\n\n\tif (self.logFileSessionCount == 1) {\n\t\t[self logFileWriteSessionBegin];\n\t}\n\n\tif (self.logFile == nil) {\n\t\tself.logFile = [[TLOFileLogger alloc] initWithChannel:self];\n\t}\n\n\t[self.logFile writeLogLine:logLine];\n}\n\n- (void)print:(TVCLogLine *)logLine\n{\n\t[self print:logLine completionBlock:nil];\n}\n\n- (void)print:(TVCLogLine *)logLine completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock\n{\n\tNSParameterAssert(logLine != nil);\n\n\t[self.viewController print:logLine completionBlock:completionBlock];\n\n\t[self writeToLogLineToLogFile:logLine];\n}\n\n#pragma mark -\n#pragma mark Member List\n\n- (void)addUser:(IRCUser *)user\n{\n\t[self.memberInfo addUser:user];\n}\n\n- (void)addMember:(IRCChannelUser *)member\n{\n\t[self.memberInfo addMember:member];\n}\n\n- (void)addMember:(IRCChannelUser *)member checkForDuplicates:(BOOL)checkForDuplicates\n{\n\t[self.memberInfo addMember:member checkForDuplicates:checkForDuplicates];\n}\n\n- (void)removeMemberWithNickname:(NSString *)nickname\n{\n\t[self.memberInfo removeMemberWithNickname:nickname];\n}\n\n- (void)removeMember:(IRCChannelUser *)member\n{\n\t[self.memberInfo removeMember:member];\n}\n\n- (void)resortMember:(IRCChannelUser *)member\n{\n\t[self.memberInfo resortMember:member];\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2\n{\n\t[self.memberInfo replaceMember:member1 withMember:member2];\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort\n{\n\t[self.memberInfo replaceMember:member1 withMember:member2 resort:resort];\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort replaceInAllChannels:(BOOL)replaceInAllChannels\n{\n\t[self.memberInfo replaceMember:member1 withMember:member2 resort:resort replaceInAllChannels:replaceInAllChannels];\n}\n\n- (void)changeMember:(NSString *)nickname mode:(NSString *)mode value:(BOOL)value\n{\n\t[self.memberInfo changeMember:nickname mode:mode value:value];\n}\n\n- (void)clearMembers\n{\n\t[self.memberInfo clearMembers];\n}\n\n- (NSUInteger)numberOfMembers\n{\n\treturn self.memberInfo.numberOfMembers;\n}\n\n- (nullable NSArray<IRCChannelUser *> *)memberList\n{\n\treturn self.memberInfo.memberList;\n}\n\n- (NSData *)pasteboardDataForMembers:(NSArray<IRCChannelUser *> *)members\n{\n\treturn [self.memberInfo pasteboardDataForMembers:members];\n}\n\n+ (BOOL)readNicknamesFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<NSString *> *nicknames))callbackBlock\n{\n\treturn [IRCChannelMemberList readNicknamesFromPasteboardData:pasteboardData withBlock:callbackBlock];\n}\n\n+ (BOOL)readMembersFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<IRCChannelUser *> *members))callbackBlock\n{\n\treturn [IRCChannelMemberList readMembersFromPasteboardData:pasteboardData withBlock:callbackBlock];\n}\n\n- (BOOL)memberExists:(NSString *)nickname\n{\n\treturn [self.memberInfo memberExists:nickname];\n}\n\n- (nullable IRCChannelUser *)findMember:(NSString *)nickname\n{\n\treturn [self.memberInfo findMember:nickname];\n}\n\n- (void)sortMembers\n{\n\t[self.memberInfo sortMembers];\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tNSView *newView = [tableView makeViewWithIdentifier:@\"GroupView\" owner:self];\n\n\treturn newView;\n}\n\n- (nullable NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row\n{\n\tTVCMemberListRowCell *rowView = [[TVCMemberListRowCell alloc] initWithMemberList:(id)tableView];\n\n\treturn rowView;\n}\n\n- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row\n{\n\t[mainWindowMemberList() refreshDrawingForRow:row];\n}\n\n#pragma mark -\n#pragma mark IRCTreeItem Properties\n\n- (BOOL)isSelectedChannel\n{\n\treturn (self == mainWindow().selectedItem);\n}\n\n- (BOOL)isActive\n{\n\treturn (self.status == IRCChannelStatusJoined);\n}\n\n- (BOOL)isClient\n{\n\treturn NO;\n}\n\n- (NSUInteger)numberOfChildren\n{\n\treturn 0;\n}\n\n- (nullable id)childAtIndex:(NSUInteger)index\n{\n\treturn nil;\n}\n\n- (NSString *)label\n{\n\tNSString *customLabel = self.config.label;\n\n\tif (customLabel.length > 0) {\n\t\treturn customLabel;\n\t}\n\n\treturn self.name;\n}\n\n- (nullable IRCClient *)associatedClient\n{\n\treturn self->_associatedClient;\n}\n\n- (nullable IRCChannel *)associatedChannel\n{\n\treturn self;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCChannelConfig.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"IRCChannelConfigInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCChannelConfig\n\n#pragma mark -\n#pragma mark Defaults\n\n- (void)populateDefaultsPreflight\n{\t\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tself->_defaults = @{\n\t  @\"autoJoin\" : @(YES),\n\t  @\"channelType\" : @(IRCChannelTypeChannel),\n\t  @\"ignoreGeneralEventMessages\"\t: @(NO),\n\t  @\"ignoreHighlights\" : @(NO),\n\t  @\"inlineMediaEnabled\" : @(NO),\n\t  @\"inlineMediaDisabled\" : @(NO),\n\t  @\"pushNotifications\" : @(YES),\n\t  @\"showTreeBadgeCount\" : @(YES)\n\t};\n}\n\n- (void)populateDefaultsPostflight\n{\t\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tSetVariableIfNil(self->_channelName, @\"\")\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n\n\tSetVariableIfNil(self->_notificationsMutable, [NSMutableDictionary dictionary])\n}\n\n- (void)populateDefaultsByAppendingDictionary:(NSDictionary<NSString *, id> *)defaultsToAppend\n{\n\tNSParameterAssert(defaultsToAppend != nil);\n\n\tself->_defaults = [self->_defaults dictionaryByAddingEntries:defaultsToAppend];\n}\n\n#pragma mark -\n#pragma mark Channel Configuration\n\n+ (IRCChannelConfig *)seedWithName:(NSString *)channelName\n{\n\tNSParameterAssert(channelName != nil);\n\n\tNSDictionary *dic = @{@\"channelName\" : channelName};\n\n\tIRCChannelConfig *config = [[self alloc] initWithDictionary:dic];\n\n\treturn config;\n}\n\n- (instancetype)init\n{\n\treturn [super initWithDictionary:@{}];\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.mutable || self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tNSParameterAssert(self->_channelName.length > 0);\n}\n\n- (void)populateDictionaryValues:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tNSMutableDictionary<NSString *, id> *defaultsMutable = [self->_defaults mutableCopy];\n\n\t[defaultsMutable addEntriesFromDictionary:dic];\n\n\t[defaultsMutable assignBoolTo:&self->_pushNotifications forKey:@\"pushNotifications\"];\n\t[defaultsMutable assignBoolTo:&self->_showTreeBadgeCount forKey:@\"showTreeBadgeCount\"];\n\n\t[defaultsMutable assignStringTo:&self->_channelName forKey:@\"channelName\"];\n\t[defaultsMutable assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_type forKey:@\"channelType\"];\n\n\tif (self->_type != IRCChannelTypeChannel) {\n\t\treturn;\n\t}\n\n\t/* Load the newest set of keys */\n\t[defaultsMutable assignBoolTo:&self->_autoJoin forKey:@\"autoJoin\"];\n\t[defaultsMutable assignBoolTo:&self->_ignoreGeneralEventMessages forKey:@\"ignoreGeneralEventMessages\"];\n\t[defaultsMutable assignBoolTo:&self->_ignoreHighlights forKey:@\"ignoreHighlights\"];\n\t[defaultsMutable assignBoolTo:&self->_inlineMediaDisabled forKey:@\"inlineMediaDisabled\"];\n\t[defaultsMutable assignBoolTo:&self->_inlineMediaEnabled forKey:@\"inlineMediaEnabled\"];\n\n\t[defaultsMutable assignStringTo:&self->_label forKey:@\"label\"];\n\n\t[defaultsMutable assignStringTo:&self->_defaultModes forKey:@\"defaultMode\"];\n\t[defaultsMutable assignStringTo:&self->_defaultTopic forKey:@\"defaultTopic\"];\n\n\tNSDictionary *notifications = [defaultsMutable dictionaryForKey:@\"notifications\"];\n\n\tif (notifications != nil) {\n\t\tself->_notificationsMutable = [notifications mutableCopy];\n\t}\n\n\t/* Load legacy keys (if they exist) */\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\t[defaultsMutable assignBoolTo:&self->_autoJoin forKey:@\"joinOnConnect\"];\n\t[defaultsMutable assignBoolTo:&self->_ignoreGeneralEventMessages forKey:@\"ignoreJPQActivity\"];\n\t[defaultsMutable assignBoolTo:&self->_pushNotifications forKey:@\"enableNotifications\"];\n\t[defaultsMutable assignBoolTo:&self->_showTreeBadgeCount forKey:@\"enableTreeBadgeCountDrawing\"];\n\n\t/* Migrate inline media */\n\t/* Old behavior was to store a single property named \"ignoreInlineMedia\"\n\t Depending on the value of the global preference, the value of this\n\t property was used to determine whether to hide inline media per-channel\n\t or to show it per-channel. That is stupid idea because if someone\n\t has it enabled globally, has it turned off in a channel, turns it\n\t off globally, then it is turned on in that channel. We split it\n\t up into two properties and this logic performs migration. */\n\t{\n\t\t/* Do new keys exist in incoming dictionary/ */\n\t\tif (dic[@\"inlineMediaEnabled\"] != nil &&\n\t\t\tdic[@\"inlineMediaDisabled\"] != nil)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tNSNumber *ignoreInlineMedia = dic[@\"ignoreInlineMedia\"]; // old key\n\n\t\t/* If old value is NO, then we do not have to continue\n\t\t because the default value for the new values is NO. */\n\t\tif (ignoreInlineMedia == nil || ignoreInlineMedia.boolValue == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\tBOOL inlineEnabledGlobally = [TPCPreferences showInlineMedia];\n\n\t\t/* Old property was the inverse of the global */\n\t\t/* Global enabled = local disabled,\n\t\t   Global disabled = local enabled */\n\t\tself->_inlineMediaDisabled = inlineEnabledGlobally;\n\t\tself->_inlineMediaEnabled = !inlineEnabledGlobally;\n\t}\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t[dic setBool:self.pushNotifications\tforKey:@\"pushNotifications\"];\n\t[dic setBool:self.showTreeBadgeCount forKey:@\"showTreeBadgeCount\"];\n\n\tif (self.type == IRCChannelTypeChannel) {\n\t\t[dic maybeSetObject:self.label forKey:@\"label\"];\n\n\t\t[dic maybeSetObject:self.defaultModes forKey:@\"defaultMode\"];\n\t\t[dic maybeSetObject:self.defaultTopic forKey:@\"defaultTopic\"];\n\n\t\t[dic maybeSetObject:self.notifications forKey:@\"notifications\"];\n\n\t\t[dic setBool:self.autoJoin forKey:@\"autoJoin\"];\n\n\t\t[dic setBool:self.ignoreGeneralEventMessages forKey:@\"ignoreGeneralEventMessages\"];\n\t\t[dic setBool:self.ignoreHighlights forKey:@\"ignoreHighlights\"];\n\n\t\t[dic setBool:self.inlineMediaDisabled forKey:@\"inlineMediaDisabled\"];\n\t\t[dic setBool:self.inlineMediaEnabled forKey:@\"inlineMediaEnabled\"];\n\t}\n\n\t[dic maybeSetObject:self.channelName forKey:@\"channelName\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[dic setUnsignedInteger:self.type forKey:@\"channelType\"];\n\n\tif (target == XRPortablePropertyDictTargetCopy ||\n\t\ttarget == XRPortablePropertyDictTargetMutableCopy)\n\t{\n\t\treturn [dic copy];\n\t}\n\n\treturn [dic dictionaryByRemovingDefaults:self->_defaults allowEmptyValues:YES];\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCChannelConfig class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCChannelConfig *objectCast = (IRCChannelConfig *)object;\n\n\tNSDictionary *s1 = self.dictionaryValue;\n\n\tNSDictionary *s2 = objectCast.dictionaryValue;\n\n\treturn ([s1 isEqualToDictionary:s2] &&\n\t\t\t((self->_secretKey == nil && objectCast->_secretKey == nil) ||\n\t\t\t [self->_secretKey isEqualToString:objectCast->_secretKey]));\n}\n\n- (NSUInteger)hash\n{\n\treturn self.uniqueIdentifier.hash;\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCChannelConfig *config = [self allocForCopyAsMutable:mutableCopy];\n\n\tconfig->_defaults = self->_defaults;\n\n\tconfig->_secretKey = self->_secretKey;\n\n\tif (uniquing) {\n\t\tconfig->_uniqueIdentifier = [NSString stringWithUUID];\n\t}\n\n\treturn [config initWithDictionary:self.dictionaryValueForCopy];\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [IRCChannelConfigMutable self];\n}\n\n- (NSDictionary<NSString *, NSNumber *> *)notifications\n{\n\t@synchronized (self->_notificationsMutable) {\n\t\treturn [self->_notificationsMutable copy];\n\t}\n}\n\n#pragma mark -\n#pragma mark Keychain Management\n\n- (nullable NSString *)secretKey\n{\n\tif (self->_secretKey) {\n\t\treturn self->_secretKey;\n\t}\n\n\treturn self.secretKeyFromKeychain;\n}\n\n- (nullable NSString *)secretKeyFromKeychain\n{\n\tNSString *secretKeyServiceName = [NSString stringWithFormat:@\"textual.cjoinkey.%@\", self.uniqueIdentifier];\n\n\tNSString *kcPassword = [XRKeychain getPasswordFromKeychainItem:@\"Textual (Channel JOIN Key)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   serviceName:secretKeyServiceName];\n\n\treturn kcPassword;\n}\n\n- (void)writeSecretKeyToKeychain\n{\n\tif (self->_secretKey == nil) {\n\t\treturn;\n\t}\n\n\tNSString *secretKeyServiceName = [NSString stringWithFormat:@\"textual.cjoinkey.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain modifyOrAddKeychainItem:@\"Textual (Channel JOIN Key)\"\n\t\t\t\t\t\t   withItemKind:@\"application password\"\n\t\t\t\t\t\t\tforUsername:nil\n\t\t\t\t\t\twithNewPassword:self->_secretKey\n\t\t\t\t\t\t\tserviceName:secretKeyServiceName];\n\n\tself->_secretKey = nil;\n}\n\n- (void)destroySecretKeyKeychainItem\n{\n\tNSString *secretKeyServiceName = [NSString stringWithFormat:@\"textual.cjoinkey.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain deleteKeychainItem:@\"Textual (Channel JOIN Key)\"\n\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t   serviceName:secretKeyServiceName];\n\n\t/* Reset temporary value */\n\tself->_secretKey = nil;\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n- (nullable NSString *)soundForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Sound\"];\n\n\tif (eventKey == nil) {\n\t\treturn nil;\n\t}\n\n\t/* @synchronized is used here because IRCChannelConfigMutable can modify\n\t this value underneath us. */\n\t@synchronized (self->_notificationsMutable) {\n\t\treturn self->_notificationsMutable[eventKey];\n\t}\n}\n\n- (NSControlStateValue)_stateForEventKey:(NSString *)eventKey\n{\n\tNSParameterAssert(eventKey != nil);\n\n\t@synchronized (self->_notificationsMutable) {\n\t\tNSNumber *value = self->_notificationsMutable[eventKey];\n\n\t\tif (value == nil) {\n\t\t\treturn NSControlStateValueMixed;\n\t\t}\n\n\t\tif (value.boolValue == NO) {\n\t\t\treturn NSControlStateValueOff;\n\t\t}\n\n\t\treturn NSControlStateValueOn;\n\t}\n}\n\n- (NSControlStateValue)notificationEnabledForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Enabled\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [self _stateForEventKey:eventKey];\n}\n\n- (NSControlStateValue)disabledWhileAwayForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Disable While Away\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [self _stateForEventKey:eventKey];\n}\n\n- (NSControlStateValue)bounceDockIconForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Bounce Dock Icon\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [self _stateForEventKey:eventKey];\n}\n\n- (NSControlStateValue)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Bounce Dock Icon Repeatedly\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [self _stateForEventKey:eventKey];\n}\n\n- (NSControlStateValue)speakEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Speak\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [self _stateForEventKey:eventKey];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCChannelConfigMutable\n\n@dynamic type;\n@dynamic autoJoin;\n@dynamic channelName;\n@dynamic label;\n@dynamic defaultModes;\n@dynamic defaultTopic;\n@dynamic ignoreGeneralEventMessages;\n@dynamic ignoreHighlights;\n@dynamic inlineMediaDisabled;\n@dynamic inlineMediaEnabled;\n@dynamic pushNotifications;\n@dynamic secretKey;\n@dynamic showTreeBadgeCount;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [IRCChannelConfig self];\n}\n\n- (void)setType:(IRCChannelType)type\n{\n\tif (self->_type != type) {\n\t\tself->_type = type;\n\t}\n}\n\n- (void)setAutoJoin:(BOOL)autoJoin\n{\n\tif (self->_autoJoin != autoJoin) {\n\t\tself->_autoJoin = autoJoin;\n\t}\n}\n\n- (void)setIgnoreGeneralEventMessages:(BOOL)ignoreGeneralEventMessages\n{\n\tif (self->_ignoreGeneralEventMessages != ignoreGeneralEventMessages) {\n\t\tself->_ignoreGeneralEventMessages = ignoreGeneralEventMessages;\n\t}\n}\n\n- (void)setIgnoreHighlights:(BOOL)ignoreHighlights\n{\n\tif (self->_ignoreHighlights != ignoreHighlights) {\n\t\tself->_ignoreHighlights = ignoreHighlights;\n\t}\n}\n\n- (void)setInlineMediaDisabled:(BOOL)inlineMediaDisabled\n{\n\tif (self->_inlineMediaDisabled != inlineMediaDisabled) {\n\t\tself->_inlineMediaDisabled = inlineMediaDisabled;\n\t}\n}\n\n- (void)setInlineMediaEnabled:(BOOL)inlineMediaEnabled\n{\n\tif (self->_inlineMediaEnabled != inlineMediaEnabled) {\n\t\tself->_inlineMediaEnabled = inlineMediaEnabled;\n\t}\n}\n\n- (void)setPushNotifications:(BOOL)pushNotifications\n{\n\tif (self->_pushNotifications != pushNotifications) {\n\t\tself->_pushNotifications = pushNotifications;\n\t}\n}\n\n- (void)setShowTreeBadgeCount:(BOOL)showTreeBadgeCount\n{\n\tif (self->_showTreeBadgeCount != showTreeBadgeCount) {\n\t\tself->_showTreeBadgeCount = showTreeBadgeCount;\n\t}\n}\n\n- (void)setChannelName:(NSString *)channelName\n{\n\tNSParameterAssert(channelName != nil);\n\n\tif (self->_channelName != channelName) {\n\t\tself->_channelName = [channelName copy];\n\t}\n}\n\n- (void)setLabel:(nullable NSString *)label\n{\n\tif (self->_label != label) {\n\t\tself->_label = [label copy];\n\t}\n}\n\n- (void)setDefaultModes:(nullable NSString *)defaultModes\n{\n\tif (self->_defaultModes != defaultModes) {\n\t\tself->_defaultModes = [defaultModes copy];\n\t}\n}\n\n- (void)setDefaultTopic:(nullable NSString *)defaultTopic\n{\n\tif (self->_defaultTopic != defaultTopic) {\n\t\tself->_defaultTopic = [defaultTopic copy];\n\t}\n}\n\n- (void)setSecretKey:(nullable NSString *)secretKey\n{\n\tif (self->_secretKey != secretKey) {\n\t\tself->_secretKey = [secretKey copy];\n\t}\n}\n\n- (void)setSound:(nullable NSString *)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Sound\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t@synchronized (self->_notificationsMutable) {\n\t\tif (value == nil) {\n\t\t\t[self->_notificationsMutable removeObjectForKey:eventKey];\n\t\t} else {\n\t\t\tself->_notificationsMutable[eventKey] = value;\n\t\t}\n\t}\n}\n\n- (void)_setState:(NSControlStateValue)state forEventKey:(NSString *)eventKey\n{\n\tNSParameterAssert(eventKey != nil);\n\n\t@synchronized (self->_notificationsMutable) {\n\t\tswitch (state) {\n\t\t\tcase NSControlStateValueOn:\n\t\t\t{\n\t\t\t\tself->_notificationsMutable[eventKey] = @(YES);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NSControlStateValueOff:\n\t\t\t{\n\t\t\t\tself->_notificationsMutable[eventKey] = @(NO);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase NSControlStateValueMixed:\n\t\t\t{\n\t\t\t\t[self->_notificationsMutable removeObjectForKey:eventKey];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tNSAssert(NO, @\"Bad 'state'\");\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)setNotificationEnabled:(NSControlStateValue)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Enabled\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[self _setState:value forEventKey:eventKey];\n}\n\n- (void)setDisabledWhileAway:(NSControlStateValue)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Disable While Away\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[self _setState:value forEventKey:eventKey];\n}\n\n- (void)setBounceDockIcon:(NSControlStateValue)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Bounce Dock Icon\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[self _setState:value forEventKey:eventKey];\n}\n\n- (void)setBounceDockIconRepeatedly:(NSControlStateValue)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Bounce Dock Icon Repeatedly\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[self _setState:value forEventKey:eventKey];\n}\n\n- (void)setEventIsSpoken:(NSControlStateValue)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [TPCPreferences keyForEvent:event category:@\"Speak\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[self _setState:value forEventKey:eventKey];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCChannelMemberList.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCChannelMemberListPrivate.h\"\n#import \"IRCChannelMemberListControllerPrivate.h\"\n#import \"IRCChannelUserPrivate.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCUserPrivate.h\"\n#import \"IRCWorld.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCMemberList.h\"\n#import \"TVCMainWindow.h\"\n#import \"TXMasterController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelMemberList ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, weak) IRCChannel *channel;\n@property (nonatomic, strong, nullable) IRCChannelMemberListController *controller;\n@property (nonatomic, strong) NSMutableArray<IRCChannelUser *> *memberContainer;\n@end\n\n@implementation IRCChannelMemberList\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.channel = channel;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.memberContainer = [NSMutableArray array];\n}\n\n- (void)dealloc\n{\n\t/* Send a last message before death. */\n\t[self unassignController];\n}\n\n- (void)assignController:(nullable IRCChannelMemberListController *)controller\n{\n\t/* All modifications to the controller occur on the main thread.\n\t The controller is a UI object which requires updates on the\n\t main thread in addition to the safety it provides us again\n\t race conditions. */\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[controller replaceContents:self.memberList];\n\n\t\tself.controller = controller;\n\t});\n}\n\n- (void)unassignController\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif ( controller) {\n\t\t\t[controller assignToChannel:nil];\n\t\t}\n\t});\n}\n\n#pragma mark -\n#pragma mark Grand Central Dispatch\n\n/* All modifications to the member list occur on this serial queue\n to guarantee that there is only ever one person accessing the mutable\n store at any given time. */\n+ (dispatch_queue_t)modifyMemberListSerialQueue\n{\n\tstatic dispatch_queue_t workerQueue = NULL;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tworkerQueue =\n\t\tXRCreateDispatchQueueWithPriority(\"IRCChannel.modifyMemberListSerialQueue\", DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT);\n\t});\n\n\treturn workerQueue;\n}\n\n+ (void)resumeMemberListSerialQueues\n{\n\tdispatch_resume([self modifyMemberListSerialQueue]);\n}\n\n+ (void)suspendMemberListSerialQueues\n{\n\tdispatch_suspend([self modifyMemberListSerialQueue]);\n}\n\n+ (void)accessMemberListUsingBlock:(dispatch_block_t)block\n{\n\tNSCParameterAssert(block != NULL);\n\n\tdispatch_queue_t workerQueue = [self modifyMemberListSerialQueue];\n\n\tstatic void *IsOnWorkerQueueKey = NULL;\n\n\tif (IsOnWorkerQueueKey == NULL) {\n\t\tIsOnWorkerQueueKey = &IsOnWorkerQueueKey;\n\n\t\tdispatch_queue_set_specific(workerQueue, IsOnWorkerQueueKey, (void *)1, NULL);\n\t}\n\n\tif (dispatch_get_specific(IsOnWorkerQueueKey)) {\n\t\tblock();\n\n\t\treturn;\n\t}\n\n\tdispatch_sync(workerQueue, ^{\n\t\t@autoreleasepool {\n\t\t\tblock();\n\t\t}\n\t});\n}\n\n#pragma mark -\n#pragma mark Backend Operations\n\n- (NSUInteger)nonatomic_sortedIndexForMember:(IRCChannelUser *)member\n{\n\tNSParameterAssert(member != nil);\n\n\tNSMutableArray *container = self.memberContainer;\n\n\tNSUInteger index = [container\n\t\t\t\t\t\t\tindexOfObject:member\n\t\t\t\t\t\t\tinSortedRange:container.range\n\t\t\t\t\t\t\t\t  options:NSBinarySearchingInsertionIndex\n\t\t\t\t\t\t  usingComparator:[IRCChannelUser channelRankComparator]];\n\n\treturn index;\n}\n\n- (NSInteger)nonatomic_sortedInsert:(IRCChannelUser *)member\n{\n\tNSParameterAssert(member != nil);\n\n\tNSInteger insertedIndex = [self nonatomic_sortedIndexForMember:member];\n\n\t[self.memberContainer insertObject:member atIndex:insertedIndex];\n\n\treturn insertedIndex;\n}\n\n- (NSInteger)nonatomic_replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2\n{\n\tNSParameterAssert(member1 != nil);\n\tNSParameterAssert(member2 != nil);\n\n\tNSMutableArray *container = self.memberContainer;\n\n\tNSUInteger index = [container indexOfObjectIdenticalTo:member1];\n\n\tif (index == NSNotFound) {\n\t\treturn (-1);\n\t}\n\n\tcontainer[index] = member2;\n\n\treturn index;\n}\n\n- (NSInteger)nonatomic_removeMember:(IRCChannelUser *)member\n{\n\tNSParameterAssert(member != nil);\n\n\tNSMutableArray *container = self.memberContainer;\n\n\tNSUInteger index = [container indexOfObjectIdenticalTo:member];\n\n\tif (index == NSNotFound) {\n\t\treturn (-1);\n\t}\n\n\t[container removeObjectAtIndex:index];\n\n\treturn index;\n}\n\n#pragma mark -\n#pragma mark Frontend Operations\n\n- (void)addUser:(IRCUser *)user\n{\n\tNSParameterAssert(user != nil);\n\n\tIRCChannelUser *member = [[IRCChannelUser alloc] initWithUser:user];\n\n\t[self addMember:member];\n}\n\n- (void)addMember:(IRCChannelUser *)member\n{\n\t[self addMember:member checkForDuplicates:NO];\n}\n\n- (void)addMember:(IRCChannelUser *)member checkForDuplicates:(BOOL)checkForDuplicates\n{\n\tNSParameterAssert(member != nil);\n\n\tIRCChannel *channel = self.channel;\n\n\tif (checkForDuplicates) {\n\t\tIRCChannelUser *oldMember = [member.user userAssociatedWithChannel:channel];\n\n\t\tif (oldMember != nil) {\n\t\t\t[self replaceMember:oldMember withMember:member];\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ([member isKindOfClass:[IRCChannelUserMutable class]]) {\n\t\t member = [member copy];\n\t}\n\n\t[member associateWithChannel:channel];\n\n\t[self willChangeValueForKey:@\"numberOfMembers\"];\n\t[self willChangeValueForKey:@\"memberList\"];\n\n\t__block NSInteger sortedIndex = (-1);\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\tsortedIndex = [self nonatomic_sortedInsert:member];\n\t}];\n\n\t[self didChangeValueForKey:@\"numberOfMembers\"];\n\t[self didChangeValueForKey:@\"memberList\"];\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif ( controller != nil) {\n\t\t\t[controller insertObject:member atArrangedObjectIndex:sortedIndex];\n\t\t}\n\n\t\t[self.client postEventToViewController:@\"channelMemberAdded\" forChannel:channel];\n\t});\n}\n\n- (void)removeMemberWithNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tIRCChannelUser *member = [self findMember:nickname];\n\n\tif (member) {\n\t\t[self removeMember:member];\n\t}\n}\n\n- (void)removeMember:(IRCChannelUser *)member\n{\n\tNSParameterAssert(member != nil);\n\n\tIRCChannel *channel = self.channel;\n\n\t[member disassociateWithChannel:channel];\n\n\t__block NSInteger sortedIndex = (-1);\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\tsortedIndex = [self nonatomic_removeMember:member];\n\t}];\n\n\tif (sortedIndex < 0 || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif ( controller != nil) {\n\t\t\t[controller removeObjectAtArrangedObjectIndex:sortedIndex];\n\t\t}\n\n\t\t[self.client postEventToViewController:@\"channelMemberRemoved\" forChannel:channel];\n\t});\n}\n\n- (void)resortMember:(IRCChannelUser *)member\n{\n\tNSParameterAssert(member != nil);\n\n\tif ([member isKindOfClass:[IRCChannelUserMutable class]]) {\n\t\t member = [member copy];\n\t}\n\n\t[self replaceMember:member withMember:member resort:YES];\n}\n\n- (void)_replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort\n{\n\tNSParameterAssert(member1 != nil);\n\tNSParameterAssert(member2 != nil);\n\n\tIRCChannel *channel = self.channel;\n\n\tif (member1 != member2) {\n\t\t[member1 disassociateWithChannel:channel];\n\n\t\t[member2 associateWithChannel:channel];\n\t}\n\n\t__block NSInteger oldIndex = (-1);\n\t__block NSInteger newIndex = (-1);\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\tif (resort) {\n\t\t\toldIndex = [self nonatomic_removeMember:member1];\n\n\t\t\tnewIndex = [self nonatomic_sortedInsert:member2];\n\t\t} else {\n\t\t\tnewIndex = [self nonatomic_replaceMember:member1 withMember:member2];\n\t\t}\n\t}];\n\n\tif (newIndex < 0 || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif (controller == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[mainWindowMemberList() beginUpdates];\n\n\t\tif (resort) {\n\t\t\tif (oldIndex >= 0) {\n\t\t\t\t[controller removeObjectAtArrangedObjectIndex:oldIndex];\n\t\t\t}\n\n\t\t\t[controller insertObject:member2 atArrangedObjectIndex:newIndex];\n\t\t} else {\n\t\t\t[mainWindowMemberList() refreshDrawingForRow:newIndex];\n\t\t}\n\n\t\t[mainWindowMemberList() endUpdates];\n\t});\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2\n{\n\t[self replaceMember:member1 withMember:member2 resort:YES replaceInAllChannels:NO];\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort\n{\n\t[self replaceMember:member1 withMember:member2 resort:YES replaceInAllChannels:NO];\n}\n\n- (void)replaceMember:(IRCChannelUser *)member1 withMember:(IRCChannelUser *)member2 resort:(BOOL)resort replaceInAllChannels:(BOOL)replaceInAllChannels\n{\n\tNSParameterAssert(member1 != nil);\n\tNSParameterAssert(member2 != nil);\n\n\tif ([member2 isKindOfClass:[IRCChannelUserMutable class]]) {\n\t\t member2 = [member2 copy];\n\t}\n\n\t[self _replaceMember:member1 withMember:member2 resort:resort];\n\n\tif (replaceInAllChannels) {\n\t\tIRCChannel *thisChannel = self.channel;\n\n\t\tNSDictionary *relations = member2.user.relations;\n\n\t\t[relations enumerateKeysAndObjectsUsingBlock:^(IRCChannel *targetChannel, IRCChannelUser *member, BOOL *stop) {\n\t\t\tif (thisChannel == targetChannel) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIRCChannelMemberList *memberList = targetChannel.memberInfo;\n\n\t\t\t[memberList _replaceMember:member withMember:member resort:resort];\n\t\t}];\n\t}\n}\n\n- (void)changeMember:(NSString *)nickname mode:(NSString *)mode value:(BOOL)value\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(mode.length == 1);\n\n\tIRCClient *client = self.client;\n\tIRCChannel *channel = self.channel;\n\n\t// Find member and create mutable copy for editing\n\tIRCChannelUser *member = [channel findMember:nickname];\n\n\tif (member == nil) {\n\t\treturn;\n\t}\n\n\tIRCChannelUserMutable *memberMutable = [member mutableCopy];\n\n\tNSString *oldMemberModes = memberMutable.modes;\n\n\t// If the member has no modes already and we are setting a mode, then\n\t// all we have to do is set the value of -modes to new mode\n\tBOOL processModes = YES;\n\n\tif (oldMemberModes.length == 0) {\n\t\tif (value) {\n\t\t\tprocessModes = NO;\n\n\t\t\tmemberMutable.modes = mode;\n\t\t} else {\n\t\t\treturn; // Can't remove mode from empty string\n\t\t}\n\t} else {\n\t\tif (value && [oldMemberModes contains:mode]) {\n\t\t\treturn; // Mode is already in string\n\t\t}\n\t}\n\n\t// Split up the current user modes into an array of characters.\n\t// Enumerate over the array of characters to find which mode in the\n\t// current set has a rank lower than the mode being inserted.\n\t// Insert before the lower ranked mode or insert at end.\n\tif (processModes) {\n\t\tIRCISupportInfo *clientSupportInfo = client.supportInfo;\n\n\t\tNSArray *oldModeSymbols = oldMemberModes.characterStringBuffer;\n\n\t\tNSMutableArray *newModeSymbols = [oldModeSymbols mutableCopy];\n\n\t\tif (value == NO) {\n\t\t\t[newModeSymbols removeObject:mode];\n\t\t} else {\n\t\t\tNSUInteger rankOfNewMode = [clientSupportInfo rankForUserPrefixWithMode:mode];\n\n\t\t\tNSUInteger lowerRankedMode =\n\t\t\t[oldModeSymbols indexOfObjectPassingTest:^BOOL(NSString *oldModeSymbol, NSUInteger index, BOOL *stop) {\n\t\t\t\tNSInteger rankOfOldMode = [clientSupportInfo rankForUserPrefixWithMode:oldModeSymbol];\n\n\t\t\t\treturn (rankOfOldMode < rankOfNewMode);\n\t\t\t}];\n\n\t\t\tif (lowerRankedMode != NSNotFound) {\n\t\t\t\t[newModeSymbols insertObject:mode atIndex:lowerRankedMode];\n\t\t\t} else {\n\t\t\t\t[newModeSymbols addObject:mode];\n\t\t\t}\n\t\t}\n\n\t\tNSString *newMemberModes = [newModeSymbols componentsJoinedByString:@\"\"];\n\n\t\tmemberMutable.modes = newMemberModes;\n\t}\n\n\tBOOL replaceInAllChannels = NO;\n\n\tif (value && [mode isEqualToString:@\"Y\"] && member.user.isIRCop == NO) {\n\t\t/* InspIRCd treats +Y as an IRCop. */\n\t\t/* If the user wasn't already marked as an IRCop, then we\n\t\t mark them at this point. */\n\n\t\t[client modifyUser:member.user withBlock:^(IRCUserMutable *userMutable) {\n\t\t\tuserMutable.isIRCop = YES;\n\t\t}];\n\n\t\tif ([TPCPreferences memberListSortFavorsServerStaff]) {\n\t\t\treplaceInAllChannels = YES;\n\t\t}\n\t}\n\n\t// Remove the user from the member list and insert sorted\n\t[self replaceMember:member\n\t\t\t withMember:memberMutable\n\t\t\t\t resort:YES\n   replaceInAllChannels:replaceInAllChannels];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)sortMembers\n{\n\t[self.class accessMemberListUsingBlock:^{\n\t\t[self.memberContainer sortUsingComparator:[IRCChannelUser channelRankComparator]];\n\t}];\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif (controller == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[controller replaceContents:self.memberList];\n\t});\n}\n\n- (void)clearMembers\n{\n\tIRCChannel *channel = self.channel;\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\t[self willChangeValueForKey:@\"numberOfMembers\"];\n\t\t[self willChangeValueForKey:@\"memberList\"];\n\n\t\t[self.memberContainer makeObjectsPerformSelector:@selector(disassociateWithChannel:) withObject:channel];\n\n\t\t[self.memberContainer removeAllObjects];\n\n\t\t[self didChangeValueForKey:@\"numberOfMembers\"];\n\t\t[self didChangeValueForKey:@\"memberList\"];\n\t}];\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCChannelMemberListController *controller = self.controller;\n\n\t\tif (controller == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[controller replaceContents:@[]];\n\t});\n}\n\n- (NSUInteger)numberOfMembers\n{\n\t__block NSUInteger memberCount = 0;\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\tmemberCount = self.memberContainer.count;\n\t}];\n\n\treturn memberCount;\n}\n\n- (nullable NSArray<IRCChannelUser *> *)memberList\n{\n\t__block NSArray<IRCChannelUser *> *memberList = nil;\n\n\t[self.class accessMemberListUsingBlock:^{\n\t\tmemberList = [self.memberContainer copy];\n\t}];\n\n\treturn memberList;\n}\n\n#pragma mark -\n#pragma mark Clipboard\n\n- (NSData *)pasteboardDataForMembers:(NSArray<IRCChannelUser *> *)members\n{\n\tNSParameterAssert(members != nil);\n\n\tNSString *channelId = self.channel.uniqueIdentifier;\n\n\tNSMutableArray<NSString *> *nicknames = [NSMutableArray arrayWithCapacity:members.count];\n\n\tfor (IRCChannelUser *member in members) {\n\t\t[nicknames addObject:member.user.nickname];\n\t}\n\n\tNSDictionary *pasteboardDictionary = @{\n\t   @\"channelId\" : channelId,\n\t   @\"nicknames\" : nicknames\n\t};\n\n\tNSData *pasteboardData = [NSKeyedArchiver archivedDataWithRootObject:pasteboardDictionary];\n\n\treturn pasteboardData;\n}\n\n+ (BOOL)readNicknamesFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<NSString *> *nicknames))callbackBlock\n{\n\tNSParameterAssert(pasteboardData != nil);\n\tNSParameterAssert(callbackBlock != nil);\n\n\t/* This is a private method which means that we are very lazy about\n\t validating the input, but this is a TODO to myself: add strict type\n\t checks if you end up making this method public. */\n\tNSDictionary *pasteboardDictionary = [NSKeyedUnarchiver unarchiveObjectWithData:pasteboardData];\n\n\tif ([pasteboardDictionary isKindOfClass:[NSDictionary class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tNSString *channelId = pasteboardDictionary[@\"channelId\"];\n\n\tIRCChannel *channel = (IRCChannel *)[worldController() findItemWithId:channelId];\n\n\tif (channel == nil) {\n\t\treturn NO;\n\t}\n\n\tNSArray *nicknames = pasteboardDictionary[@\"nicknames\"];\n\n\tcallbackBlock(channel, nicknames);\n\n\treturn YES;\n}\n\n+ (BOOL)readMembersFromPasteboardData:(NSData *)pasteboardData withBlock:(void (NS_NOESCAPE ^)(IRCChannel *channel, NSArray<IRCChannelUser *> *members))callbackBlock\n{\n\tNSParameterAssert(pasteboardData != nil);\n\tNSParameterAssert(callbackBlock != nil);\n\n\treturn\n\t[self readNicknamesFromPasteboardData:pasteboardData withBlock:^(IRCChannel *channel, NSArray<NSString *> *nicknames) {\n\t\tNSMutableArray *members = [NSMutableArray arrayWithCapacity:nicknames.count];\n\n\t\tfor (NSString *nickname in nicknames) {\n\t\t\tIRCChannelUser *member = [channel findMember:nickname];\n\n\t\t\tif (member == nil) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[members addObject:member];\n\t\t}\n\n\t\tcallbackBlock(channel, [members copy]);\n\t}];\n}\n\n#pragma mark -\n#pragma mark Search\n\n- (BOOL)memberExists:(NSString *)nickname\n{\n\treturn ([self findMember:nickname] != nil);\n}\n\n- (nullable IRCChannelUser *)findMember:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tIRCUser *user = [self.client findUser:nickname];\n\n\tif (user == nil) {\n\t\treturn nil;\n\t}\n\n\tIRCChannelUser *member = [user userAssociatedWithChannel:self.channel];\n\n\tif (member == nil) {\n\t\treturn nil;\n\t}\n\n\treturn member;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCChannelMemberListController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannelPrivate.h\"\n#import \"IRCChannelMemberList.h\"\n#import \"IRCChannelMemberListControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelMemberList ()\n- (void)assignController:(nullable IRCChannelMemberListController *)controller;\n@end\n\n@interface IRCChannelMemberListController ()\n@property (nonatomic, weak) IRCChannelMemberList *memberList;\n@property (nonatomic, weak) IBOutlet NSTableView *tableView;\n@end\n\n@implementation IRCChannelMemberListController\n\n- (void)assignToChannel:(nullable IRCChannel *)channel\n{\n\t/* Modify table sources */\n\tNSTableView *tableView = self.tableView;\n\n\ttableView.dataSource = (id)channel;\n\ttableView.delegate = (id)channel;\n\n\t/* Are we assigned? */\n\tIRCChannelMemberList *oldList = self.memberList;\n\n\tif ( oldList) {\n\t\t[oldList assignController:nil];\n\t}\n\n\tIRCChannelMemberList *newList = channel.memberInfo;\n\n\tif ( newList) {\n\t\t[newList assignController:self];\n\t}\n\n\t/* It is acceptable and correct behavior to assign nil\n\t to -memberList when there is none so there is no reason\n\t to place this assignment in the condition above. */\n\tself.memberList = newList;\n\n\tif (channel == nil || newList == nil) {\n\t\tself.content = @[];\n\t}\n}\n\n- (void)replaceContents:(NSArray<IRCChannelUser *> *)contents\n{\n\tNSParameterAssert(contents != nil);\n\n\tself.content = [contents mutableCopy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCChannelMode.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCISupportInfoPrivate.h\"\n#import \"IRCModeInfo.h\"\n#import \"IRCChannelModePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelMode ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, weak) IRCChannel *channel;\n@property (nonatomic, copy, readwrite) IRCChannelModeContainer *modes;\n@end\n\n@interface IRCChannelModeContainer ()\n@property (nonatomic, weak) IRCISupportInfo *supportInfo;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, IRCModeInfo *> *modeObjects;\n@property (readonly, copy) NSArray<NSString *> *unwantedModes;\n\n- (instancetype)initWithSupportInfo:(IRCISupportInfo *)supportInfo;\n@end\n\n@implementation IRCChannelMode\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.channel = channel;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself->_modes = [[IRCChannelModeContainer alloc] initWithSupportInfo:self.client.supportInfo];\n}\n\n- (NSArray<IRCModeInfo *> *)updateModes:(NSString *)modeString\n{\n\tNSParameterAssert(modeString != nil);\n\n\tIRCISupportInfo *supportInfo = self.client.supportInfo;\n\n\tNSArray *modes = [supportInfo parseModes:modeString];\n\n\t[self.modes applyModes:modes];\n\n\treturn modes;\n}\n\n- (NSString *)getChangeCommand:(IRCChannelModeContainer *)modes\n{\n\tNSParameterAssert(modes != nil);\n\n\tNSDictionary *modesSetOld = self.modes.modes;\n\n\tNSDictionary *modesSetNew = modes.modes;\n\n\tNSMutableString *modeAddString = [NSMutableString string];\n\tNSMutableString *modeRemoveString = [NSMutableString string];\n\tNSMutableString *modeParamString = [NSMutableString string];\n\n\t/* Look over the set of modes that are currently set. If a mode is present\n\t in that set, but not in the new set, then mark that mode for removal. */\n\t[modesSetOld enumerateKeysAndObjectsUsingBlock:^(NSString *modeSymbol, IRCModeInfo *mode, BOOL *stop) {\n\t\tif (modesSetNew[modeSymbol] != nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (modeRemoveString.length == 0) {\n\t\t\t[modeRemoveString appendFormat:@\"-%@\", modeSymbol];\n\t\t} else {\n\t\t\t[modeRemoveString appendString:modeSymbol];\n\t\t}\n\t}];\n\n\t/* Look over the new set of modes and compare them to the old set.\n\t If a mode has changed (check for equality), then perform action. */\n\t[modesSetNew enumerateKeysAndObjectsUsingBlock:^(NSString *modeSymbol, IRCModeInfo *mode, BOOL *stop) {\n\t\tIRCModeInfo *modeOld = modesSetOld[modeSymbol];\n\n\t\tif ([mode isEqual:modeOld]) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (mode.modeIsSet) {\n\t\t\tif (modeAddString.length == 0) {\n\t\t\t\t[modeAddString appendFormat:@\"+%@\", modeSymbol];\n\t\t\t} else {\n\t\t\t\t[modeAddString appendString:modeSymbol];\n\t\t\t}\n\t\t} else {\n\t\t\tif (modeRemoveString.length == 0) {\n\t\t\t\t[modeRemoveString appendFormat:@\"-%@\", modeSymbol];\n\t\t\t} else {\n\t\t\t\t[modeRemoveString appendString:modeSymbol];\n\t\t\t}\n\t\t}\n\n\t\tNSString *modeParameter = mode.modeParameter;\n\n\t\tif (modeParameter.length == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t[modeParamString appendFormat:@\" %@\", modeParameter];\n\t}];\n\n\treturn [NSString stringWithFormat:@\"%@%@%@\", modeRemoveString, modeAddString, modeParamString];\n}\n\n- (void)clear\n{\n\t[self.modes clear];\n}\n\n- (BOOL)modeIsDefined:(NSString *)modeSymbol\n{\n\treturn [self.modes modeIsDefined:modeSymbol];\n}\n\n- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol\n{\n\treturn [self.modes modeInfoFor:modeSymbol];\n}\n\n- (NSString *)stringWithMaskedPassword:(BOOL)maskPassword\n{\n\tNSMutableString *modeSetString = [NSMutableString string];\n\tNSMutableString *modeParamString = [NSMutableString string];\n\n\tNSDictionary *modes = self.modes.modes;\n\n\tNSArray *modesSorted = modes.sortedDictionaryKeys;\n\n\tfor (NSString *modeSymbol in modesSorted) {\n\t\tIRCModeInfo *mode = modes[modeSymbol];\n\n\t\tif (mode.modeIsSet == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (modeSetString.length == 0) {\n\t\t\t[modeSetString appendFormat:@\"+%@\", modeSymbol];\n\t\t} else {\n\t\t\t[modeSetString appendString:modeSymbol];\n\t\t}\n\n\t\tNSString *modeParameter = mode.modeParameter;\n\n\t\tif (modeParameter.length == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ([modeSymbol isEqualToString:@\"k\"] && maskPassword) {\n\t\t\t[modeParamString appendFormat:@\" ******\"];\n\t\t} else {\n\t\t\t[modeParamString appendFormat:@\" %@\", modeParameter];\n\t\t}\n\t}\n\n\treturn [modeSetString stringByAppendingString:modeParamString];\n}\n\n- (NSString *)string\n{\n\treturn [self stringWithMaskedPassword:NO];\n}\n\n- (NSString *)stringWithMaskedPassword\n{\n\treturn [self stringWithMaskedPassword:YES];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCChannelModeContainer\n\n- (instancetype)initWithSupportInfo:(IRCISupportInfo *)supportInfo\n{\n\tNSParameterAssert(supportInfo != nil);\n\n\tif ((self = [super init])) {\n\t\tself.supportInfo = supportInfo;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.modeObjects = [NSMutableDictionary dictionary];\n}\n\n- (void)clear\n{\n\t@synchronized(self.modeObjects) {\n\t\t[self.modeObjects removeAllObjects];\n\t}\n}\n\n- (NSDictionary<NSString *, IRCModeInfo *> *)modes\n{\n\t@synchronized(self.modeObjects) {\n\t\treturn [self.modeObjects copy];\n\t}\n}\n\n- (NSArray<NSString *> *)unwantedModes\n{\n\tIRCISupportInfo *supportInfo = self.supportInfo;\n\n\t/* Using some random value in place of mode if there is none\n\t is easier than creating a mutable array with four if statements. */\n\treturn @[\n\t\t /* ban */\t\t\t \t(([supportInfo modeSymbolForList:IRCISupportInfoListTypeBan]) ?: @\"not supported: b\"),\n\t\t /* ban exception */\t(([supportInfo modeSymbolForList:IRCISupportInfoListTypeBanException]) ?: @\"not supported: e\"),\n\t\t /* invite exception */\t(([supportInfo modeSymbolForList:IRCISupportInfoListTypeInviteException]) ?: @\"not supported: I\"),\n\t\t /* quiet */\t\t\t(([supportInfo modeSymbolForList:IRCISupportInfoListTypeQuiet]) ?: @\"not supported: q\")\n\t];\n}\n\n- (BOOL)modeIsPermitted:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tif ([self.unwantedModes containsObject:modeSymbol]) {\n\t\treturn NO;\n\t}\n\n\tif ([self.supportInfo modeSymbolIsUserPrefix:modeSymbol]) {\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)modeIsDefined:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\treturn (self.modes[modeSymbol] != nil);\n}\n\n- (nullable IRCModeInfo *)modeInfoFor:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\t@synchronized (self.modeObjects) {\n\t\tIRCModeInfo *mode = self.modeObjects[modeSymbol];\n\n\t\tif (mode) {\n\t\t\treturn mode;\n\t\t}\n\n\t\tif ([self modeIsPermitted:modeSymbol] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tmode = [[IRCModeInfo alloc] initWithModeSymbol:modeSymbol];\n\n\t\tself.modeObjects[modeSymbol] = mode;\n\n\t\treturn mode;\n\t}\n}\n\n- (void)applyModes:(NSArray<IRCModeInfo *> *)modes\n{\n\tNSParameterAssert(modes != nil);\n\n\tfor (IRCModeInfo *mode in modes) {\n\t\t[self changeMode:mode.modeSymbol\n\t\t\t   modeIsSet:mode.modeIsSet\n\t\t   modeParameter:mode.modeParameter];\n\t}\n}\n\n- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet\n{\n\t[self changeMode:modeSymbol modeIsSet:modeIsSet modeParameter:nil];\n}\n\n- (void)changeMode:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tIRCModeInfo *mode = [self modeInfoFor:modeSymbol];\n\n\tif (mode == nil) {\n\t\treturn;\n\t}\n\n\tIRCModeInfoMutable *modeMutable = [mode mutableCopy];\n\n\tmodeMutable.modeSymbol = modeSymbol;\n\tmodeMutable.modeIsSet = modeIsSet;\n\tmodeMutable.modeParameter = modeParameter;\n\n\t@synchronized (self.modeObjects) {\n\t\tself.modeObjects[modeSymbol] = [modeMutable copy];\n\t}\n}\n\n- (id)copyWithZone:(nullable NSZone *)zone\n{\n\tIRCChannelModeContainer *object =\n\t[[IRCChannelModeContainer alloc] initWithSupportInfo:self.supportInfo];\n\n\t/* modeObjects contain immutable objects which means\n\t we don't have to copy the objects themselves. */\n\t/* If we ever modify IRCModeInfo internal logic to ever\n\t modify the contents of the object after initialization,\n\t then we should perform a deep copy here. */\n\tobject.modeObjects = [self.modeObjects mutableCopy];\n\n\treturn object;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCClient.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *      Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* A portion of this source file contains copyrighted work derived from one or more\n 3rd-party, open source projects. The use of this work is hereby acknowledged. */\n\n/* This source file contains work that originated from the Chat Core \n framework of the Colloquy project. The source in question is in relation\n to the handling of SASL authentication requests. The license of the \n Chat Core project is as follows: \n\n This document can be found mirrored at the author's website:\n <http://colloquy.info/project/browser/trunk/Resources/BSD%20License.txt>\n\n No actual copyright is presented in the license file or the actual \n source file in which this work was obtained so the work is assumed to\n be Copyright © 2000 - 2012 the Colloquy IRC Client\n\n ------- License -------\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are\n met:\n\n 1. Redistributions of source code must retain the above copyright\n notice, this list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n 3. The name of the author may not be used to endorse or promote\n products derived from this software without specific prior written\n permission.\n\n THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN\n NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#import <objc/message.h>\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"GCDAsyncSocketExtensions.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCResourceManager.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"THOPluginProtocol.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOFileLoggerPrivate.h\"\n#import \"TLOInputHistoryPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLONotificationControllerPrivate.h\"\n#import \"TLOpenLink.h\"\n#import \"TLOSoundPlayer.h\"\n#import \"TLOSpeechSynthesizerPrivate.h\"\n#import \"TLOSpokenNotificationPrivate.h\"\n#import \"TLOTimer.h\"\n#import \"TXGlobalModelsPrivate.h\"\n#import \"TXMasterControllerPrivate.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TXWindowControllerPrivate.h\"\n#import \"TVCDockIconPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.h\"\n#import \"TVCLogControllerOperationQueuePrivate.h\"\n#import \"TVCLogRenderer.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowTextViewPrivate.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TDCChannelBanListSheetPrivate.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n#import \"TDCFileTransferDialogTransferControllerPrivate.h\"\n#import \"TDCServerChannelListDialogPrivate.h\"\n#import \"TDCServerHighlightListSheetPrivate.h\"\n#import \"IRC.h\"\n#import \"IRCAddressBook.h\"\n#import \"IRCAddressBookMatchCachePrivate.h\"\n#import \"IRCAddressBookUserTrackingPrivate.h\"\n#import \"IRCChannelConfig.h\"\n#import \"IRCChannelModePrivate.h\"\n#import \"IRCChannelUserPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCClientConfigPrivate.h\"\n#import \"IRCClientRequestedCommandsPrivate.h\"\n#import \"IRCColorFormatPrivate.h\"\n#import \"IRCConnectionPrivate.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCConnectionErrors.h\"\n#import \"IRCExtrasPrivate.h\"\n#import \"IRCHighlightLogEntryPrivate.h\"\n#import \"IRCHighlightMatchCondition.h\"\n#import \"IRCISupportInfoPrivate.h\"\n#import \"IRCMessagePrivate.h\"\n#import \"IRCMessageBatchPrivate.h\"\n#import \"IRCModeInfo.h\"\n#import \"IRCNumerics.h\"\n#import \"IRCSendingMessage.h\"\n#import \"IRCServerPrivate.h\"\n#import \"IRCTimerCommandPrivate.h\"\n#import \"IRCTreeItemPrivate.h\"\n#import \"IRCUserPrivate.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"IRCClientPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _autojoinDelayedWarningInterval\t\t90 // max delay after identification is 10 so keep this above that\n#define _autojoinDelayedWarningMaxCount\t\t3\n\n#define _isonCheckInterval\t\t\t30\n#define _pingInterval\t\t\t\t270\n#define _pongCheckInterval\t\t\t30\n#define _reconnectInterval\t\t\t20\n#define _retryInterval\t\t\t\t240\n#define _timeoutInterval\t\t\t360\n#define _whoCheckInterval\t\t\t120\n\nNSString * const IRCClientConfigurationWasUpdatedNotification = @\"IRCClientConfigurationWasUpdatedNotification\";\n\nNSString * const IRCClientChannelListWasModifiedNotification = @\"IRCClientChannelListWasModifiedNotification\";\n\nNSString * const IRCClientWillConnectNotification = @\"IRCClientWillConnectNotification\";\nNSString * const IRCClientDidConnectNotification = @\"IRCClientDidConnectNotification\";\n\nNSString * const IRCClientWillSendQuitNotification = @\"IRCClientWillSendQuitNotification\";\nNSString * const IRCClientWillDisconnectNotification = @\"IRCClientWillDisconnectNotification\";\nNSString * const IRCClientDidDisconnectNotification = @\"IRCClientDidDisconnectNotification\";\n\nNSString * const IRCClientUserNicknameChangedNotification = @\"IRCClientUserNicknameChangedNotification\";\n\n@interface IRCClient ()\n// Properties that are public in IRCClient.h\n@property (nonatomic, copy, readwrite) IRCClientConfig *config;\n@property (nonatomic, copy, readwrite, nullable) IRCServer *server;\n@property (nonatomic, strong, readwrite) IRCISupportInfo *supportInfo;\n@property (nonatomic, assign, readwrite) BOOL isAutojoined;\n@property (nonatomic, assign, readwrite) BOOL isAutojoining;\n@property (nonatomic, assign, readwrite) BOOL isConnecting;\n@property (nonatomic, assign, readwrite) BOOL isConnected;\n@property (nonatomic, assign, readwrite) BOOL isConnectedToZNC;\n@property (nonatomic, assign, readwrite) BOOL isLoggedIn;\n@property (nonatomic, assign, readwrite) BOOL isQuitting;\n@property (nonatomic, assign, readwrite) BOOL isDisconnecting;\n@property (nonatomic, assign, readwrite) BOOL isReconnecting;\n@property (nonatomic, assign, readwrite) BOOL isSecured;\n@property (nonatomic, assign, readwrite) BOOL userIsAway;\n@property (nonatomic, assign, readwrite) BOOL userIsIRCop;\n@property (nonatomic, assign, readwrite) BOOL userIsIdentifiedWithNickServ;\n@property (nonatomic, assign, readwrite) BOOL isWaitingForNickServ;\n@property (nonatomic, assign, readwrite) BOOL serverHasNickServ;\n@property (nonatomic, assign, readwrite) NSTimeInterval lastMessageReceived;\n@property (nonatomic, assign, readwrite) NSTimeInterval lastMessageServerTime;\n@property (nonatomic, assign, readwrite) ClientIRCv3SupportedCapability capabilities;\n@property (nonatomic, copy, readwrite) NSArray<IRCHighlightLogEntry *> *cachedHighlights;\n@property (nonatomic, copy, readwrite, nullable) NSString *userHostmask;\n@property (nonatomic, copy, readwrite) NSString *userNickname;\n@property (nonatomic, copy, readwrite) NSString *serverAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *preAwayUserNickname;\n@property (nonatomic, assign, readwrite) NSUInteger logFileSessionCount;\n\n// Properties private\n@property (nonatomic, assign) BOOL configurationIsStale;\n@property (nonatomic, strong, nullable) IRCConnection *socket;\n@property (nonatomic, strong) IRCMessageBatchMessageContainer *batchMessages;\n@property (nonatomic, strong, nullable) TLOFileLogger *logFile;\n@property (nonatomic, strong) TLOTimer *autojoinTimer;\n@property (nonatomic, strong) TLOTimer *autojoinNextJoinTimer;\n@property (nonatomic, strong) TLOTimer *autojoinDelayedWarningTimer;\n@property (nonatomic, strong) TLOTimer *isonTimer;\n@property (nonatomic, strong) TLOTimer *pongTimer;\n@property (nonatomic, strong) TLOTimer *reconnectTimer;\n@property (nonatomic, strong) TLOTimer *retryTimer;\n@property (nonatomic, strong) TLOTimer *whoTimer;\n@property (nonatomic, assign) BOOL capabilityNegotiationIsPaused;\n@property (nonatomic, assign) BOOL invokingISONCommandForFirstTime;\n@property (nonatomic, assign) BOOL isTerminating; // Is being destroyed\n@property (nonatomic, assign) BOOL inWhoisResponse;\n@property (nonatomic, assign) BOOL inWhowasResponse;\n@property (nonatomic, assign) BOOL reconnectEnabled;\n@property (nonatomic, assign) BOOL reconnectEnabledBecauseOfSleepMode;\n@property (nonatomic, assign) BOOL timeoutWarningShownToUser;\n@property (nonatomic, assign) BOOL zncBouncerIsSendingCertificateInfo;\n@property (nonatomic, assign) BOOL zncBouncerIsPlayingBackHistory;\n@property (nonatomic, strong) NSMutableArray<NSNumber *> *capabilitiesPending;\n@property (nonatomic, assign) NSUInteger connectDelay;\n@property (nonatomic, assign) NSUInteger lastServerSelected;\n@property (nonatomic, assign) NSUInteger lastWhoRequestChannelListIndex;\n@property (nonatomic, assign) NSUInteger successfulConnects;\n@property (nonatomic, assign) NSUInteger tryingNicknameNumber;\n@property (nonatomic, assign) NSUInteger autojoinDelayedWarningCount;\n@property (nonatomic, copy, nullable) NSString *tryingNicknameSentNickname;\n@property (nonatomic, strong) NSMutableArray<IRCChannel *> *channelListPrivate;\n@property (nonatomic, strong, nullable) NSMutableArray<IRCChannel *> *channelsToAutojoin;\n@property (nonatomic, strong) IRCAddressBookMatchCache *addressBookMatchCache;\n@property (nonatomic, strong) IRCAddressBookUserTrackingContainer *trackedUsers;\n@property (nonatomic, strong) IRCClientRequestedCommands *requestedCommands;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, IRCTimedCommand *> *timedCommands;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, IRCUser *> *userListPrivate;\n@property (nonatomic, strong, nullable) NSMutableString *zncBouncerCertificateChainDataMutable;\n@property (nonatomic, copy, nullable) NSString *temporaryServerAddressOverride;\n@property (nonatomic, assign) uint16_t temporaryServerPortOverride;\n@property (readonly) BOOL isBrokenIRCd_aka_Twitch;\n@property (readonly) BOOL monitorAwayStatus;\n@property (readonly) BOOL supportsAdvancedTracking;\n@property (readonly, copy) NSArray<NSString *> *nickServSupportedNeedIdentificationTokens;\n@property (readonly, copy) NSArray<NSString *> *nickServSupportedSuccessfulIdentificationTokens;\n@property (nonatomic, strong, nullable) IRCChannel *rawDataLogQuery;\n@property (nonatomic, strong, nullable) IRCChannel *hiddenCommandResponsesQuery;\n@end\n\n@implementation IRCClient\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfigDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tIRCClientConfig *config = [[IRCClientConfig alloc] initWithDictionary:dic];\n\n\treturn [self initWithConfig:config];\n}\n\n- (instancetype)initWithConfig:(IRCClientConfig *)config\n{\n\tNSParameterAssert(config != nil);\n\n\tif ((self = [super init])) {\n\t\tself.config = config;\n\n\t\t[self writePasswordsToKeychain];\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.batchMessages = [IRCMessageBatchMessageContainer new];\n\n\tself.supportInfo = [[IRCISupportInfo alloc] initWithClient:self];\n\n\tself.connectType = IRCClientConnectModeNormal;\n\tself.disconnectType = IRCClientDisconnectModeNormal;\n\n\tself.cachedHighlights = @[];\n\n\tself.capabilitiesPending = [NSMutableArray array];\n\n\tself.channelListPrivate = [NSMutableArray array];\n\n\tself.timedCommands = [NSMutableDictionary dictionary];\n\n\tself.userListPrivate = [NSMutableDictionary dictionary];\n\n\tself.addressBookMatchCache = [[IRCAddressBookMatchCache alloc] initWithClient:self];\n\t\n\tself.trackedUsers = [[IRCAddressBookUserTrackingContainer alloc] initWithClient:self];\n\n\tself.requestedCommands = [IRCClientRequestedCommands new];\n\n\tself.lastMessageServerTime = self.config.lastMessageServerTime;\n\n\tself.lastServerSelected = NSNotFound;\n\n\tself.autojoinTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onAutojoinTimer];\n\t}];\n\n\tself.autojoinNextJoinTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onAutojoinNextJoinTimer];\n\t}];\n\n\tself.autojoinDelayedWarningTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onAutojoinDelayedWarningTimer];\n\t}];\n\n\tself.isonTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onISONTimer];\n\t}];\n\n\tself.reconnectTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onReconnectTimer];\n\t}];\n\n\tself.retryTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onRetryTimer];\n\t}];\n\n\tself.pongTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onPongTimer];\n\t}];\n\n\tself.whoTimer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t[self onWhoTimer];\n\t}];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(willDestroyChannel:) name:IRCWorldWillDestroyChannelNotification object:nil];\n}\n\n- (void)dealloc\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\t[self.autojoinTimer stop];\n\t[self.autojoinNextJoinTimer stop];\n\t[self.autojoinDelayedWarningTimer stop];\n\t[self.isonTimer\tstop];\n\t[self.pongTimer\tstop];\n\t[self.reconnectTimer stop];\n\t[self.retryTimer stop];\n\t[self.whoTimer stop];\n\n\tself.autojoinTimer = nil;\n\tself.autojoinNextJoinTimer = nil;\n\tself.autojoinDelayedWarningTimer = nil;\n\tself.isonTimer = nil;\n\tself.pongTimer = nil;\n\tself.reconnectTimer = nil;\n\tself.retryTimer = nil;\n\tself.whoTimer = nil;\n\n\tself.addressBookMatchCache = nil;\n\tself.batchMessages = nil;\n\tself.cachedHighlights = nil;\n\tself.channelListPrivate = nil;\n\tself.channelsToAutojoin = nil;\n\tself.logFile = nil;\n\tself.socket = nil;\n\tself.supportInfo = nil;\n\tself.timedCommands = nil;\n\tself.trackedUsers = nil;\n\tself.requestedCommands = nil;\n\tself.userListPrivate = nil;\n\n\t[self cancelPerformRequests];\n}\n\n- (void)updateConfig:(IRCClientConfig *)config\n{\n\t[self updateConfig:config updateSelection:YES];\n}\n\n- (void)updateConfig:(IRCClientConfig *)config updateSelection:(BOOL)updateSelection\n{\n\tNSParameterAssert(config != nil);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tIRCClientConfig *currentConfig = self.config;\n\n\tif ([currentConfig isEqual:config]) {\n\t\treturn;\n\t}\n\n\tif ([currentConfig.uniqueIdentifier isEqualToString:config.uniqueIdentifier] == NO) {\n\t\tLogToConsoleError(\"Tried to load configuration for incorrect client\");\n\n\t\treturn;\n\t}\n\n\tself.config = config;\n\n\t/* Update channel list */\n\t{\n\t\tNSMutableArray<IRCChannel *> *channelListOld = [self.channelList mutableCopy];\n\n\t\tNSMutableArray<IRCChannel *> *channelListNew = [NSMutableArray array];\n\n\t\tNSMutableArray<NSString *> *channelListNewNames = [NSMutableArray array];\n\n\t\tNSArray *channelConfigurations = self.config.channelList;\n\n\t\tfor (IRCChannelConfig *channelConfig in channelConfigurations) {\n\t\t\t/* Block duplicate channel names by maintaining array of names */\n\t\t\tNSString *channelName = channelConfig.channelName;\n\n\t\t\tif ([channelListNewNames containsObject:channelName] == NO) {\n\t\t\t\t[channelListNewNames addObject:channelName];\n\t\t\t} else {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Check whether the channel exists in the current list of channels */\n\t\t\t/* If it does not exist, then create it. Otherwise, update it. */\n\t\t\tIRCChannel *channel = [self findChannel:channelConfig.channelName inList:channelListOld];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tchannel = [worldController() createChannelWithConfig:channelConfig onClient:self add:NO adjust:NO reload:NO];\n\t\t\t} else {\n\t\t\t\t[channel updateConfig:channelConfig fireChangedNotification:NO updateStoredChannelList:NO];\n\n\t\t\t\t[channelListOld removeObjectIdenticalTo:channel];\n\t\t\t}\n\n\t\t\t[channelListNew addObject:channel];\n\t\t}\n\n\t\t/* Any channels left in the old array can be destroyed \n\t\t or if they are not a channel, then they can be reinserted\n\t\t because we do not care about private messages being updated\n\t\t above so they must be reinserted here. */\n\t\tfor (IRCChannel *channel in channelListOld) {\n\t\t\tif (channel.isChannel == NO) {\n\t\t\t\t[channelListNew addObject:channel];\n\t\t\t} else {\n\t\t\t\t[worldController() destroyChannel:channel reload:NO];\n\t\t\t}\n\t\t}\n\n\t\t/* Save updated channel list then safe its contents */\n\t\tself.channelList = channelListNew;\n\t}\n\n\t/* Update server list */\n\t{\n\t\t/* To update the server list, we first make a map of all existing\n\t\t servers in a dictionary with the key as the identifier and the\n\t\t object is the server itself. */\n\t\tNSArray *serverListOld = currentConfig.serverList;\n\n\t\tNSMutableDictionary<NSString *, IRCServer *> *serverListOldMap =\n\t\t[[NSMutableDictionary alloc] initWithCapacity:serverListOld.count];\n\n\t\tfor (IRCServer *server in serverListOld) {\n\t\t\tserverListOldMap[server.uniqueIdentifier] = server;\n\t\t}\n\n\t\t/* We then make a map of the new server list */\n\t\tNSArray *serverListNew = self.config.serverList;\n\n\t\tNSMutableDictionary<NSString *, IRCServer *> *serverListNewMap =\n\t\t[[NSMutableDictionary alloc] initWithCapacity:serverListNew.count];\n\n\t\tfor (IRCServer *server in serverListNew) {\n\t\t\tserverListNewMap[server.uniqueIdentifier] = server;\n\t\t}\n\n\t\t/* Record information about the current server (if any). */\n\t\tIRCServer *serverInUse = self.server;\n\n\t\tNSString *uniqueIdentifierInUse = serverInUse.uniqueIdentifier;\n\n\t\t/* Enumerate old server list */\n\t\t/* If an old server no longer appears in the new list of identifiers,\n\t\t then we destroy its keychain items. If the server is the active server,\n\t\t then we mark the keychain items to be destroyed later, incase they\n\t\t need to be reused by IRCClient. */\n\t\t[serverListOldMap enumerateKeysAndObjectsUsingBlock:^(NSString *uniqueIdentifier, IRCServer *server, BOOL *stop) {\n\t\t\tif ([serverListNewMap containsKey:uniqueIdentifier]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ([uniqueIdentifier isEqualToString:uniqueIdentifierInUse]) {\n\t\t\t\tserverInUse.destroyKeychainItemsDuringDealloc = YES;\n\t\t\t} else {\n\t\t\t\t[server destroyServerPasswordKeychainItem];\n\t\t\t}\n\t\t}];\n\n\t\t/* Enumerate new server list */\n\t\t/* All servers in the new server list have their keychain item written. */\n\t\tif (serverListNew.count == 0) {\n\t\t\tself.lastServerSelected = NSNotFound;\n\t\t} else {\n\t\t\t[serverListNewMap enumerateKeysAndObjectsUsingBlock:^(NSString *uniqueIdentifier, IRCServer *server, BOOL *stop) {\n\t\t\t\t[server writeServerPasswordToKeychain];\n\t\t\t}];\n\t\t}\n\t}\n\n\t/* -reloadItem will drop the views and reload them. */\n\t/* We need to remember the selection because of this. */\n\tif (updateSelection) {\n\t\t[self reloadServerListItems];\n\t}\n\n\t/* Update navigation list */\n\t[menuController() populateNavigationChannelList];\n\n\t/* Write passwords to keychain */\n\t[self writePasswordsToKeychain];\n\n\t[self destroyServerPasswordKeychainItemAfterMigration];\n\n\t/* Update main window title */\n\t[mainWindow() updateTitleFor:self];\n\n\t/* Rebuild list of users that are ignored and/or tracked */\n\t[self clearAddressBookCache];\n\n\t[self populateISONTrackedUsersList];\n\n\t/* Post notification */\n\t[RZNotificationCenter() postNotificationName:IRCClientConfigurationWasUpdatedNotification object:self];\n}\n\n- (void)reloadServerListItems\n{\n\tmainWindow().ignoreOutlineViewSelectionChanges = YES;\n\n\t[mainWindowServerList() beginUpdates];\n\n\t[mainWindowServerList() reloadItem:self reloadChildren:YES];\n\n\t[mainWindowServerList() endUpdates];\n\n\t[mainWindow() adjustSelection];\n\n\tmainWindow().ignoreOutlineViewSelectionChanges = NO;\n}\n\n- (void)writePasswordsToKeychain\n{\n\t[self.config writeNicknamePasswordToKeychain];\n\t[self.config writeProxyPasswordToKeychain];\n}\n\n- (void)destroyServerPasswordKeychainItemAfterMigration\n{\n\t[self.config destroyServerPasswordKeychainItemAfterMigration];\n}\n\n- (void)updateStoredConfiguration\n{\n\tif (self.configurationIsStale == NO) {\n\t\treturn;\n\t}\n\n\tIRCClientConfigMutable *configMutable = [self.config mutableCopy];\n\n\tconfigMutable.lastMessageServerTime = self.lastMessageServerTime;\n\n\tconfigMutable.sidebarItemExpanded = self.sidebarItemIsExpanded;\n\n\tself.config = configMutable;\n}\n\n- (void)updateStoredChannelList\n{\n\t/* Rebuild list of channel configurations */\n\tNSMutableArray<IRCChannelConfig *> *channelList = [NSMutableArray array];\n\n\tfor (IRCChannel *channel in self.channelList) {\n\t\tif (channel.isUtility) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (channel.isChannel == NO && [TPCPreferences rememberServerListQueryStates] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[channelList addObject:channel.config];\n\t}\n\n\t/* Save list */\n\tIRCClientConfigMutable *mutableConfig = [self.config mutableCopy];\n\n\tmutableConfig.channelList = channelList;\n\n\tself.config = mutableConfig;\n\n\t/* Post notification */\n\t[RZNotificationCenter() postNotificationName:IRCClientChannelListWasModifiedNotification object:self];\n}\n\n- (NSDictionary<NSString *, id> *)configurationDictionary\n{\n\t[self updateStoredConfiguration];\n\n\treturn [self.config dictionaryValue];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tself.isTerminating = YES;\n\n\tLogToConsoleTerminationProgress(\"Preparing client: <%{public}@>\", self.uniqueIdentifier);\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Closing dialogs\", self.uniqueIdentifier);\n\n\t[self closeDialogs];\n\n\tif (self.isConnecting || self.isConnected) {\n\t\tLogToConsoleTerminationProgress(\"[%{public}@] Performing disconnect\", self.uniqueIdentifier);\n\n\t\t__weak IRCClient *weakSelf = self;\n\n\t\tself.disconnectCallback = ^{\n\t\t\t[weakSelf prepareForApplicationTerminationPostflight];\n\t\t};\n\n\t\t[self quit];\n\n\t\treturn;\n\t}\n\n\t[self prepareForApplicationTerminationPostflight];\n}\n\n- (void)prepareForApplicationTerminationPostflight\n{\n\tLogToConsoleTerminationProgress(\"[%{public}@] Closing log file\", self.uniqueIdentifier);\n\n\t[self closeLogFile];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Removing unspoken messages from speech synthesizer\", self.uniqueIdentifier);\n\n\t[self clearEventsToSpeak];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Emptying Address Book cache\", self.uniqueIdentifier);\n\n\t[self clearAddressBookCache];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Removing all tracked users\", self.uniqueIdentifier);\n\n\t[self clearTrackedUsers];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Preparing channels: %{public}ld\", self.uniqueIdentifier, self.channelCount);\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\t[c prepareForApplicationTermination];\n\t}\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Preparing view controller: <%{public}@>\",\n\t\t\t\t\tself.uniqueIdentifier, self.viewController.uniqueIdentifier);\n\n\t[self.viewController prepareForApplicationTermination];\n\n\tLogToConsoleTerminationProgress(\"[%{public}@] Decrementing client count\", self.uniqueIdentifier);\n\n\tmasterController().terminatingClientCount -= 1;\n}\n\n- (void)prepareForPermanentDestruction\n{\n\tself.isTerminating = YES;\n\n//\t[self disconnect];\t// Disconnect is called by IRCWorld for us\n\n\t[self closeDialogs];\n\n\t[self closeLogFile];\n\n\t[self clearEventsToSpeak];\n\t\n\t[self clearAddressBookCache];\n\n\t[self clearTrackedUsers];\n\n\t[self.config destroyNicknamePasswordKeychainItem];\n\t[self.config destroyProxyPasswordKeychainItem];\n\n\t[self destroyServerPasswordsKeychainItems];\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\t[c prepareForPermanentDestruction];\n\t}\n\n\t[[mainWindow() inputHistoryManager] destroy:self];\n\n\t[self.viewController prepareForPermanentDestruction];\n}\n\n- (void)closeDialogs\n{\n\tTDCServerChannelListDialog *channelListDialog = [self channelListDialog];\n\n\tif (channelListDialog) {\n\t\t[channelListDialog close];\n\t}\n\n\tNSArray *openWindows =\n\t[windowController() windowsFromWindowList:@[@\"TDCChannelInviteSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCServerChangeNicknameSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCServerHighlightListSheet\",\n\t\t\t\t\t\t\t\t\t\t\t\t@\"TDCServerPropertiesSheet\"]];\n\n\tfor (TDCSheetBase <TDCClientPrototype> *windowObject in openWindows) {\n\t\tif ([windowObject.clientId isEqualToString:self.uniqueIdentifier]) {\n\t\t\t[windowObject close];\n\t\t}\n\t}\n}\n\n- (void)preferencesChanged\n{\n\tfor (IRCChannel *c in self.channelList) {\n\t\t[c preferencesChanged];\n\t}\n\n\tif (self.monitorAwayStatus == NO) {\n\t\t[self resetAwayStatusForUsers];\n\t}\n}\n\n- (void)willDestroyChannel:(NSNotification *)notification\n{\n\tIRCChannel *channel = notification.object;\n\n\tif (channel.associatedClient != self) {\n\t\treturn;\n\t}\n\n\t[self zncPlaybackClearChannel:channel];\n\n\tif (self.hiddenCommandResponsesQuery == channel) {\n\t\tself.hiddenCommandResponsesQuery = channel;\n\t}\n\n\tif (self.rawDataLogQuery == channel) {\n\t\tself.rawDataLogQuery = nil;\n\t}\n}\n\n- (id)copyWithZone:(nullable NSZone *)zone\n{\n\t/* Implement this method to allow client to be\n\t used as a dictionary key. */\n\n\treturn self;\n}\n\n#pragma mark -\n#pragma mark Servers\n\n- (void)enumerateServers:(void (NS_NOESCAPE ^)(IRCServer *server, NSUInteger index, BOOL *stop))block\n{\n\t[self.config.serverList enumerateObjectsUsingBlock:block];\n}\n\n- (void)writeServerPasswordsToKeychain\n{\n\t[self enumerateServers:^(IRCServer *server, NSUInteger index, BOOL *stop) {\n\t\t[server writeServerPasswordToKeychain];\n\t}];\n}\n\n- (void)destroyServerPasswordsKeychainItems\n{\n\t[self enumerateServers:^(IRCServer *server, NSUInteger index, BOOL *stop) {\n\t\t[server destroyServerPasswordKeychainItem];\n\t}];\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (NSString *)description\n{\n\treturn [NSString stringWithFormat:@\"<IRCClient [%@]: %@>\", self.networkNameAlt, self.serverAddress];\n}\n\n- (NSString *)uniqueIdentifier\n{\n\treturn self.config.uniqueIdentifier;\n}\n\n- (NSString *)name\n{\n\treturn self.config.connectionName;\n}\n\n- (nullable NSString *)networkName\n{\n\treturn self.supportInfo.networkNameFormatted;\n}\n\n- (NSString *)networkNameAlt\n{\n\tNSString *networkName = self.networkName;\n\n\tif (networkName) {\n\t\treturn networkName;\n\t}\n\n\treturn self.config.connectionName;\n}\n\n- (nullable NSString *)serverAddress\n{\n\tNSString *serverAddress = self.supportInfo.serverAddress;\n\n\tif (serverAddress) {\n\t\treturn serverAddress;\n\t}\n\n\tNSString *serverAddressOnSocket = self.socket.config.serverAddress;\n\n\tif (serverAddressOnSocket) {\n\t\treturn serverAddressOnSocket;\n\t}\n\n\treturn self.server.serverAddress;\n}\n\n- (NSString *)userNickname\n{\n\tNSString *userNickname = self->_userNickname;\n\n\tif (userNickname) {\n\t\treturn userNickname;\n\t}\n\n\treturn self.config.nickname;\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (NSString *)encryptionAccountNameForLocalUser\n{\n\treturn [sharedEncryptionManager() accountNameForUser:self.userNickname onClient:self];\n}\n\n- (NSString *)encryptionAccountNameForUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\treturn [sharedEncryptionManager() accountNameForUser:nickname onClient:self];\n}\n#endif\n\n- (TDCFileTransferDialog *)fileTransferController\n{\n\treturn [TXSharedApplication sharedFileTransferDialog];\n}\n\n- (BOOL)isReconnecting\n{\n\treturn self.reconnectTimer.timerIsActive;\n}\n\n- (void)setSidebarItemIsExpanded:(BOOL)sidebarItemIsExpanded\n{\n\t/* This is a non-critical property that can be saved periodically */\n\tif (self->_sidebarItemIsExpanded != sidebarItemIsExpanded) {\n\t\tself->_sidebarItemIsExpanded = sidebarItemIsExpanded;\n\n\t\tself.configurationIsStale = YES;\n\n\t\t[worldController() savePeriodically];\n\t}\n}\n\n- (void)setLastMessageServerTime:(NSTimeInterval)lastMessageServerTime\n{\n\t/* This is a non-critical property that can be saved periodically */\n\tif (self->_lastMessageServerTime != lastMessageServerTime) {\n\t\tself->_lastMessageServerTime = lastMessageServerTime;\n\n\t\tself.configurationIsStale = YES;\n\n\t\t[worldController() savePeriodically];\n\t}\n}\n\n- (BOOL)isSecured\n{\n\tif (self.socket) {\n\t\treturn self.socket.isSecured;\n\t}\n\n\treturn NO;\n}\n\n- (nullable NSData *)zncBouncerCertificateChainData\n{\n\t/* If the data is still being processed, then return\n\t nil so that partial data is not returned. */\n\tif (self.isConnectedToZNC == NO ||\n\t\tself.zncBouncerIsSendingCertificateInfo ||\n\t\tself.zncBouncerCertificateChainDataMutable == nil)\n\t{\n\t\treturn nil;\n\t}\n\n\treturn [self.zncBouncerCertificateChainDataMutable dataUsingEncoding:NSASCIIStringEncoding];\n}\n\n- (BOOL)isBrokenIRCd_aka_Twitch\n{\n\treturn [self.serverAddress hasSuffix:@\".twitch.tv\"];\n}\n\n- (BOOL)supportsAdvancedTracking\n{\n\treturn ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityMonitorCommand] ||\n\t\t\t[self isCapabilityEnabled:ClientIRCv3SupportedCapabilityWatchCommand]);\n}\n\n- (BOOL)monitorAwayStatus\n{\n\treturn ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityAwayNotify] ||\n\t\t\t[TPCPreferences trackUserAwayStatusMaximumChannelSize] > 0);\n}\n\n- (nullable TVCLogLine *)lastLine\n{\n\treturn self.viewController.lastLine;\n}\n\n#pragma mark -\n#pragma mark Standalone Utilities\n\n- (BOOL)messageIsFromMyself:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\treturn [self nicknameIsMyself:message.senderNickname];\n}\n\n- (BOOL)nicknameIsMyself:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\treturn [self.userNickname isEqualToStringIgnoringCase:nickname];\n}\n\n- (BOOL)stringIsNickname:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\treturn ([string isHostmaskNicknameOn:self] && [string isChannelNameOn:self] == NO);\n}\n\n- (BOOL)stringIsChannelName:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\treturn [string isChannelNameOn:self];\n}\n\n- (BOOL)stringIsChannelNameOrZero:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\treturn ([self stringIsChannelName:string] || [string isEqualToString:@\"0\"]);\n}\n\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString\n{\n\treturn [self compileListOfModeChangesForModeSymbol:modeSymbol modeIsSet:modeIsSet parameterString:parameterString characterSet:[NSCharacterSet whitespaceCharacterSet]];\n}\n\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet parameterString:(NSString *)parameterString characterSet:(NSCharacterSet *)characterList\n{\n\tNSParameterAssert(parameterString != nil);\n\tNSParameterAssert(characterList != nil);\n\n\tNSArray *modeParameters = [parameterString componentsSeparatedByCharactersInSet:characterList];\n\n\treturn [self compileListOfModeChangesForModeSymbol:modeSymbol modeIsSet:modeIsSet modeParameters:modeParameters];\n}\n\n- (NSArray<NSString *> *)compileListOfModeChangesForModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameters:(NSArray<NSString *> *)modeParameters\n{\n\tNSParameterAssert(modeSymbol.length == 1);\n\tNSParameterAssert(modeParameters != nil);\n\n\tif (modeParameters.count == 0) {\n\t\treturn @[];\n\t}\n\n\tNSMutableArray<NSString *> *listOfChanges = [NSMutableArray array];\n\n\tNSMutableString *modeSetString = [NSMutableString string];\n\tNSMutableString *modeParamString = [NSMutableString string];\n\n\tNSUInteger numberOfEntries = 0;\n\n\tfor (NSString *modeParameter in modeParameters) {\n\t\tif (modeParameter.length == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (modeSetString.length == 0) {\n\t\t\tif (modeIsSet) {\n\t\t\t\t[modeSetString appendFormat:@\"+%@\", modeSymbol];\n\t\t\t} else {\n\t\t\t\t[modeSetString appendFormat:@\"-%@\", modeSymbol];\n\t\t\t}\n\t\t} else {\n\t\t\t[modeSetString appendString:modeSymbol];\n\t\t}\n\n\t\t[modeParamString appendFormat:@\" %@\", modeParameter];\n\n\t\tnumberOfEntries += 1;\n\n\t\tif (numberOfEntries == self.supportInfo.maximumModeCount) {\n\t\t\tnumberOfEntries = 0;\n\n\t\t\tNSString *modeSetCombined = [modeSetString stringByAppendingString:modeParamString];\n\n\t\t\t[listOfChanges addObject:modeSetCombined];\n\n\t\t\t[modeSetString setString:@\"\"];\n\t\t\t[modeParamString setString:@\"\"];\n\t\t}\n\t}\n\n\tif (modeSetString.length > 0 && modeParamString.length > 0) {\n\t\tNSString *modeSetCombined = [modeSetString stringByAppendingString:modeParamString];\n\n\t\t[listOfChanges addObject:modeSetCombined];\n\t}\n\n\treturn [listOfChanges copy];\n}\n\n- (void)separateTargetsInString:(NSString *)targetString withCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<NSString *> *targets))completionBlock\n{\n\tNSParameterAssert(targetString != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSArray *targets = [targetString componentsSeparatedByString:@\",\"];\n\n\tcompletionBlock(targets);\n}\n\n- (void)enumerateTargetsInString:(NSString *)targetString withBlock:(void (^)(NSString *target, NSUInteger atIndex, NSUInteger ofTotal, BOOL *stop))block\n{\n\tNSParameterAssert(targetString != nil);\n\tNSParameterAssert(block != nil);\n\n\tNSArray *targets = [targetString componentsSeparatedByString:@\",\"];\n\n\tNSUInteger targetsCount = targets.count;\n\n\t[targets enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {\n\t\tblock(object, index, targetsCount, stop);\n\t}];\n}\n\n#pragma mark -\n#pragma mark Highlights\n\n- (void)clearCachedHighlights\n{\n\tself.cachedHighlights = @[];\n}\n\n- (void)cacheHighlightInChannel:(IRCChannel *)channel withLogLine:(TVCLogLine *)logLine\n{\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(logLine != nil);\n\n\tif ([TPCPreferences logHighlights] == NO) {\n\t\treturn;\n\t}\n\n\t/* Create entry */\n\tIRCHighlightLogEntryMutable *newEntry = [IRCHighlightLogEntryMutable new];\n\n\tnewEntry.clientId = self.uniqueIdentifier;\n\tnewEntry.channelId = channel.uniqueIdentifier;\n\n\tnewEntry.lineLogged = logLine;\n\n\t/* We insert at head so that latest is always on top. */\n\tNSMutableArray *cachedHighlights = [self.cachedHighlights mutableCopy];\n\n\t[cachedHighlights insertObject:[newEntry copy] atIndex:0];\n\n\tself.cachedHighlights = cachedHighlights;\n\n\t/* Reload table if the window is open. */\n\tTDCServerHighlightListSheet *highlightListSheet = [windowController() windowFromWindowList:@\"TDCServerHighlightListSheet\"];\n\n\tif ([highlightListSheet.clientId isEqualToString:self.uniqueIdentifier] == NO) {\n\t\treturn;\n\t}\n\n\t[highlightListSheet addEntry:self.cachedHighlights.firstObject];\n}\n\n#pragma mark -\n#pragma mark Reachability\n\n- (void)noteReachabilityChanged:(BOOL)reachable\n{\n\tif (reachable) {\n\t\treturn;\n\t}\n\n\t[self disconnectOnReachabilityChange];\n}\n\n- (void)disconnectOnReachabilityChange\n{\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (self.config.performDisconnectOnReachabilityChange == NO) {\n\t\treturn;\n\t}\n\n\tself.disconnectType = IRCClientDisconnectModeReachabilityChange;\n\n\tself.reconnectEnabled = YES;\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self disconnect];\n\t});\n}\n\n#pragma mark -\n#pragma mark Channel Storage\n\n- (void)selectFirstChannelInChannelList\n{\n\tNSArray *channelList = self.channelList;\n\n\tif (channelList.count == 0) {\n\t\treturn;\n\t}\n\n\t[mainWindow() select:channelList[0]];\n}\n\n- (void)addChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t@synchronized(self.channelListPrivate) {\n\t\tif ([self.channelListPrivate containsObject:channel]) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* Add channels atop of the first non-channel (private message).\n\t\t Private messages can be add to the bottom of the array. */\n\t\tif (channel.isChannel == NO)\n\t\t{\n\t\t\t[self.channelListPrivate addObject:channel];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSUInteger privateMessageIndex =\n\t\t\t[self.channelListPrivate indexOfObjectPassingTest:^BOOL(IRCChannel *object, NSUInteger index, BOOL *stop) {\n\t\t\t\treturn (object.isChannel == NO);\n\t\t\t}];\n\n\t\t\tif (privateMessageIndex == NSNotFound) {\n\t\t\t\t[self.channelListPrivate addObject:channel];\n\t\t\t} else {\n\t\t\t\t[self.channelListPrivate insertObject:channel atIndex:privateMessageIndex];\n\t\t\t}\n\t\t}\n\n\t\t[self updateStoredChannelList];\n\t}\n}\n\n- (void)addChannel:(IRCChannel *)channel atPosition:(NSUInteger)position\n{\n\tNSParameterAssert(channel != nil);\n\n\t@synchronized(self.channelListPrivate) {\n\t\tif ([self.channelListPrivate containsObject:channel]) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.channelListPrivate insertObject:channel atIndex:position];\n\n\t\t[self updateStoredChannelList];\n\t}\n}\n\n- (void)removeChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t@synchronized(self.channelListPrivate) {\n\t\t[self.channelListPrivate removeObjectIdenticalTo:channel];\n\n\t\t[self updateStoredChannelList];\n\t}\n}\n\n- (NSUInteger)indexOfChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t@synchronized (self.channelListPrivate) {\n\t\treturn [self.channelListPrivate indexOfObject:channel];\n\t}\n}\n\n- (NSUInteger)channelCount\n{\n\t@synchronized (self.channelListPrivate) {\n\t\treturn self.channelListPrivate.count;\n\t}\n}\n\n- (NSArray<IRCChannel *> *)channelList\n{\n\t@synchronized (self.channelListPrivate) {\n\t\treturn [self.channelListPrivate copy];\n\t}\n}\n\n- (void)setChannelList:(NSArray<IRCChannel *> *)channelList\n{\n\tNSParameterAssert(channelList != nil);\n\n\t@synchronized (self.channelListPrivate) {\n\t\t[self.channelListPrivate removeAllObjects];\n\n\t\t[self.channelListPrivate addObjectsFromArray:channelList];\n\n\t\t[self updateStoredChannelList];\n\t}\n}\n\n#pragma mark -\n#pragma mark IRCTreeItem\n\n- (BOOL)isClient\n{\n\treturn YES;\n}\n\n- (BOOL)isActive\n{\n\treturn self.isLoggedIn;\n}\n\n- (nullable IRCClient *)associatedClient\n{\n\treturn self;\n}\n\n- (nullable IRCChannel *)associatedChannel\n{\n\treturn nil;\n}\n\n- (NSUInteger)numberOfChildren\n{\n\treturn self.channelCount;\n}\n\n- (nullable id)childAtIndex:(NSUInteger)index\n{\n\treturn self.channelList[index];\n}\n\n- (NSString *)label\n{\n\treturn self.config.connectionName;\n}\n\n#pragma mark -\n#pragma mark Encoding\n\n- (nullable NSData *)convertToCommonEncoding:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tNSData *data = [string dataUsingEncoding:self.config.primaryEncoding allowLossyConversion:NO];\n\n\tif (data == nil) {\n\t\tdata = [string dataUsingEncoding:self.config.fallbackEncoding allowLossyConversion:NO];\n\n\t\tif (data == nil) {\n\t\t\tdata = [string dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];\n\t\t}\n\t}\n\n\tif (data == nil) {\n\t\tLogToConsoleError(\"NSData encode failure\");\n\t\tLogStackTrace();\n\t}\n\n\treturn data;\n}\n\n- (nullable NSString *)convertFromCommonEncoding:(NSData *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tNSString *string = [NSString stringWithBytes:data.bytes length:data.length encoding:self.config.primaryEncoding];\n\n\tif (string == nil) {\n\t\tstring = [NSString stringWithBytes:data.bytes length:data.length encoding:self.config.fallbackEncoding];\n\n\t\tif (string == nil) {\n\t\t\tstring = [NSString stringWithBytes:data.bytes length:data.length encoding:NSASCIIStringEncoding];\n\t\t}\n\t}\n\n\tif (string == nil) {\n\t\tLogToConsoleError(\"NSData decode failure\");\n\t\tLogStackTrace();\n\t}\n\n\treturn string;\n}\n\n#pragma mark -\n#pragma mark Address Book\n\n- (NSArray<IRCAddressBookEntry *> *)findIgnoresForHostmask:(NSString *)hostmask\n{\n\treturn [self.addressBookMatchCache findIgnoresForHostmask:hostmask];\n}\n\n- (nullable IRCAddressBookEntry *)findUserTrackingAddressBookEntryForHostmask:(NSString *)hostmask\n{\n\t/* We chop off the nickname from the host and only use that in the\n\t matching to keep everything a little more consistent internally. */\n\tNSString *nickname = hostmask.nicknameFromHostmask;\n\t\n\tif (nickname == nil) {\n\t\treturn nil;\n\t}\n\t\n\treturn [self findUserTrackingAddressBookEntryForNickname:nickname];\n}\n\n- (nullable IRCAddressBookEntry *)findUserTrackingAddressBookEntryForNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tNSString *hostmask = [NSString stringWithFormat:@\"%@!*@*\", nickname];\n\t\n\treturn [self findAddressBookEntryForHostmask:hostmask];\n}\n\n- (nullable IRCAddressBookEntry *)findAddressBookEntryForHostmask:(NSString *)hostmask\n{\n\treturn [self.addressBookMatchCache findAddressBookEntryForHostmask:hostmask];\n}\n\n- (void)clearAddressBookCache\n{\n\t[self.addressBookMatchCache clearCachedMatches];\n}\n\n- (void)clearAddressBookCacheForHostmask:(NSString *)hostmask\n{\n\t/* Clear host */\n\t[self.addressBookMatchCache clearCachedMatchesForHostmask:hostmask];\n\n\t/* Clear nickname */\n\tNSString *nickname = hostmask.nicknameFromHostmask;\n\n\tNSString *nicknameHostmask = [NSString stringWithFormat:@\"%@!*@*\", nickname];\n\t\n\t[self.addressBookMatchCache clearCachedMatchesForHostmask:nicknameHostmask];\n}\n\n#pragma mark -\n#pragma mark Output Rules\n\n- (BOOL)outputRuleMatchedInMessage:(NSString *)message inChannel:(nullable IRCChannel *)channel\n{\n\tNSParameterAssert(message != nil);\n\n\tif ([TPCPreferences removeAllFormatting] == NO) {\n\t\tmessage = message.stripIRCEffects;\n\t}\n\n\tNSArray *rules = sharedPluginManager().pluginOutputSuppressionRules;\n\n\tfor (THOPluginOutputSuppressionRule *rule in rules) {\n\t\tif ([XRRegularExpression string:message isMatchedByRegex:rule.match] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (channel) {\n\t\t\tif ((channel.isChannel && rule.restrictChannel) ||\n\t\t\t\t(channel.isPrivateMessage && rule.restrictPrivateMessage))\n\t\t\t{\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t} else {\n\t\t\tif (rule.restrictConsole) {\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Encryption and Decryption\n\n- (NSDictionary<NSString *, NSString *> *)listOfNicknamesToDisallowEncryption\n{\n\treturn [TPCResourceManager dictionaryFromResources:@\"StaticStore\" key:@\"IRCClient List of Nicknames that Encryption Forbids\"];\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (BOOL)encryptionAllowedForTarget:(NSString *)target\n{\n\treturn [self encryptionAllowedForTarget:target lenient:NO];\n}\n\n- (BOOL)encryptionAllowedForTarget:(NSString *)target lenient:(BOOL)lenient\n{\n\tNSParameterAssert(target != nil);\n\n\t/* Encryption is disabled */\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\treturn NO;\n\t}\n\n\t/* General rules */\n\tif ([self stringIsNickname:target] == NO) { // Do not allow channel names\n\t\treturn NO;\n\t} else if ([self nicknameIsMyself:target] && lenient == NO) { // Do not allow the local user\n\t\treturn NO;\n\t} else if ([self nicknameIsZNCUser:target] && lenient == NO) { // Do not allow a ZNC private user\n\t\treturn NO;\n\t}\n\n\t/* Build context information for lookup */\n\tNSDictionary *exceptionRules = [self listOfNicknamesToDisallowEncryption];\n\n\tNSString *lowercaseNickname = target.lowercaseString;\n\n\t/* Check network specific rules (such as \"X\" on UnderNet) */\n\tNSString *networkName = self.supportInfo.networkName;\n\n\tif (networkName) {\n\t\tNSArray *networkSpecificData = [exceptionRules arrayForKey:networkName];\n\n\t\tif ([networkSpecificData containsObject:lowercaseNickname]) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\t/* Look up rules for all networks */\n\tNSArray *defaultsData = exceptionRules[@\"-default-\"];\n\n\tif ([defaultsData containsObject:lowercaseNickname]) {\n\t\treturn NO;\n\t}\n\n\t/* Allow the nickname through when there are no rules */\n\treturn YES;\n}\n#endif\n\n- (NSUInteger)lengthOfEncryptedMessageDirectedAt:(NSString *)messageTo thatFitsWithinBounds:(NSUInteger)maximumLength\n{\n\treturn 0;\n}\n\n- (void)encryptMessage:(NSString *)messageBody directedAt:(NSString *)messageTo encodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback injectionCallback:(TLOEncryptionManagerInjectCallbackBlock)injectionCallback\n{\n\tNSParameterAssert(messageBody != nil);\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(encodingCallback != nil);\n\tNSParameterAssert(injectionCallback != nil);\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t/* Check if we are accepting encryption from this user */\n\tif (messageBody.length == 0 || [self encryptionAllowedForTarget:messageTo] == NO) {\n#endif\n\t\tif (encodingCallback) {\n\t\t\tencodingCallback(messageBody, NO);\n\t\t}\n\n\t\tif (injectionCallback) {\n\t\t\tinjectionCallback(messageBody);\n\t\t}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t\treturn;\n\t}\n\n\t/* Continue with normal encryption operations */\n\t[sharedEncryptionManager() encryptMessage:messageBody\n\t\t\t\t\t\t\t\t\t\t from:[self encryptionAccountNameForLocalUser]\n\t\t\t\t\t\t\t\t\t\t   to:[self encryptionAccountNameForUser:messageTo]\n\t\t\t\t\t\t\t encodingCallback:encodingCallback\n\t\t\t\t\t\t\tinjectionCallback:injectionCallback];\n#endif\n}\n\n- (void)decryptMessage:(NSString *)messageBody from:(NSString *)messageFrom target:(NSString *)target decodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback\n{\n\tNSParameterAssert(messageBody != nil);\n\tNSParameterAssert(messageFrom != nil);\n\tNSParameterAssert(target != nil);\n\tNSParameterAssert(decodingCallback != nil);\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t/* Check if we are accepting encryption from this user */\n\tif (messageBody.length == 0 || [self encryptionAllowedForTarget:target lenient:YES] == NO) {\n#endif\n\t\tif (decodingCallback) {\n\t\t\tdecodingCallback(messageBody, NO);\n\t\t}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t\treturn;\n\t}\n\n\t/* Continue with normal encryption operations */\n\t[sharedEncryptionManager() decryptMessage:messageBody\n\t\t\t\t\t\t\t\t\t\t from:[self encryptionAccountNameForUser:messageFrom]\n\t\t\t\t\t\t\t\t\t\t   to:[self encryptionAccountNameForLocalUser]\n\t\t\t\t\t\t\t decodingCallback:decodingCallback];\n#endif\n}\n\n- (void)encryptionAuthenticateUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t/* Encryption is disabled */\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\treturn;\n\t}\n\n\t/* General rules */\n\tif ([self stringIsNickname:nickname] == NO) {\n\t\treturn;\n\t}\n\n\tif ([self nicknameIsMyself:nickname]) {\n\t\treturn;\n\t}\n\n\t/* Authenticate user */\n\t[sharedEncryptionManager() authenticateUser:[self encryptionAccountNameForUser:nickname]\n\t\t\t\t\t\t\t\t\t\t   from:[self encryptionAccountNameForLocalUser]];\n#endif\n\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n- (nullable NSString *)formatNotificationToSpeak:(TLOSpokenNotification *)notification\n{\n\tNSParameterAssert(notification != nil);\n\n\tif (self.isTerminating) {\n\t\treturn nil;\n\t}\n\n\tNSString *formattedMessage = nil;\n\n\tTXNotificationType eventType = notification.notificationType;\n\n\tIRCChannel *channel = notification.channel;\n\n\tNSString *nickname = notification.nickname;\n\n\tNSString *text = notification.text;\n\n\tif (text) {\n\t\ttext = text.trim;\n\n\t\tif ([TPCPreferences removeAllFormatting] == NO) {\n\t\t\ttext = text.stripIRCEffects;\n\t\t}\n\t}\n\n\tswitch (eventType) {\n\t\tcase TXNotificationTypeHighlight:\n\t\t{\n\t\t\tNSParameterAssert(channel != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tif (text.length == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Highlights are spoken regardless of whether the user has configured\n\t\t\t Channel Messages to be only spoken for selection. When the user has \n\t\t\t configured that preference, then we exclude the channel name at least\n\t\t\t because that information is uninteresting. */\n\t\t\t/* For private messages, we speak everything, regardless of any preference. */\n\t\t\tBOOL isChannel = channel.isChannel;\n\n\t\t\tBOOL onlySpeakEventsForSelection = [TPCPreferences onlySpeakEventsForSelection];\n\n\t\t\tBOOL speakChannelName =\n\t\t\t/* 1 */\t(isChannel == NO ||\n\t\t\t/* 2 */ (onlySpeakEventsForSelection == NO &&\n\t\t\t\t\t [TPCPreferences channelMessageSpeakChannelName]) ||\n\t\t\t/* 2 */\t(onlySpeakEventsForSelection &&\n\t\t\t\t\t [mainWindow() isItemSelected:channel] == NO));\n\n\t\t\tBOOL speakNickname = (isChannel == NO ||\n\t\t\t\t\t[TPCPreferences channelMessageSpeakNickname]);\n\n\t\t\tNSMutableString *mutableMessage = [NSMutableString string];\n\n\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[qld-sa]\")];\n\n\t\t\tif (speakChannelName || speakNickname) {\n\t\t\t\tif (speakChannelName) {\n\t\t\t\t\tif (isChannel) {\n\t\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[ke8-17]\", channel.name.channelNameWithoutBang)]; // Channel\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[6nw-ec]\")]; // Private Message\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (speakNickname) {\n\t\t\t\t\tif (isChannel) {\n\t\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[qy9-86]\", nickname)]; // by <nickname>\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[a7i-pu]\", nickname)]; // from <nickname>\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[g9t-bt]\")];\n\t\t\t}\n\n\t\t\t[mutableMessage appendString:text];\n\n\t\t\tformattedMessage = [mutableMessage copy];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeChannelMessage:\n\t\tcase TXNotificationTypeChannelNotice:\n\t\t{\n\t\t\tNSParameterAssert(channel != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tif (text.length == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tBOOL onlySpeakEventsForSelection = [TPCPreferences onlySpeakEventsForSelection];\n\n\t\t\tBOOL channelIsSelected = [mainWindow() isItemSelected:channel];\n\n\t\t\tif (onlySpeakEventsForSelection && channelIsSelected == NO) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tBOOL speakChannelName = (onlySpeakEventsForSelection == NO &&\n\t\t\t\t\t\t\t\t\t [TPCPreferences channelMessageSpeakChannelName]);\n\n\t\t\tBOOL speakNickname = [TPCPreferences channelMessageSpeakNickname];\n\n\t\t\tNSMutableString *mutableMessage = [NSMutableString string];\n\n\t\t\tif (speakChannelName || speakNickname) {\n\t\t\t\tif (eventType == TXNotificationTypeChannelMessage) {\n\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[tao-i2]\")];\n\t\t\t\t} else if (eventType == TXNotificationTypeChannelNotice) {\n\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[kk4-68]\")];\n\t\t\t\t}\n\n\t\t\t\tif (speakChannelName) {\n\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[ke8-17]\", channel.name.channelNameWithoutBang)];\n\t\t\t\t}\n\n\t\t\t\tif (speakNickname) {\n\t\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[qy9-86]\", nickname)];\n\t\t\t\t}\n\n\t\t\t\t[mutableMessage appendString:TXTLS(@\"Notifications[g9t-bt]\")];\n\t\t\t}\n\n\t\t\t[mutableMessage appendString:text];\n\n\t\t\tformattedMessage = [mutableMessage copy];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeNewPrivateMessage:\n\t\tcase TXNotificationTypePrivateMessage:\n\t\tcase TXNotificationTypePrivateNotice:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tif (text.length == 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *formatter = nil;\n\n\t\t\tif (eventType == TXNotificationTypeNewPrivateMessage) {\n\t\t\t\tformatter = @\"Notifications[rvb-9l]\";\n\t\t\t} else if (eventType == TXNotificationTypePrivateMessage) {\n\t\t\t\tformatter = @\"Notifications[2bu-ep]\";\n\t\t\t} else if (eventType == TXNotificationTypePrivateNotice) {\n\t\t\t\tformatter = @\"Notifications[6jl-vh]\";\n\t\t\t}\n\n\t\t\tformattedMessage = TXTLS(formatter, nickname, text);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeKick:\n\t\t{\n\t\t\tNSParameterAssert(channel != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\n\t\t\tNSString *formatter = @\"Notifications[5yu-bf]\";\n\n\t\t\tformattedMessage = TXTLS(formatter, channel.name.channelNameWithoutBang, nickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeInvite:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tNSString *formatter = @\"Notifications[l5i-at]\";\n\n\t\t\tformattedMessage = TXTLS(formatter, text.channelNameWithoutBang, nickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeConnect:\n\t\tcase TXNotificationTypeDisconnect:\n\t\t{\n\t\t\tNSString *formatter = nil;\n\n\t\t\tif (eventType == TXNotificationTypeConnect) {\n\t\t\t\tformatter = @\"Notifications[z4p-yr]\";\n\t\t\t} else if (eventType == TXNotificationTypeDisconnect) {\n\t\t\t\tformatter = @\"Notifications[fd0-f8]\";\n\t\t\t}\n\n\t\t\tformattedMessage = TXTLS(formatter, self.networkNameAlt);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeAddressBookMatch:\n\t\t{\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tformattedMessage = text;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferSendSuccessful:\n\t\tcase TXNotificationTypeFileTransferReceiveSuccessful:\n\t\tcase TXNotificationTypeFileTransferSendFailed:\n\t\tcase TXNotificationTypeFileTransferReceiveFailed:\n\t\tcase TXNotificationTypeFileTransferReceiveRequested:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\n\t\t\tNSString *formatter = nil;\n\n\t\t\tif (eventType == TXNotificationTypeFileTransferSendSuccessful) {\n\t\t\t\tformatter = @\"Notifications[5e4-vg]\";\n\t\t\t} else if (eventType == TXNotificationTypeFileTransferReceiveSuccessful) {\n\t\t\t\tformatter = @\"Notifications[4cd-p3]\";\n\t\t\t} else if (eventType == TXNotificationTypeFileTransferSendFailed) {\n\t\t\t\tformatter = @\"Notifications[f0u-32]\";\n\t\t\t} else if (eventType == TXNotificationTypeFileTransferReceiveFailed) {\n\t\t\t\tformatter = @\"Notifications[mak-bj]\";\n\t\t\t} else if (eventType == TXNotificationTypeFileTransferReceiveRequested) {\n\t\t\t\tformatter = @\"Notifications[at0-vi]\";\n\t\t\t}\n\n\t\t\tformattedMessage = TXTLS(formatter, nickname);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserJoined:\n\t\tcase TXNotificationTypeUserParted:\n\t\t{\n\t\t\tNSParameterAssert(channel != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\n\t\t\tNSString *formatter = nil;\n\n\t\t\tif (eventType == TXNotificationTypeUserJoined) {\n\t\t\t\tformatter = @\"Notifications[bwu-ps]\";\n\t\t\t} else if (eventType == TXNotificationTypeUserParted) {\n\t\t\t\tformatter = @\"Notifications[4aq-hz]\";\n\t\t\t}\n\n\t\t\tformattedMessage = TXTLS(formatter, nickname, channel.name.channelNameWithoutBang);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserDisconnected:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\n\t\t\tNSString *formatter = @\"Notifications[sqf-4y]\";\n\n\t\t\tformattedMessage = TXTLS(formatter, nickname);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn formattedMessage;\n}\n\n- (void)clearEventsToSpeak\n{\n\t[[TXSharedApplication sharedSpeechSynthesizer] clearQueueForClient:self];\n}\n\n- (void)speakEvent:(TXNotificationType)eventType lineType:(TVCLogLineType)lineType target:(null_unspecified IRCTreeItem *)target nickname:(null_unspecified NSString *)nickname text:(null_unspecified NSString *)text\n{\n\tif ([sharedNotificationController() speakEvent:eventType inChannel:(IRCChannel *)target] == NO) {\n\t\treturn;\n\t}\n\n\tif (target == nil) {\n\t\ttarget = self;\n\t}\n\n\tTLOSpokenNotification *notification =\n\t[[TLOSpokenNotification alloc] initWithNotification:eventType\n\t\t\t\t\t\t\t\t\t\t\t   lineType:lineType\n\t\t\t\t\t\t\t\t\t\t\t\t target:target\n\t\t\t\t\t\t\t\t\t\t\t   nickname:nickname\n\t\t\t\t\t\t\t\t\t\t\t\t   text:text];\n\n\t[[TXSharedApplication sharedSpeechSynthesizer] speak:notification];\n}\n\n- (BOOL)notifyText:(TXNotificationType)eventType lineType:(TVCLogLineType)lineType target:(IRCChannel *)target nickname:(NSString *)nickname text:(NSString *)text\n{\n\treturn [self notifyEvent:eventType lineType:lineType target:target nickname:nickname text:text userInfo:nil];\n}\n\n- (BOOL)notifyEvent:(TXNotificationType)eventType lineType:(TVCLogLineType)lineType\n{\n\treturn [self notifyEvent:eventType lineType:lineType target:nil nickname:nil text:nil userInfo:nil];\n}\n\n- (BOOL)notifyEvent:(TXNotificationType)eventType lineType:(TVCLogLineType)lineType target:(null_unspecified IRCChannel *)target nickname:(null_unspecified NSString *)nickname text:(null_unspecified NSString *)text\n{\n\treturn [self notifyEvent:eventType lineType:lineType target:target nickname:nickname text:text userInfo:nil];\n}\n\n- (BOOL)notifyEvent:(TXNotificationType)eventType lineType:(TVCLogLineType)lineType target:(null_unspecified IRCChannel *)target nickname:(null_unspecified NSString *)nickname text:(null_unspecified NSString *)text userInfo:(nullable NSDictionary<NSString *, id> *)userInfo\n{\n\tif (self.isTerminating) {\n\t\treturn NO;\n\t}\n\n\tBOOL isTextEvent =\n\t(eventType == TXNotificationTypeHighlight\t\t\t||\n\t eventType == TXNotificationTypeNewPrivateMessage\t||\n\t eventType == TXNotificationTypeChannelMessage\t\t||\n\t eventType == TXNotificationTypeChannelNotice\t\t||\n\t eventType == TXNotificationTypePrivateMessage\t\t||\n\t eventType == TXNotificationTypePrivateNotice);\n\n\tif (isTextEvent) {\n\t\tif ([self nicknameIsMyself:nickname]) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\tif (target && text != nil) {\n\t\tif ([self outputRuleMatchedInMessage:text inChannel:target]) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\tIRCChannelConfig *targetConfig = nil;\n\n\tif (target) {\n\t\ttargetConfig = target.config;\n\n\t\tif (eventType == TXNotificationTypeHighlight) {\n\t\t\tif (targetConfig.ignoreHighlights) {\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t} else {\n\t\t\tif (targetConfig.pushNotifications == NO) {\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ([sharedNotificationController() bounceDockIconForEvent:eventType inChannel:target]) {\n\t\tif ([sharedNotificationController() bounceDockIconRepeatedlyForEvent:eventType inChannel:target]) {\n\t\t\t[NSApp requestUserAttention:NSCriticalRequest];\n\t\t} else {\n\t\t\t[NSApp requestUserAttention:NSInformationalRequest];\n\t\t}\n\t}\n\n\tif (sharedNotificationController().areNotificationsDisabled) {\n\t\treturn YES;\n\t}\n\n\tBOOL mainWindowIsFocused = (mainWindow().inactive == NO);\n\n\tBOOL postNotificationsWhileFocused = [TPCPreferences postNotificationsWhileInFocus];\n\n\tBOOL targetIsSelected = [mainWindow() isItemSelected:target];\n\n\tBOOL onlySpeakEvent = (postNotificationsWhileFocused && mainWindowIsFocused && targetIsSelected);\n\n\tif ([TPCPreferences soundIsMuted] == NO) {\n\t\tif (onlySpeakEvent == NO) {\n\t\t\tNSString *soundName = [sharedNotificationController() soundForEvent:eventType inChannel:target];\n\n\t\t\tif (soundName) {\n\t\t\t\t[TLOSoundPlayer playAlertSound:soundName];\n\t\t\t}\n\t\t}\n\n\t\t[self speakEvent:eventType lineType:lineType target:target nickname:nickname text:text];\n\t}\n\n\tif (onlySpeakEvent) {\n\t\treturn YES;\n\t}\n\n\tif ([sharedNotificationController() notificationEnabledForEvent:eventType inChannel:target] == NO) {\n\t\treturn YES;\n\t}\n\n\tif (postNotificationsWhileFocused == NO && mainWindowIsFocused) {\n\t\tif (eventType != TXNotificationTypeAddressBookMatch) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\tif ([sharedNotificationController() disabledWhileAwayForEvent:eventType inChannel:target]) {\n\t\tif (self.userIsAway) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\tNSString *eventTitle = nil;\n\n\tNSString *eventDescription = nil;\n\n\tif (userInfo == nil) {\n\t\tif (target) {\n\t\t\tuserInfo = @{TXNotificationUserInfoClientIdentifierKey : self.uniqueIdentifier,\n\t\t\t\t\t\t TXNotificationUserInfoChannelIdentifierKey: target.uniqueIdentifier};\n\t\t} else {\n\t\t\tuserInfo = @{TXNotificationUserInfoClientIdentifierKey : self.uniqueIdentifier};\n\t\t}\n\t}\n\n\tswitch (eventType) {\n\t\tcase TXNotificationTypeHighlight:\n\t\tcase TXNotificationTypeNewPrivateMessage:\n\t\tcase TXNotificationTypeChannelMessage:\n\t\tcase TXNotificationTypeChannelNotice:\n\t\tcase TXNotificationTypePrivateMessage:\n\t\tcase TXNotificationTypePrivateNotice:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\tif (eventType == TXNotificationTypeHighlight ||\n\t\t\t\teventType == TXNotificationTypeChannelMessage ||\n\t\t\t\teventType == TXNotificationTypeChannelNotice)\n\t\t\t{\n\t\t\t\tNSParameterAssert(target != nil);\n\n\t\t\t\teventTitle = target.name;\n\t\t\t}\n\n\t\t\tif (lineType == TVCLogLineTypeAction || lineType == TVCLogLineTypeActionNoHighlight) {\n\t\t\t\teventDescription = [NSString stringWithFormat:TXNotificationDialogActionNicknameFormat, nickname, text];\n\t\t\t} else {\n\t\t\t\tnickname = [self formatNickname:nickname inChannel:target];\n\n\t\t\t\teventDescription = [NSString stringWithFormat:TXNotificationDialogStandardNicknameFormat, nickname, text];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferSendSuccessful:\n\t\tcase TXNotificationTypeFileTransferReceiveSuccessful:\n\t\tcase TXNotificationTypeFileTransferSendFailed:\n\t\tcase TXNotificationTypeFileTransferReceiveFailed:\n\t\tcase TXNotificationTypeFileTransferReceiveRequested:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventTitle = nickname;\n\n\t\t\teventDescription = text;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeConnect:\n\t\t{\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeDisconnect:\n\t\t{\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeAddressBookMatch:\n\t\t{\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventDescription = text;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeKick:\n\t\t{\n\t\t\tNSParameterAssert(target != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\teventDescription = TXTLS(@\"Notifications[fkt-p3]\", nickname, target.name, text);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeInvite:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\teventDescription = TXTLS(@\"Notifications[xl5-dn]\", nickname, text);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserJoined:\n\t\t{\n\t\t\tNSParameterAssert(target != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\teventDescription = TXTLS(@\"Notifications[yas-us]\", nickname, target.name);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserParted:\n\t\t{\n\t\t\tNSParameterAssert(target != nil);\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\tif (text == nil || text.length == 0) {\n\t\t\t\teventDescription = TXTLS(@\"Notifications[bu2-9m]\", nickname, target.name);\n\t\t\t} else {\n\t\t\t\teventDescription = TXTLS(@\"Notifications[3ur-i8]\", nickname, target.name, text);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserDisconnected:\n\t\t{\n\t\t\tNSParameterAssert(nickname != nil);\n\t\t\tNSParameterAssert(text != nil);\n\n\t\t\teventTitle = self.networkNameAlt;\n\n\t\t\tif (text == nil || text.length == 0) {\n\t\t\t\teventDescription = TXTLS(@\"Notifications[7ao-n8]\", nickname);\n\t\t\t} else {\n\t\t\t\teventDescription = TXTLS(@\"Notifications[ssw-m6]\", nickname, text);\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\t[sharedNotificationController() notify:eventType title:eventTitle description:eventDescription userInfo:userInfo];\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Playback\n\n- (void)playbackClearChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityPlayback] == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.isPrivateMessage == NO || channel.isPrivateMessageForZNCUser) {\n\t\treturn;\n\t}\n\n\tNSString *command = [NSString stringWithFormat:@\"clear %@\", channel.name];\n\n\tif (self.isConnectedToZNC) {\n\t\t[self sendCommand:command toZNCModuleNamed:@\"playback\"];\n\n\t\treturn;\n\t}\n\n\t[self send:@\"PRIVMSG\", @\"*playback\", command, nil];\n}\n\n- (void)requestPlayback\n{\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityPlayback] == NO) {\n\t\treturn;\n\t}\n\n\t/* For our first connect, only playback using timestamp if logging was enabled. */\n\t/* For all other connects, then playback timestamp regardless of logging. */\n\tNSString *command = nil;\n\n\tif ((self.successfulConnects > 1 || (self.successfulConnects == 1 && self.config.zncOnlyPlaybackLatest)) && self.lastMessageServerTime > 0) {\n\t\tcommand = [NSString stringWithFormat:@\"play * %.0f\", self.lastMessageServerTime];\n\t} else {\n\t\tcommand = @\"play * 0\";\n\t}\n\n\tif (self.isConnectedToZNC) {\n\t\t[self sendCommand:command toZNCModuleNamed:@\"playback\"];\n\n\t\treturn;\n\t}\n\n\t[self send:@\"PRIVMSG\", @\"*playback\", command, nil];\n}\n\n#pragma mark -\n#pragma mark ZNC Bouncer Accessories\n\n- (void)zncPlaybackClearChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isConnectedToZNC == NO) {\n\t\treturn;\n\t}\n\n\t[self playbackClearChannel:channel];\n}\n\n- (BOOL)nicknameIsZNCUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self.isConnectedToZNC == NO) {\n\t\treturn NO;\n\t}\n\n\treturn [nickname hasPrefix:@\"*\"];\n}\n\n- (BOOL)nickname:(NSString *)nickname isZNCUser:(NSString *)zncNickname\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(zncNickname != nil);\n\t\n\treturn [nickname isEqualToString:[self nicknameAsZNCUser:zncNickname]];\n}\n\n- (nullable NSString *)nicknameAsZNCUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self.isConnectedToZNC == NO) {\n\t\treturn nil;\n\t}\n\n\treturn [@\"*\" stringByAppendingString:nickname];\n}\n\n- (BOOL)isSafeToPostNotificationForMessage:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel\n{\n\tNSParameterAssert(message != nil);\n\n\tif (self.isConnectedToZNC == NO) {\n\t\treturn YES;\n\t}\n\n\tif (self.config.zncIgnoreUserNotifications) {\n\t\tif (channel && [self nicknameIsZNCUser:channel.name]) {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\tif (self.config.zncIgnorePlaybackNotifications == NO) {\n\t\treturn YES;\n\t}\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityBatch]) {\n\t\tNSString *batchType = message.parentBatchMessage.batchType;\n\n\t\treturn ([batchType isEqualToString:@\"znc.in/playback\"] == NO);\n\t}\n\n\treturn (message.isHistoric == NO);\n}\n\n- (void)updateConnectedToZNCPropertyWithMessage:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\tif (self.isConnectedToZNC) {\n\t\treturn;\n\t}\n\n\tif (message.senderIsServer == NO) {\n\t\treturn;\n\t}\n\n\tif ([message.senderNickname isEqualToString:@\"irc.znc.in\"]) {\n\t\tself.isConnectedToZNC = YES;\n\n\t\tLogToConsole(\"ZNC detected...\");\n\t}\n}\n\n- (void)sendCommand:(NSString *)command toZNCModuleNamed:(NSString *)module\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(module != nil);\n\n\tNSString *destination = [self nicknameAsZNCUser:module];\n\n\tif (destination == nil) {\n\t\treturn;\n\t}\n\n\tNSString *stringToSend = [NSString stringWithFormat:@\"ZNC %@ %@\", destination, command];\n\n\t[self sendLine:stringToSend];\n}\n\n#pragma mark -\n#pragma mark Channel States\n\n- (void)setHighlightStateForChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (mainWindow().keyWindow && [mainWindow() isItemSelected:channel]) {\n\t\treturn;\n\t}\n\n\tchannel.nicknameHighlightCount += 1;\n\n\t[TVCDockIcon updateDockIcon];\n\n\t[mainWindow() reloadTreeItem:channel];\n}\n\n- (void)setUnreadStateForChannel:(IRCChannel *)channel\n{\n\t[self setUnreadStateForChannel:channel isHighlight:NO];\n}\n\n- (void)setUnreadStateForChannel:(IRCChannel *)channel isHighlight:(BOOL)isHighlight\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (mainWindow().keyWindow && [mainWindow() isItemSelected:channel]) {\n\t\treturn;\n\t}\n\n\tif (channel.isChannel == NO || [TPCPreferences displayPublicMessageCountOnDockBadge]) {\n\t\tchannel.dockUnreadCount += 1;\n\n\t\t[TVCDockIcon updateDockIcon];\n\t}\n\n\tchannel.treeUnreadCount += 1;\n\n\t// The isHighlight flag is not sent for the purpose of incrementing\n\t// a count. It's passed so that we can know whether the option to\n\t// show badge count should be ignored when performing update.\n\tif (isHighlight || channel.config.showTreeBadgeCount) {\n\t\t[mainWindowServerList() refreshMessageCountForItem:channel];\n\t}\n}\n\n#pragma mark -\n#pragma mark Find Channel\n\n- (nullable IRCChannel *)findChannel:(NSString *)withName inList:(NSArray<IRCChannel *> *)channelList\n{\n\tNSParameterAssert(withName != nil);\n\tNSParameterAssert(channelList != nil);\n\n\tNSUInteger channelIndex =\n\t[channelList indexOfObjectWithOptions:NSEnumerationConcurrent\n\t\t\t\t\t\t\t  passingTest:^BOOL(IRCChannel *channel, NSUInteger index, BOOL *stop) {\n\t\t\t\t\t\t\t\t  NSString *channelName = channel.name;\n\n\t\t\t\t\t\t\t\t  return [withName isEqualToStringIgnoringCase:channelName];\n\t\t\t\t\t\t\t  }];\n\n\tif (channelIndex != NSNotFound) {\n\t\treturn channelList[channelIndex];\n\t}\n\n\treturn nil;\n}\n\n- (nullable IRCChannel *)findChannel:(NSString *)name\n{\n\treturn [self findChannel:name inList:self.channelList];\n}\n\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)name\n{\n\treturn [self findChannelOrCreate:name isPrivateMessage:NO];\n}\n\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isPrivateMessage:(BOOL)isPrivateMessage\n{\n\tNSParameterAssert(withName != nil);\n\n\tif (isPrivateMessage == NO) {\n\t\treturn [self findChannelOrCreate:withName asType:IRCChannelTypeChannel];\n\t} else {\n\t\treturn [self findChannelOrCreate:withName asType:IRCChannelTypePrivateMessage];\n\t}\n}\n\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName isUtility:(BOOL)isUtility\n{\n\tNSParameterAssert(withName != nil);\n\n\tif (isUtility == NO) {\n\t\treturn [self findChannelOrCreate:withName asType:IRCChannelTypeChannel];\n\t} else {\n\t\treturn [self findChannelOrCreate:withName asType:IRCChannelTypeUtility];\n\t}\n}\n\n- (nullable IRCChannel *)findChannelOrCreate:(NSString *)withName asType:(IRCChannelType)type\n{\n\tNSParameterAssert(withName != nil);\n\n\tIRCChannel *channel = [self findChannel:withName];\n\n\tif (channel) {\n\t\treturn channel;\n\t}\n\n\tif (type == IRCChannelTypeChannel) {\n\t\tIRCChannelConfig *config = [IRCChannelConfig seedWithName:withName];\n\n\t\tchannel = [worldController() createChannelWithConfig:config onClient:self add:YES adjust:YES reload:YES];\n\n\t\t[worldController() savePeriodically];\n\t} else {\n\t\tchannel = [worldController() createPrivateMessage:withName onClient:self asType:type];\n\t}\n\n\treturn channel;\n}\n\n#pragma mark -\n#pragma mark User List \n\n- (nullable IRCUser *)myself\n{\n\treturn [self findUser:self.userNickname];\n}\n\n- (BOOL)userExists:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\treturn ([self findUser:nickname] != nil);\n}\n\n- (nullable IRCUser *)findUser:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tnickname = nickname.lowercaseString;\n\n\t@synchronized (self.userListPrivate) {\n\t\treturn self.userListPrivate[nickname];\n\t}\n}\n\n- (IRCUserMutable *)mutableCopyOfUserWithNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tIRCUser *user = [self findUser:nickname];\n\n\tif (user == nil) {\n\t\treturn [[IRCUserMutable alloc] initWithNickname:nickname onClient:self];\n\t} else {\n\t\treturn [user mutableCopy];\n\t}\n}\n\n- (NSUInteger)numberOfUsers\n{\n\t@synchronized (self.userListPrivate) {\n\t\treturn self.userListPrivate.count;\n\t}\n}\n\n- (NSArray<IRCUser *> *)userList\n{\n\t@synchronized (self.userListPrivate) {\n\t\treturn self.userListPrivate.allValues;\n\t}\n}\n\n- (void)addUser:(IRCUser *)user\n{\n\t[self addUserAndReturn:user];\n}\n\n- (IRCUser *)addUserAndReturn:(IRCUser *)user\n{\n\tNSParameterAssert(user != nil);\n\n\tif ([user isKindOfClass:[IRCUserMutable class]]) {\n\t\tuser = [user copy];\n\t}\n\n\tNSString *nickname = user.lowercaseNickname;\n\n\t@synchronized (self.userListPrivate) {\n\t\tself.userListPrivate[nickname] = user;\n\t}\n\n\t[user becamePrimaryUser];\n\n\treturn user;\n}\n\n- (IRCUser *)findUserOrCreate:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tIRCUser *user = [self findUser:nickname];\n\n\tif (user == nil) {\n\t\tuser = [[IRCUser alloc] initWithNickname:nickname onClient:self];\n\n\t\t[self addUser:user];\n\t}\n\n\treturn user;\n}\n\n- (void)removeUser:(IRCUser *)user\n{\n\tNSParameterAssert(user != nil);\n\n\t[user cancelRemoveUserTimer];\n\t\n\tNSString *hostmask = user.hostmask;\n\n\tif (hostmask) {\n\t\t[self clearAddressBookCacheForHostmask:hostmask];\n\t}\n\n\t[self removeUserWithNickname:user.nickname];\n}\n\n- (void)removeUserWithNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tnickname = nickname.lowercaseString;\n\n\t@synchronized (self.userListPrivate) {\n\t\t[self.userListPrivate removeObjectForKey:nickname];\n\t}\n}\n\n- (void)renameUser:(IRCUser *)user to:(NSString *)toNickname\n{\n\tNSParameterAssert(user != nil);\n\tNSParameterAssert(toNickname != nil);\n\n\t[self modifyUser:user withBlock:^(IRCUserMutable *userMutable) {\n\t\tuserMutable.nickname = toNickname;\n\t}];\n}\n\n- (void)renameUserWithNickname:(NSString *)fromNickname to:(NSString *)toNickname\n{\n\tNSParameterAssert(fromNickname != nil);\n\tNSParameterAssert(toNickname != nil);\n\n\tIRCUser *user = [self findUser:fromNickname];\n\n\tif (user == nil) {\n\t\treturn;\n\t}\n\n\t[self renameUser:user to:toNickname];\n}\n\n- (void)modifyUser:(IRCUser *)user withBlock:(void(NS_NOESCAPE ^)(IRCUserMutable *userMutable))block\n{\n\tNSParameterAssert(user != nil);\n\tNSParameterAssert(block != nil);\n\n\tIRCUserMutable *userMutable = [user mutableCopy];\n\n\tblock(userMutable);\n\n\tif ([user.nickname isEqualToString:userMutable.nickname] == NO) {\n\t\t[self removeUser:user];\n\t}\n\n\t[self addUser:userMutable];\n}\n\n- (void)modifyUserUserWithNickname:(NSString *)nickname withBlock:(void(NS_NOESCAPE ^)(IRCUserMutable *userMutable))block\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(block != nil);\n\n\tIRCUser *user = [self findUser:nickname];\n\n\tif (user == nil) {\n\t\treturn;\n\t}\n\n\t[self modifyUser:user withBlock:block];\n}\n\n- (void)modifyUserWithNickname:(NSString *)nickname asAway:(BOOL)away\n{\n\tNSParameterAssert(nickname != nil);\n\t\n\tIRCUser *user = [self findUser:nickname];\n\t\n\tif (user == nil) {\n\t\treturn;\n\t}\n\n\t[self modifyUser:user asAway:away];\n}\n\n- (void)modifyUser:(IRCUser *)user asAway:(BOOL)away\n{\n\tNSParameterAssert(user != nil);\n\t\n\tif (self.monitorAwayStatus == NO) {\n\t\treturn;\n\t}\n\n\tif (away) {\n\t\t[user markAsAway];\n\t} else {\n\t\t[user markAsReturned];\n\t}\n\t\n\t[mainWindow() updateDrawingForUserInUserList:user];\n}\n\n- (void)resetAwayStatusForUsers\n{\n\t[self.userList makeObjectsPerformSelector:@selector(markAsReturned)];\n}\n\n#pragma mark -\n#pragma mark Send Raw Data\n\n- (void)sendLine:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tif (self.isConnected == NO) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[6rj-2r]\")];\n\n\t\treturn;\n\t}\n\n\t[self.socket sendLine:string];\n\n\tworldController().bandwidthOut += string.length;\n\n\tworldController().messagesSent += 1;\n}\n\n- (void)send:(NSString *)string arguments:(NSArray<NSString *> *)arguments\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(arguments != nil);\n\n\tNSString *stringToSend = [IRCSendingMessage stringWithCommand:string arguments:arguments];\n\n\t[self sendLine:stringToSend];\n}\n\n- (void)send:(NSString *)string, ...\n{\n\tNSParameterAssert(string != nil);\n\n\tNSMutableArray<NSString *> *argumentsOut = [NSMutableArray array];\n\n\tva_list argumentsIn;\n\tva_start(argumentsIn, string);\n\n\tNSString *argumentInString = nil;\n\n\twhile ((argumentInString = va_arg(argumentsIn, NSString *))) {\n\t\t[argumentsOut addObject:argumentInString];\n\t}\n\n\tva_end(argumentsIn);\n\n\t[self send:string arguments:argumentsOut];\n}\n\n#pragma mark -\n#pragma mark Sending Text\n\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command\n{\n\tIRCTreeItem *destination = mainWindow().selectedItem;\n\n\t[self inputText:string asCommand:command destination:destination];\n}\n\n- (void)inputText:(id)string destination:(IRCTreeItem *)destination\n{\n\t[self inputText:string asCommand:IRCRemoteCommandPrivmsg destination:destination];\n}\n\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command destination:(IRCTreeItem *)destination\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(destination != nil);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tBOOL inputIsNSString = [string isKindOfClass:[NSString class]];\n\n\tif (inputIsNSString == NO && [string isKindOfClass:[NSAttributedString class]] == NO) {\n\t\tNSAssert(NO, @\"'string' must be NSString or NSAttributedString\");\n\t}\n\n\tif (command != IRCRemoteCommandPrivmsg &&\n\t\tcommand != IRCRemoteCommandPrivmsgAction &&\n\t\tcommand != IRCRemoteCommandNotice)\n\t{\n\t\tNSAssert(NO, @\"Bad 'command' value\");\n\t}\n\n\tif ([string length] == 0) {\n\t\treturn;\n\t}\n\n\tNSAttributedString *stringIn = nil;\n\n\tif (inputIsNSString) {\n\t\tstringIn = [NSAttributedString attributedStringWithString:string];\n\t} else {\n\t\tstringIn = string;\n\t}\n\n\tNSArray *lines = ((NSAttributedString *)stringIn).splitIntoLines;\n\n\t/* Warn if the split value is above 4 lines or if the total string \n\t length exceeds TXMaximumIRCBodyLength times 4. */\n\tif (lines.count > 4 || (stringIn.length > (TXMaximumIRCBodyLength * 4))) {\n\t\tBOOL continueInput = [TDCAlert modalAlertWithMessage:TXTLS(@\"IRC[lql-8i]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t   title:TXTLS(@\"IRC[u4c-7i]\")\n\t\t\t\t\t\t\t\t\t\t\t   defaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t\t\t alternateButton:TXTLS(@\"Prompts[99q-gg]\")\n\t\t\t\t\t\t\t\t\t\t\t  suppressionKey:@\"input_text_possible_flood_warning\"\n\t\t\t\t\t\t\t\t\t\t\t suppressionText:nil];\n\n\t\tif (continueInput == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tfor (__strong NSAttributedString *line in lines) {\n\t\tNSString *lineString = line.string;\n\n\t\tBOOL isPrefixed = [lineString hasPrefix:@\"/\"];\n\n\t\tif (destination.isClient) {\n\t\t\tif (isPrefixed) {\n\t\t\t\tline = [line attributedSubstringFromIndex:1];\n\t\t\t}\n\n\t\t\t[self sendCommand:line];\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSUInteger lineLength = line.length;\n\n\t\tIRCChannel *channel = (IRCChannel *)destination;\n\n\t\tif (isPrefixed && [lineString hasPrefix:@\"//\"] == NO && lineLength > 1) {\n\t\t\tline = [line attributedSubstringFromIndex:1];\n\n\t\t\t[self sendCommand:line];\n\t\t} else {\n\t\t\tif (isPrefixed && lineLength > 1) {\n\t\t\t\tline = [line attributedSubstringFromIndex:1];\n\t\t\t}\n\n\t\t\t[self sendText:line asCommand:command toChannel:channel];\n\t\t}\n\t}\n}\n\n- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel\n{\n\t[self sendText:string asCommand:command toChannel:channel withEncryption:YES];\n}\n\n- (void)sendText:(NSAttributedString *)string asCommand:(IRCRemoteCommand)command toChannel:(IRCChannel *)channel withEncryption:(BOOL)encryptText\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(channel != nil);\n\n\tif (string.length == 0) {\n\t\treturn;\n\t}\n\n\tif (channel.isUtility) {\n\t\t[self printDebugInformation:TXTLS(@\"IRC[z2r-sd]\") inChannel:channel];\n\n\t\treturn;\n\t}\n\n\tNSString *commandToSend = nil;\n\n\tTVCLogLineType lineType = TVCLogLineTypeUndefined;\n\n\tif (command == IRCRemoteCommandPrivmsg) {\n\t\tcommandToSend = @\"PRIVMSG\";\n\n\t\tlineType = TVCLogLineTypePrivateMessage;\n\t} else if (command == IRCRemoteCommandPrivmsgAction) {\n\t\tcommandToSend = @\"PRIVMSG\";\n\n\t\tlineType = TVCLogLineTypeAction;\n\t} else if (command == IRCRemoteCommandNotice) {\n\t\tcommandToSend = @\"NOTICE\";\n\n\t\tlineType = TVCLogLineTypeNotice;\n\t}\n\n\tNSParameterAssert(lineType != TVCLogLineTypeUndefined);\n\n\tNSArray *lines = string.splitIntoLines;\n\n\tfor (NSAttributedString *line in lines) {\n\t\tNSMutableAttributedString *lineMutable = [line mutableCopy];\n\n\t\twhile (lineMutable.length > 0)\n\t\t{\n\t\t\tNSString *unencryptedMessage = [lineMutable stringFormattedForChannel:channel.name onClient:self withLineType:lineType];\n\n\t\t\tTLOEncryptionManagerEncodingDecodingCallbackBlock encryptionBlock = ^(NSString *originalString, BOOL wasEncrypted) {\n\t\t\t\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage] && wasEncrypted == NO) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t[self print:originalString\n\t\t\t\t\t\t by:self.userNickname\n\t\t\t\t  inChannel:channel\n\t\t\t\t\t asType:lineType\n\t\t\t\t\tcommand:commandToSend\n\t\t\t\t receivedAt:[NSDate date]\n\t\t\t\tisEncrypted:wasEncrypted];\n\t\t\t};\n\n\t\t\tTLOEncryptionManagerInjectCallbackBlock injectionBlock = ^(NSString *encodedString) {\n\t\t\t\tNSString *sendMessage = encodedString;\n\n\t\t\t\tif (lineType == TVCLogLineTypeAction) {\n\t\t\t\t\tsendMessage = [NSString stringWithFormat:@\"%cACTION %@%c\", 0x01, sendMessage, 0x01];\n\t\t\t\t}\n\n\t\t\t\t[self send:commandToSend, channel.name, sendMessage, nil];\n\t\t\t};\n\n\t\t\tif (encryptText == NO) {\n\t\t\t\tencryptionBlock(unencryptedMessage, NO);\n\n\t\t\t\tinjectionBlock(unencryptedMessage);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[self encryptMessage:unencryptedMessage\n\t\t\t\t\t  directedAt:channel.name\n\t\t\t\tencodingCallback:encryptionBlock\n\t\t\t   injectionCallback:injectionBlock];\n\t\t}\n\t}\n\n\t[self processBundlesUserMessage:string.string command:commandToSend];\n}\n\n- (void)sendPrivmsg:(NSString *)message toChannel:(IRCChannel *)channel\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self sendText:[NSAttributedString attributedStringWithString:message]\n\t\t\t asCommand:IRCRemoteCommandPrivmsg\n\t\t\t toChannel:channel];\n\t});\n}\n\n- (void)sendAction:(NSString *)message toChannel:(IRCChannel *)channel\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self sendText:[NSAttributedString attributedStringWithString:message]\n\t\t\t asCommand:IRCRemoteCommandPrivmsgAction\n\t\t\t toChannel:channel];\n\t});\n}\n\n- (void)sendNotice:(NSString *)message toChannel:(IRCChannel *)channel\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self sendText:[NSAttributedString attributedStringWithString:message]\n\t\t\t asCommand:IRCRemoteCommandNotice\n\t\t\t toChannel:channel];\n\t});\n}\n\n- (void)sendPrivmsgToSelectedChannel:(NSString *)message\n{\n\tIRCChannel *channel = [mainWindow() selectedChannelOn:self];\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\t[self sendPrivmsg:message toChannel:channel];\n}\n\n- (void)sendCTCPQuery:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(command != nil);\n\n\tNSString *stringToSend = nil;\n\n\tif (text == nil) {\n\t\tstringToSend = command;\n\t} else {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %@\", command, text];\n\t}\n\n\tNSString *message = [NSString stringWithFormat:@\"%c%@%c\", 0x01, stringToSend, 0x01];\n\n\t[self send:@\"PRIVMSG\", nickname, message, nil];\n}\n\n- (void)sendCTCPReply:(NSString *)nickname command:(NSString *)command text:(nullable NSString *)text\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(command != nil);\n\n\tNSString *stringToSend = nil;\n\n\tif (text == nil) {\n\t\tstringToSend = command;\n\t} else {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %@\", command, text];\n\t}\n\n\tNSString *message = [NSString stringWithFormat:@\"%c%@%c\", 0x01, stringToSend, 0x01];\n\n\t[self send:@\"NOTICE\", nickname, message, nil];\n}\n\n- (void)sendCTCPPing:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\t\n\tNSString *text = [NSString stringWithFormat:@\"%f\", [NSDate timeIntervalSince1970]];\n\n\t[self sendCTCPQuery:nickname\n\t\t\t\tcommand:@\"PING\"\n\t\t\t\t   text:text];\n}\n\n#pragma mark -\n#pragma mark Send Command\n\n- (void)sendCommand:(id)string\n{\n\t[self sendCommand:string completeTarget:YES target:nil];\n}\n\n- (void)sendCommand:(id)string completeTarget:(BOOL)completeTarget target:(nullable NSString *)targetChannelName\n{\n\tNSParameterAssert(string != nil);\n\n\tBOOL inputIsNSString = [string isKindOfClass:[NSString class]];\n\n\tif (inputIsNSString == NO && [string isKindOfClass:[NSAttributedString class]] == NO) {\n\t\tNSAssert(NO, @\"'string' must be NSString or NSAttributedString\");\n\t}\n\n\tif ([string length] == 0) {\n\t\treturn;\n\t}\n\n\tNSMutableAttributedString *stringIn = nil;\n\n\tif (inputIsNSString) {\n\t\tstringIn = [[NSMutableAttributedString alloc] initWithString:string];\n\t} else {\n\t\tstringIn = [string mutableCopy];\n\t}\n\n\tif ([stringIn.string hasPrefix:@\"/\"]) {\n\t\t[stringIn deleteCharactersInRange:NSMakeRange(0, 1)];\n\t}\n\n\tNSString *command = stringIn.tokenAsString;\n\n\tNSString *lowercaseCommand = command.lowercaseString;\n\tNSString *uppercaseCommand = command.uppercaseString;\n\n\tIRCClient *selectedClient = mainWindow().selectedClient;\n\tIRCChannel *selectedChannel = mainWindow().selectedChannel;\n\n\tIRCChannel *targetChannel = nil;\n\n\tNSInteger commandNumeric = [IRCCommandIndex indexOfLocalCommand:command];\n\n\tif (completeTarget && targetChannelName != nil) {\n\t\ttargetChannel = [self findChannel:targetChannelName];\n\t} else if (completeTarget && selectedClient == self && selectedChannel) {\n\t\ttargetChannel = selectedChannel;\n\t}\n\n\tswitch (commandNumeric) {\n\t\tcase IRCLocalCommandAme: // Command: AME\n\t\tcase IRCLocalCommandAmsg: // Command: AMSG\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tIRCRemoteCommand sendAsCommand = 0;\n\n\t\t\tif (commandNumeric == IRCLocalCommandAmsg) {\n\t\t\t\tsendAsCommand = IRCRemoteCommandPrivmsg;\n\t\t\t} else {\n\t\t\t\tsendAsCommand = IRCRemoteCommandPrivmsgAction;\n\t\t\t}\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && [TPCPreferences amsgAllConnections] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfor (IRCChannel *channel in client.channelList) {\n\t\t\t\t\tif (channel.isActive == NO || channel.isChannel == NO) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t[client sendText:stringIn asCommand:sendAsCommand toChannel:channel];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandAquote: // Command: AQUOTE\n\t\tcase IRCLocalCommandAraw: // Command: ARAW\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isConnected);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\t[client sendLine:stringIn.string];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandAutojoin: // Command: AUTOJOIN\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\t[self performAutoJoinInitiatedByUser:YES];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandAway: // Command: AWAY\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && [TPCPreferences awayAllConnections] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tNSString *comment = stringIn.string;\n\n\t\t\t\t/* We enforce the maximum away length here instead of\n\t\t\t\t -toggleAwayStatusWithComment: so that we have an easier\n\t\t\t\t way to know when it is truncated so the user can be informed. */\n\t\t\t\tNSUInteger commentMaximumLength = client.supportInfo.maximumAwayLength;\n\n\t\t\t\tif (commentMaximumLength > 0 && comment.length > commentMaximumLength) {\n\t\t\t\t\t[client printDebugInformation:TXTLS(@\"IRC[41y-p2]\", self.networkNameAlt, commentMaximumLength)];\n\t\t\t\t}\n\n\t\t\t\t[client toggleAwayStatusWithComment:comment];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandBack: // Command: BACK\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && [TPCPreferences awayAllConnections] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[client toggleAwayStatus:NO withComment:nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandCap: // Command: CAP\n\t\tcase IRCLocalCommandCaps: // Command: CAPS\n\t\t{\n\t\t\tNSString *capabilities = self.enabledCapabilitiesStringValue;\n\n\t\t\tif (capabilities.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[5wa-lb]\")];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[7p9-rs]\", capabilities)];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandClear: // Command: CLEAR\n\t\t{\n\t\t\tif (targetChannel) {\n\t\t\t\t[mainWindow() clearContentsOfChannel:targetChannel];\n\t\t\t} else {\n\t\t\t\t[mainWindow() clearContentsOfClient:self];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandClearall: // Command: CLEARALL\n\t\t{\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && [TPCPreferences clearAllConnections] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[mainWindow() clearContentsOfClient:client];\n\n\t\t\t\tfor (IRCChannel *channel in client.channelList) {\n\t\t\t\t\t[mainWindow() clearContentsOfChannel:channel];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandClose: // Command: CLOSE\n\t\tcase IRCLocalCommandRemove: // Command: REMOVE\n\t\t{\n\t\t\tNSString *channelName = stringIn.tokenAsString;\n\t\t\t\n\t\t\tif (channelName.length == 0) {\n\t\t\t\tif (targetChannel) {\n\t\t\t\t\t[worldController() destroyChannel:targetChannel];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[pxa-ox]\", channelName)];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t[worldController() destroyChannel:channel];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandConn: // Command: CONN\n\t\t{\n\t\t\tNSString *serverAddress = stringIn.lowercaseGetToken;\n\n\t\t\tif (serverAddress.length > 0) {\n\t\t\t\tif (serverAddress.isValidInternetAddress == NO) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[zef-q9]\")];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tself.temporaryServerAddressOverride = serverAddress;\n\t\t\t}\n\n\t\t\tif (self.isConnecting || self.isConnected) {\n\t\t\t\t__weak IRCClient *weakSelf = self;\n\n\t\t\t\tself.disconnectCallback = ^{\n\t\t\t\t\t[weakSelf connect];\n\t\t\t\t};\n\n\t\t\t\t[self quit];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self connect];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandCtcp: // Command: CTCP\n\t\tcase IRCLocalCommandCtcpreply: // Command: CTCPREPLY\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (targetChannel && targetChannel != selectedChannel) {\n\t\t\t\tif (targetChannel.isUtility) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"sxf-qx\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\n\t\t\tNSString *subCommand = stringIn.uppercaseGetToken;\n\n\t\t\tif (subCommand.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (commandNumeric == IRCLocalCommandCtcp) {\n\t\t\t\tif ([subCommand isEqualToString:@\"PING\"]) {\n\t\t\t\t\t[self sendCTCPPing:targetChannelName];\n\t\t\t\t} else {\n\t\t\t\t\t[self sendCTCPQuery:targetChannelName command:subCommand text:stringIn.string];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t[self sendCTCPReply:targetChannelName command:subCommand text:stringIn.string];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandCycle: // Command: CYCLE\n\t\tcase IRCLocalCommandHop: // Command: HOP\n\t\tcase IRCLocalCommandRejoin: // Command: REJOIN\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (targetChannel == nil || targetChannel.isChannel == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self partChannel:targetChannel];\n\n\t\t\t[self forceJoinChannel:targetChannel.name password:targetChannel.secretKey];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandDehalfop: // Command: DEHALFOP\n\t\tcase IRCLocalCommandDeop: // Command: DEOP\n\t\tcase IRCLocalCommandDevoice: // Command: DEVOICE\n\t\tcase IRCLocalCommandHalfop: // Command: HALFOP\n\t\tcase IRCLocalCommandOp: // Command: OP\n\t\tcase IRCLocalCommandVoice: // Command: VOICE\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\t\t\t\n\t\t\tBOOL modeIsSet = (commandNumeric == IRCLocalCommandOp ||\n\t\t\t\t\t\t\t  commandNumeric == IRCLocalCommandHalfop ||\n\t\t\t\t\t\t\t  commandNumeric == IRCLocalCommandVoice);\n\n\t\t\tNSString *modeSymbol = nil;\n\n\t\t\tif (commandNumeric == IRCLocalCommandOp || commandNumeric == IRCLocalCommandDeop) {\n\t\t\t\tmodeSymbol = @\"o\";\n\t\t\t} else if (commandNumeric == IRCLocalCommandHalfop || commandNumeric == IRCLocalCommandDehalfop) {\n\t\t\t\tmodeSymbol = @\"h\";\n\t\t\t} else if (commandNumeric == IRCLocalCommandVoice || commandNumeric == IRCLocalCommandDevoice) {\n\t\t\t\tmodeSymbol = @\"v\";\n\t\t\t}\n\n\t\t\tif ([self.supportInfo modeSymbolIsUserPrefix:modeSymbol] == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[dwi-d1]\", modeSymbol)];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ([self stringIsChannelName:stringIn.string] == NO) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\t\t\t\n\t\t\tNSString *nicknamesString = stringIn.string;\n\n\t\t\tif (nicknamesString.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSArray *modeChanges =\n\t\t\t[self compileListOfModeChangesForModeSymbol:modeSymbol\n\t\t\t\t\t\t\t\t\t\t\t  modeIsSet:modeIsSet\n\t\t\t\t\t\t\t\t\t\tparameterString:nicknamesString];\n\n\t\t\tfor (NSString *modeChange in modeChanges) {\n\t\t\t\t[self send:@\"MODE\", targetChannelName, modeChange, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandDebug: // Command: DEBUG\n\t\tcase IRCLocalCommandEcho: // Command: ECHO\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tNSString *stringInString = stringIn.string;\n\n\t\t\tif ([stringInString isEqualToStringIgnoringCase:@\"raw on\"])\n\t\t\t{\n\t\t\t\t[self createRawDataLogQuery];\n\t\t\t}\n\t\t\telse if ([stringInString isEqualToStringIgnoringCase:@\"raw off\"])\n\t\t\t{\n\t\t\t\t[self destroyRawDataLogQuery];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[self printDebugInformation:stringInString];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandDefaults: // Command: DEFAULTS\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[1dz-jb]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *action = stringIn.tokenAsString;\n\n\t\t\t/* Present help */\n\t\t\tif ([action isEqualToString:@\"help\"])\n\t\t\t{\n\t\t\t\tNSString *help = TXTLS(@\"IRC[bkk-lo]\");\n\n\t\t\t\t[self printDebugInformationMultiline:help];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Present list of features */\n\t\t\telse if ([action isEqualToString:@\"features\"])\n\t\t\t{\n\t\t\t\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Command-Reference.kb#cr=defaults\" inBackground:NO];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Prepare to toggle feature */\n\t\t\tNSString *feature = stringIn.tokenInsideQuotes.string;\n\n\t\t\tBOOL applyToAll = [feature isEqualToString:@\"-a\"];\n\n\t\t\tif (applyToAll) {\n\t\t\t\tfeature = stringIn.tokenInsideQuotes.string;\n\t\t\t}\n\n\t\t\tNSDictionary *features = @{\n\t\t\t\t@\"Ignore Notifications by Private ZNC Users\"\t\t: @\"setZncIgnoreUserNotifications:\",\n\t\t\t\t@\"Send Authentication Requests to UserServ\"\t\t\t: @\"setSendAuthenticationRequestsToUserServ:\",\n\t\t\t\t@\"Disable Automatic SASL EXTERNAL Response\"\t\t\t: @\"setSaslAuthenticationDisableExternalMechanism:\",\n\t\t\t\t@\"Send WHO Command Requests to Channels\"\t\t\t: @\"setSendWhoCommandRequestsToChannels:\",\n\t\t\t};\n\n\t\t\tBOOL enableFeature = [action isEqualToString:@\"enable\"];\n\n\t\t\t/* Cannot toggle feature if the user doesn't tell us which */\n\t\t\tif (feature.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[1dz-jb]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Make sure the feature exists */\n\t\t\tif ([features containsKey:feature] == NO) {\n\t\t\t\tif (enableFeature) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[pc4-67]\", feature)];\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[d7y-pv]\", feature)];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Toggle the feature by mutating the client's configuration,\n\t\t\t invoking the appropriate method, then saving it. */\n\t\t\tvoid (^toggleFeature)(IRCClient *, NSString *, BOOL) = ^(IRCClient *client, NSString *featureKey, BOOL featureValue) {\n\t\t\t\tNSString *selectorString = features[featureKey];\n\n\t\t\t\tSEL selector = NSSelectorFromString(selectorString);\n\n\t\t\t\tIRCClientConfigMutable *mutableClientConfig = [client.config mutableCopy];\n\n\t\t\t\tNSMethodSignature *signature = [mutableClientConfig methodSignatureForSelector:selector];\n\n\t\t\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t\t\t[invocation setTarget:mutableClientConfig];\n\t\t\t\t[invocation setSelector:selector];\n\n\t\t\t\t[invocation setArgument:&featureValue atIndex:2];\n\n\t\t\t\t[invocation invoke];\n\n\t\t\t\tclient.config = mutableClientConfig;\n\t\t\t};\n\n\t\t\t/* Toggle feature */\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && applyToAll == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttoggleFeature(client, feature, enableFeature);\n\n\t\t\t\tif (enableFeature) {\n\t\t\t\t\t[client printDebugInformation:TXTLS(@\"IRC[5ke-18]\", feature)];\n\t\t\t\t} else {\n\t\t\t\t\t[client printDebugInformation:TXTLS(@\"IRC[0gn-cb]\", feature)];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Save modified client */\n\t\t\t[worldController() save];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandGetscripts: // Command: GETSCRIPTS\n\t\t{\n\t\t\t[sharedPluginManager() extrasInstallerLaunchInstaller];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandGline: // Command: GLINE\n\t\tcase IRCLocalCommandGzline: // Command: GZLINE\n\t\tcase IRCLocalCommandShun:  // Command: SHUN\n\t\tcase IRCLocalCommandTempshun: // Command: TEMPSHUN\n\t\tcase IRCLocalCommandZline: // Command: ZLINE\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSString *segment1 = stringIn.getTokenAsString;\n\t\t\tNSString *segment2 = stringIn.getTokenAsString;\n\n\t\t\t[self send:uppercaseCommand, segment1, segment2, stringIn.string, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandGoto: // Command: GOTO\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *needle = stringIn.tokenAsString;\n\n\t\t\tIRCTreeItem *bestMatch = mainWindow().selectedItem;\n\n\t\t\tCGFloat bestScore = 0.0;\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tfor (IRCChannel *channel in client.channelList) {\n\t\t\t\t\tCGFloat currentScore = [channel.name compareWithWord:needle lengthPenaltyWeight:0.1];\n\n\t\t\t\t\tif (currentScore > bestScore) {\n\t\t\t\t\t\tbestMatch = channel;\n\n\t\t\t\t\t\tbestScore = currentScore;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[mainWindow() select:bestMatch];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandIgnore: // Command: IGNORE\n\t\tcase IRCLocalCommandUnignore: // Command: UNIGNORE\n\t\t{\n\t\t\tBOOL isIgnoreCommand = (commandNumeric == IRCLocalCommandIgnore);\n\n\t\t\tif (stringIn.length == 0 || targetChannel == nil) {\n\t\t\t\tif (isIgnoreCommand) {\n\t\t\t\t\t[menuController() showServerPropertiesSheetForClient:self withSelection:TDCServerPropertiesSheetSelectionNewIgnoreEntry context:@\"\"];\n\t\t\t\t} else {\n\t\t\t\t\t[menuController() showServerPropertiesSheetForClient:self withSelection:TDCServerPropertiesSheetSelectionAddressBook context:nil];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *nickname = stringIn.tokenAsString;\n\n\t\t\tIRCUser *member = [self findUser:nickname];\n\n\t\t\tif (member == nil) {\n\t\t\t\tif (isIgnoreCommand) {\n\t\t\t\t\t[menuController() showServerPropertiesSheetForClient:self withSelection:TDCServerPropertiesSheetSelectionNewIgnoreEntry context:nickname];\n\t\t\t\t} else {\n\t\t\t\t\t[menuController() showServerPropertiesSheetForClient:self withSelection:TDCServerPropertiesSheetSelectionAddressBook context:nil];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Build list of ignores that already match the user's host */\n\t\t\tNSString *hostmask = member.hostmask;\n\n\t\t\tif (hostmask == nil) {\n\t\t\t\thostmask = [NSString stringWithFormat:@\"%@!*@*\", nickname];\n\t\t\t}\n\n\t\t\tNSMutableArray *matchedIgnores = [NSMutableArray array];\n\n\t\t\tfor (IRCAddressBookEntry *ignore in self.config.ignoreList) {\n\t\t\t\tif (ignore.entryType != IRCAddressBookEntryTypeIgnore) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ([ignore checkMatch:hostmask]) {\n\t\t\t\t\t[matchedIgnores addObject:ignore];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Cancel if there is nothing to change */\n\t\t\tif (isIgnoreCommand) {\n\t\t\t\tif (matchedIgnores.count > 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[5ix-zn]\", member.nickname)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (matchedIgnores.count == 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[wu0-jp]\", member.nickname)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (matchedIgnores.count > 1) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[vrx-1f]\", member.nickname)];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Modify ignore list and inform user of change */\n\t\t\tNSMutableArray *mutableIgnoreList = [self.config.ignoreList mutableCopy];\n\n\t\t\tif (isIgnoreCommand) {\n\t\t\t\tIRCAddressBookEntry *ignore =\n\t\t\t\t[IRCAddressBookEntry newIgnoreEntryForHostmask:member.banMask];\n\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[ret-20]\", member.nickname, ignore.hostmask)];\n\n\t\t\t\t[mutableIgnoreList addObject:ignore];\n\t\t\t} else{\n\t\t\t\tIRCAddressBookEntry *ignore = matchedIgnores[0];\n\t\t\t\t\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[jzg-g8]\", member.nickname, ignore.hostmask)];\n\n\t\t\t\t[mutableIgnoreList removeObjectIdenticalTo:ignore];\n\t\t\t}\n\n\t\t\t/* Save modified ignore list */\n\t\t\tIRCClientConfigMutable *mutableClientConfig = [self.config mutableCopy];\n\n\t\t\tmutableClientConfig.ignoreList = mutableIgnoreList;\n\n\t\t\tself.config = mutableClientConfig;\n\t\t\t\n\t\t\t/* Clear cache */\n\t\t\t/* If we have a host, then it's easy to clear only that.\n\t\t\t If we don't have a host, then we have to clear everything. */\n\t\t\tif (hostmask) {\n\t\t\t\t[self clearAddressBookCacheForHostmask:hostmask];\n\t\t\t} else {\n\t\t\t\t[self clearAddressBookCache];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandInvite: // Command: INVITE\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSArray *nicknames = [stringIn.string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tif ([self stringIsChannelName:nicknames.lastObject] == NO) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = nicknames.lastObject;\n\t\t\t\t\n\t\t\t\tnicknames = [nicknames subarrayWithRange:NSMakeRange(0, (nicknames.count - 1))];\n\t\t\t}\n\n\t\t\tfor (NSString *nickname in nicknames) {\n\t\t\t\tif ([self stringIsNickname:nickname] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[self send:@\"INVITE\", nickname, targetChannelName, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandIson: // Command: ISON\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self createHiddenCommandResponses];\n\n\t\t\t[self.requestedCommands recordIsonRequestOpenedAsVisible];\n\n\t\t\t[self send:@\"ISON\", stringIn.string, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandJ: // Command: J\n\t\tcase IRCLocalCommandJoin:  // Command: JOIN\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\n\t\t\t\tif (targetChannelName.length == 0) {\n\t\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ([self stringIsChannelNameOrZero:targetChannelName] == NO) {\n\t\t\t\t\ttargetChannelName = [@\"#\" stringByAppendingString:targetChannelName];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[self joinUnlistedChannelsWithStringAndSelectBestMatch:targetChannelName passwords:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandJoinRandom: // Command: JOIN_RANDOM\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSInteger numberOfChannelsToJoin = 0;\n\n\t\t\tNSString *numberOfChannelsToken = stringIn.tokenAsString;\n\n\t\t\tif (numberOfChannelsToken.isNumericOnly) {\n\t\t\t\tnumberOfChannelsToJoin = numberOfChannelsToken.integerValue;\n\t\t\t}\n\n\t\t\tif (numberOfChannelsToJoin <= 0) {\n\t\t\t\tnumberOfChannelsToJoin = 1;\n\t\t\t}\n\n\t\t\tfor (NSUInteger i = 0; i < numberOfChannelsToJoin; i++) {\n\t\t\t\tNSString *channelName = [NSString stringWithFormat:@\"#debug-channel-%lu\", TXRandomNumber(9999999)];\n\n\t\t\t\t[self send:@\"JOIN\", channelName, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandBan: // Command: BAN\n\t\tcase IRCLocalCommandKb: // Command: KB\n\t\tcase IRCLocalCommandKick: // Command: KICK\n\t\tcase IRCLocalCommandKickban: // Command: KICKBAN\n\t\tcase IRCLocalCommandUnban: // Command: UNBAN\n\t\tcase IRCLocalCommandUnquiet: // Command: UNQUIET\n\t\tcase IRCLocalCommandQuiet: // Command: QUIET\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSString *nickname = stringIn.tokenAsString;\n\n\t\t\tif ([self stringIsChannelName:nickname] == NO) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = nickname;\n\n\t\t\t\ttargetChannel = [self findChannel:targetChannelName];\n\t\t\t\t\n\t\t\t\tnickname = stringIn.tokenAsString;\n\t\t\t}\n\n\t\t\tif (nickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (commandNumeric == IRCLocalCommandKickban ||\n\t\t\t\tcommandNumeric == IRCLocalCommandKb ||\n\t\t\t\tcommandNumeric == IRCLocalCommandBan ||\n\t\t\t\tcommandNumeric == IRCLocalCommandUnban ||\n\t\t\t\tcommandNumeric == IRCLocalCommandQuiet ||\n\t\t\t\tcommandNumeric == IRCLocalCommandUnquiet)\n\t\t\t{\n\t\t\t\tIRCChannelUser *member = [targetChannel findMember:nickname];\n\n\t\t\t\tNSString *banMask = member.user.banMask;\n\n\t\t\t\tif (banMask == nil) {\n\t\t\t\t\tbanMask = nickname;\n\t\t\t\t}\n\n\t\t\t\tNSString *modeSymbol = nil;\n\n\t\t\t\tif (commandNumeric == IRCLocalCommandQuiet ||\n\t\t\t\t\tcommandNumeric == IRCLocalCommandUnquiet)\n\t\t\t\t{\n\t\t\t\t\tmodeSymbol = @\"q\";\n\t\t\t\t} else {\n\t\t\t\t\tmodeSymbol = @\"b\";\n\t\t\t\t}\n\n\t\t\t\tif ([self.supportInfo modeSymbolIsUserPrefix:modeSymbol]) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[dwi-d1]\", modeSymbol)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (commandNumeric == IRCLocalCommandUnban ||\n\t\t\t\t\tcommandNumeric == IRCLocalCommandUnquiet)\n\t\t\t\t{\n\t\t\t\t\t[self send:@\"MODE\", targetChannelName, [@\"-\" stringByAppendingString:modeSymbol], banMask, nil];\n\t\t\t\t} else {\n\t\t\t\t\t[self send:@\"MODE\", targetChannelName, [@\"+\" stringByAppendingString:modeSymbol], banMask, nil];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (commandNumeric == IRCLocalCommandKb ||\n\t\t\t\tcommandNumeric == IRCLocalCommandKick ||\n\t\t\t\tcommandNumeric == IRCLocalCommandKickban)\n\t\t\t{\n\t\t\t\tNSString *reason = stringIn.string;\n\n\t\t\t\tif (reason.length == 0) {\n\t\t\t\t\treason = [TPCPreferences defaultKickMessage];\n\t\t\t\t}\n\n\t\t\t\tNSUInteger reasonMaximumLength = self.supportInfo.maximumKickLength;\n\n\t\t\t\tif (reasonMaximumLength > 0 && reason.length > reasonMaximumLength) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[59a-ir]\", self.networkNameAlt, reasonMaximumLength)];\n\t\t\t\t}\n\n\t\t\t\t[self send:@\"KICK\", targetChannelName, nickname, reason, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandKill: // Command: KILL\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSString *nickname = stringIn.getTokenAsString;\n\n\t\t\tif (nickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *reason = stringIn.string;\n\n\t\t\tif (reason.length == 0) {\n\t\t\t\treason = [TPCPreferences IRCopDefaultKillMessage];\n\t\t\t}\n\n\t\t\t[self send:@\"KILL\", nickname, reason, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandLagcheck: // Command: LAGCHECK\n\t\tcase IRCLocalCommandMylag: // Command: MYLAG\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\t/* We only accept LAGCHECK CTCP responses from ourselves which\n\t\t\t means it is relatively safe to pack some data on the end of\n\t\t\t the CTCP so that we can provide ourselves some context. */\n\t\t\tNSMutableDictionary *lagCheckContext = [NSMutableDictionary dictionaryWithCapacity:3];\n\n\t\t\tlagCheckContext[@\"connection\"] = self.socket.uniqueIdentifier;\n\t\t\t\n\t\t\tlagCheckContext[@\"time\"] = @([NSDate timeIntervalSince1970]);\n\n\t\t\tif (commandNumeric == IRCLocalCommandMylag) {\n\t\t\t\tIRCChannel *selectedChannel = [mainWindow() selectedChannelOn:self];\n\t\t\t\t\n\t\t\t\tif (selectedChannel) {\n\t\t\t\t\tlagCheckContext[@\"channel\"] = selectedChannel.name;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tNSString *ctcpContext = [lagCheckContext formDataUsingSeparator:@\"&\"];\n\n\t\t\t[self sendCTCPQuery:self.userNickname\n\t\t\t\t\t\tcommand:@\"LAGCHECK\"\n\t\t\t\t\t\t   text:ctcpContext];\n\n\t\t\t[self printDebugInformation:TXTLS(@\"IRC[qoh-kt]\")];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandLeave: // Command: LEAVE\n\t\tcase IRCLocalCommandPart: // Command: PART\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif ([self stringIsChannelName:stringIn.string] == NO) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else if (targetChannel) {\n\t\t\t\t\t[worldController() destroyChannel:targetChannel];\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\t\t\t\n\t\t\tNSString *reason = stringIn.string;\n\n\t\t\tif (reason.length == 0) {\n\t\t\t\treason = self.config.normalLeavingComment;\n\t\t\t}\n\n\t\t\t[self send:@\"PART\", targetChannelName, reason, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandList: // Command: LIST\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tTDCServerChannelListDialog *channelListDialog = [self channelListDialog];\n\n\t\t\tif (channelListDialog == nil) {\n\t\t\t\t[self createChannelListDialog];\n\t\t\t}\n\n\t\t\t[self requestChannelList];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandM: // Command: M\n\t\tcase IRCLocalCommandMode: // Command: MODE\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSString *modeString = stringIn.string;\n\n\t\t\tif (  modeString.length == 0 ||\n\t\t\t\t([modeString hasPrefix:@\"+\"] ||\n\t\t\t\t [modeString hasPrefix:@\"-\"]))\n\t\t\t{\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\n\t\t\tif (modeString.length == 0) {\n\t\t\t\t[self send:@\"MODE\", targetChannelName, nil];\n\t\t\t} else {\n\t\t\t\t[self send:@\"MODE\", targetChannelName, modeString, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandMute: // Command: MUTE\n\t\t{\n\t\t\tif ([TPCPreferences soundIsMuted]) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[sdn-yr]\")];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[u48-aa]\")];\n\n\t\t\t\t[menuController() toggleMuteOnNotificationSoundsShortcutOn:YES];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandMyversion: // Command: MYVERSION\n\t\t{\n\t\t\tNSString *applicationName = [TPCApplicationInfo applicationNameWithoutVersion];\n\t\t\tNSString *versionLong = [TPCApplicationInfo applicationVersion];\n\t\t\tNSString *versionShort = [TPCApplicationInfo applicationVersionShort];\n//\t\t\tNSString *buildScheme = [TPCApplicationInfo applicationBuildScheme];\n\n\t\t\tNSString *downloadSource = @\"\"; // Assume standalone by default\n\t\t\tNSString *buildType = @\"\"; // Assume universal binary by default\n\n#if TEXTUAL_BUILT_AS_UNIVERSAL_BINARY == 0\n\t\t\tNSString *hostType = nil;\n\n#if TARGET_CPU_ARM64\n\t\t\thostType = TXTLS(@\"IRC[g1u-os]\");\n#elif TARGET_CPU_X86_64\n\t\t\thostType = TXTLS(@\"IRC[swz-uj]\");\n#endif\n\n\t\t\tbuildType = TXTLS(@\"IRC[b8p-44]\", hostType);\n#endif // Universal\n\n\t\t\tNSString *message = TXTLS(@\"IRC[ccb-ur]\", applicationName, versionShort, versionLong, downloadSource, buildType);\n\n\t\t\tif (targetChannel) {\n\t\t\t\tmessage = TXTLS(@\"IRC[pqj-1y]\", message);\n\n\t\t\t\t[self sendPrivmsg:message toChannel:targetChannel];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformationToConsole:message];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandNick: // Command: NICK\n\t\t{\n\t\t\t/* Use -isConnected instead of -isLoggedIn so that\n\t\t\t user can change their nickname during registration\n\t\t\t phase before the 001 numeric is received. */\n\t\t\tNSAssertReturnLoopBreak(self.isConnected);\n\t\t\t\n\t\t\tNSString *newNickname = stringIn.tokenAsString;\n\t\t\t\n\t\t\tif (newNickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfor (IRCClient *client in worldController().clientList) {\n\t\t\t\tif (client != self && [TPCPreferences nickAllConnections] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[client changeNickname:newNickname];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandNotifybubble: // Command: NOTIFYBUBBLE\n\t\t{\n\t\t\tif ([self stringIsChannelName:stringIn.string]) {\n\t\t\t\ttargetChannel = [self findChannel:stringIn.tokenAsString];\n\t\t\t} else {\n\t\t\t\ttargetChannel = nil;\n\t\t\t}\n\t\t\t\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *title = [TPCApplicationInfo applicationNameWithoutVersion];\n\n\t\t\tNSString *message = stringIn.string;\n\n\t\t\t[sharedNotificationController() scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  message:message\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   forChannel:targetChannel\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t onClient:self];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandNotifysound: // Command: NOTIFYSOUND\n\t\t{\n\t\t\tNSString *soundName = stringIn.tokenAsString;\n\t\t\t\n\t\t\tif (soundName.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[TLOSoundPlayer playAlertSound:soundName];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandNotifyspeak: // Command: NOTIFYSPEAK\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t[[TXSharedApplication sharedSpeechSynthesizer] speak:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandQuery: // Command: QUERY\n\t\t{\n\t\t\tNSString *nickname = stringIn.tokenAsString;\n\t\t\t\n\t\t\tif (nickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ([self stringIsNickname:nickname] == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[zef-q9]\")];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tIRCChannel *query = [self findChannelOrCreate:nickname isPrivateMessage:YES];\n\n\t\t\t[mainWindow() select:query];\n\n\t\t\tif (stringIn.length > 0) {\n\t\t\t\t[self sendText:stringIn asCommand:IRCRemoteCommandPrivmsg toChannel:query];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandQuote: // Command: QUOTE\n\t\tcase IRCLocalCommandRaw: // Command: RAW\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isConnected);\n\t\t\t\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\t[self sendLine:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandQuit: // Command: QUIT\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isConnected);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self quit];\n\t\t\t} else {\n\t\t\t\t[self quitWithComment:stringIn.string];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandNames: // Command: NAMES\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self createHiddenCommandResponses];\n\n\t\t\t[self send:@\"NAMES\", stringIn.string, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandRecv: // Command: RECV\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self ircConnection:self.socket didReceiveData:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandSetcolor: // Command: SETCOLOR\n\t\t{\n\t\t\tif ([TPCPreferences disableNicknameColorHashing]) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[026-qv]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *nickname = stringIn.lowercaseGetToken;\n\n\t\t\tif (nickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ([self stringIsNickname:nickname] == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[8dy-6f]\", nickname)];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[menuController() memberChangeColor:nickname];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandSetqueryname: // Command: SETQUERYNAME\n\t\t{\n\t\t\tif (targetChannel == nil || targetChannel.isPrivateMessage == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[m6o-z1]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *nickname = stringIn.getTokenAsString;\n\n\t\t\tif (nickname.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif ([self stringIsNickname:nickname] == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[zef-q9]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tIRCChannel *oldQuery = [self findChannel:nickname];\n\n\t\t\tif (oldQuery) {\n\t\t\t\tBOOL deleteOldQuery =\n\t\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[61s-jc]\")\n\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[d22-76]\", oldQuery.name)\n\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\talternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\t\t\t\tif (deleteOldQuery) {\n\t\t\t\t\t[worldController() destroyChannel:oldQuery];\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttargetChannel.name = nickname;\n\n\t\t\t[mainWindow() reloadTreeItem:targetChannel];\n\n\t\t\t[mainWindow() updateTitleFor:targetChannel];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandServer: // Command: SERVER\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[IRCExtras createConnectionToServer:stringIn.string channelList:nil connectWhenCreated:YES];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandSslcontext: // Command: SSLCONTEXT\n\t\t{\n\t\t\t[self presentCertificateTrustInformation];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandTage: // Command: TAGE\n\t\t{\n\t\t\tNSTimeInterval timePassed = [NSDate timeIntervalSinceNow:[TPCApplicationInfo applicationBirthday]];\n\n\t\t\tNSString *message = TXTLS(@\"IRC[v9x-18]\", TXHumanReadableTimeInterval(timePassed, NO, 0));\n\n\t\t\tif (targetChannel) {\n\t\t\t\t[self sendPrivmsg:message toChannel:targetChannel];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformationToConsole:message];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandTimer: // Command: TIMER\n\t\t{\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[jj9-94]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *action = stringIn.tokenAsString;\n\n\t\t\t/* Present help */\n\t\t\tif ([action isEqualToString:@\"help\"])\n\t\t\t{\n\t\t\t\tNSString *topic = stringIn.tokenAsString;\n\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[aox-zz]\")]; // divider\n\n\t\t\t\tif ([topic isEqualToStringIgnoringCase:@\"add\"])\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[6r0-il]\")];\n\t\t\t\t}\n\t\t\t\telse if ([topic isEqualToStringIgnoringCase:@\"remove\"])\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[i2d-x5]\")];\n\t\t\t\t}\n\t\t\t\telse if ([topic isEqualToStringIgnoringCase:@\"list\"])\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[x1n-ve]\")];\n\t\t\t\t}\n\t\t\t\telse if ([topic isEqualToStringIgnoringCase:@\"stop\"])\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[bx2-n1]\")];\n\t\t\t\t}\n\t\t\t\telse if ([topic isEqualToStringIgnoringCase:@\"restart\"])\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[r27-tv]\")];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[self printDebugInformationMultiline:TXTLS(@\"IRC[xkq-rt]\")];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Stop timer */\n\t\t\tif ([action isEqualToString:@\"stop\"])\n\t\t\t{\n\t\t\t\tNSString *identifier = stringIn.tokenAsString;\n\n\t\t\t\tif (identifier.length == 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[p6l-o4]\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tIRCTimedCommand *timedCommand = [self timedCommandWithIdentifier:identifier];\n\n\t\t\t\tif (timedCommand == nil) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[vzu-xh]\", identifier)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (timedCommand.timerIsActive == NO) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[ax6-n9]\", identifier)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t[self stopTimedCommand:timedCommand];\n\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[hs0-up]\", identifier)];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Restart timer */\n\t\t\tif ([action isEqualToString:@\"restart\"])\n\t\t\t{\n\t\t\t\tNSString *identifier = stringIn.tokenAsString;\n\n\t\t\t\tif (identifier.length == 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[p6l-o4]\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tIRCTimedCommand *timedCommand = [self timedCommandWithIdentifier:identifier];\n\n\t\t\t\tif (timedCommand == nil) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[vzu-xh]\", identifier)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ([self restartTimedCommand:timedCommand]) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[qb7-mi]\", identifier)];\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[dgp-d4]\", identifier)];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Remove timer */\n\t\t\tif ([action isEqualToString:@\"remove\"])\n\t\t\t{\n\t\t\t\tNSString *identifier = stringIn.tokenAsString;\n\n\t\t\t\tif (identifier.length == 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[p6l-o4]\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ([identifier isEqualToStringIgnoringCase:@\"all\"]) {\n\t\t\t\t\t[self removeTimedCommands];\n\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[808-bs]\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tIRCTimedCommand *timedCommand = [self timedCommandWithIdentifier:identifier];\n\n\t\t\t\tif (timedCommand == nil) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[vzu-xh]\", identifier)];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t[self removeTimedCommand:timedCommand];\n\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[p7s-is]\", identifier)];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* List timers */\n\t\t\tif ([action isEqualToString:@\"list\"])\n\t\t\t{\n\t\t\t\tNSArray *timedCommands = [self listOfTimedCommands];\n\n\t\t\t\tNSUInteger numberOfTimers = timedCommands.count;\n\n\t\t\t\tif (numberOfTimers == 0) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[pqk-5k]\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if (numberOfTimers == 1) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[6ts-oi]\", numberOfTimers)];\n\t\t\t\t} else {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[q1m-1e]\", numberOfTimers)];\n\t\t\t\t}\n\n\t\t\t\tfor (IRCTimedCommand *timedCommand in timedCommands) {\n\t\t\t\t\tNSString *description = [self descriptionForTimedCommand:timedCommand];\n\n\t\t\t\t\t[self printDebugInformation:description];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Add timer */\n\t\t\t/*\n\t\t\t This command is designed to be backwards compatible.\n\n\t\t\t Old syntax:\n\t\t\t \"/timer <seconds> <command>\"\n\n\t\t\t New syntax:\n\t\t\t \"/timer <seconds> <repeat> <command>\"\n\n\t\t\t We check the value of the second argument. If it's a number,\n\t\t\t then we treat it as the new syntax which means that number\n\t\t\t is the repeat count for the timer.\n\t\t\t */\n\n\t\t\t/* Parse interval */\n\t\t\tNSString *intervalString = action;\n\n\t\t\tif (intervalString.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[jj9-94]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSInteger interval = intervalString.integerValue;\n\n\t\t\tif (interval <= 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[327-pv]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Parse repeat count and/or command */\n\t\t\t/*\n\t\t\t Repeat argument is treated as such:\n\t\t\t   == 0 — repeat and never stop\n\t\t\t   == 1 - perform timer once, do not repeat\n\t\t\t   > 1 — repeat number of times\n\t\t\t */\n\t\t\tNSString *repeatString = stringIn.tokenAsString;\n\n\t\t\tNSInteger repeat = NSNotFound;\n\n\t\t\tNSString *command = stringIn.trimmedString;\n\n\t\t\tif ([repeatString contentsIsOfType:CSStringTypeAnyNumber])\n\t\t\t{\n\t\t\t\t/* Contents of second argument is a number,\n\t\t\t\t which means we want to treat it as the repeat count. */\n\t\t\t\trepeat = repeatString.integerValue;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/* Contents of second argument is NOT a number,\n\t\t\t\t which means we need to merge that back with the\n\t\t\t\t remainder of the command value. */\n\t\t\t\tif (command.length == 0) {\n\t\t\t\t\tcommand = repeatString;\n\t\t\t\t} else {\n\t\t\t\t\tcommand = [repeatString stringByAppendingFormat:@\" %@\", command];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Perform additional validation */\n\t\t\tif (repeat < 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[eud-kc]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (command.length == 0) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[jj9-94]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* If we have no repeat value, then treat is one pass. */\n\t\t\tif (repeat == NSNotFound) {\n\t\t\t\trepeat = 1;\n\t\t\t}\n\n\t\t\t/* Add timer */\n\t\t\tIRCTimedCommand *timedCommand = nil;\n\n\t\t\tif (targetChannel == nil) {\n\t\t\t\ttimedCommand = [[IRCTimedCommand alloc] initWithCommand:command onClient:self];\n\t\t\t} else {\n\t\t\t\ttimedCommand = [[IRCTimedCommand alloc] initWithCommand:command onClient:self inChannel:targetChannel];\n\t\t\t}\n\n\t\t\t[self addTimedCommand:timedCommand];\n\n\t\t\t[self startTimedCommand:timedCommand interval:interval onRepeat:(repeat != 1) iterations:repeat];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandT: // Command: T\n\t\tcase IRCLocalCommandTopic: // Command: TOPIC\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif ([self stringIsChannelName:stringIn.string] == NO) {\n\t\t\t\tif (targetChannel && targetChannel.isChannel) {\n\t\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\n\t\t\tNSString *topic = stringIn.stringFormattedForIRC;\n\n\t\t\tNSUInteger topicLength = topic.length;\n\n\t\t\tif (topicLength == 0) {\n\t\t\t\t[self send:@\"TOPIC\", targetChannelName, nil];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSUInteger topicLengthMaximum = self.supportInfo.maximumTopicLength;\n\n\t\t\tif (topicLengthMaximum > 0 && topicLength > topicLengthMaximum) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[1oo-3b]\", self.networkNameAlt, topicLengthMaximum)];\n\t\t\t}\n\n\t\t\t[self send:@\"TOPIC\", targetChannelName, topic, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandUmode: // Command: UMODE\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self send:@\"MODE\", self.userNickname, nil];\n\t\t\t} else {\n\t\t\t\t[self send:@\"MODE\", self.userNickname, stringIn.string, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandUnmute: // Command: UNMUTE\n\t\t{\n\t\t\tif ([TPCPreferences soundIsMuted] == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[5rf-mj]\")];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[190-f2]\")];\n\n\t\t\t\t[menuController() toggleMuteOnNotificationSoundsShortcutOn:NO];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandWallops: // Command: WALLOPS\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self send:@\"WALLOPS\", stringIn.string, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandMonitor: // Command: MONITOR\n\t\tcase IRCLocalCommandWatch: // Command: WATCH\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tBOOL isClearCommand = NO;\n\t\t\tBOOL isModifierCommand = NO;\n\n\t\t\t/* UnrealIRCd splits arguments using space and loops through all of them\n\t\t\t which means a modifier or clear command can appear at the same time. */\n\t\t\tNSArray *arguments = [stringIn.string componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *argument in arguments) {\n\t\t\t\tif ([argument hasPrefix:@\"-\"] || [stringIn.string hasPrefix:@\"+\"] ) {\n\t\t\t\t\tisModifierCommand = YES;\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if ([argument isEqualIgnoringCase:@\"c\"]) {\n\t\t\t\t\tisClearCommand = YES;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isModifierCommand) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[khw-4y]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* The clear command doesn't produce a result */\n\t\t\tif (isClearCommand == NO) {\n\t\t\t\t[self createHiddenCommandResponses];\n\t\t\t}\n\n\t\t\t[self sendCommand:uppercaseCommand withData:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandWho: // Command: WHO\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self createHiddenCommandResponses];\n\n\t\t\t[self.requestedCommands recordWhoRequestOpenedAsVisible];\n\n\t\t\t[self send:@\"WHO\", stringIn.string, nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandWeights: // Command: WEIGHTS\n\t\t{\n\t\t\tif (targetChannel == nil || targetChannel.isChannel == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[g01-qn]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self printDebugInformation:TXTLS(@\"IRC[zud-u3]\", targetChannel.name)];\n\n\t\t\tBOOL haveWeights = NO;\n\n\t\t\tfor (IRCChannelUser *member in targetChannel.memberList) {\n\t\t\t\tdouble incomingWeight = member.incomingWeight;\n\t\t\t\tdouble outgoingWeight = member.outgoingWeight;\n\n\t\t\t\tCGFloat weight = (incomingWeight + outgoingWeight);\n\n\t\t\t\tif (weight > 0) {\n\t\t\t\t\thaveWeights = YES;\n\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[24r-8c]\",\n\t\t\t\t\t\t\tmember.user.nickname, outgoingWeight, incomingWeight, weight)];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (haveWeights == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[dje-41]\")];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandWhois: // Command: WHOIS\n\t\t{\n\t\t\tNSAssertReturnLoopBreak(self.isLoggedIn);\n\n\t\t\tNSString *nickname1 = stringIn.tokenAsString;\n\n\t\t\tif (nickname1.length == 0) {\n\t\t\t\tif (targetChannel && targetChannel.isPrivateMessage) {\n\t\t\t\t\tnickname1 = targetChannel.name;\n\t\t\t\t} else {\n\t\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tNSString *nickname2 = stringIn.tokenAsString;\n\t\n\t\t\tif (nickname2.length == 0) {\n\t\t\t\t[self send:@\"WHOIS\", nickname1, nickname1, nil];\n\t\t\t} else {\n\t\t\t\t[self send:@\"WHOIS\", nickname1, nickname2, nil];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCLocalCommandMe: // Command: ME\n\t\tcase IRCLocalCommandMsg: // Command: MSG\n\t\tcase IRCLocalCommandNotice: // Command: NOTICE\n\t\tcase IRCLocalCommandOmsg: // Command: OMSG\n\t\tcase IRCLocalCommandOnotice: // Command: ONOTICE\n\t\tcase IRCLocalCommandSme: // Command: SME\n\t\tcase IRCLocalCommandSmsg: // Command: SMSG\n\t\tcase IRCLocalCommandUme: // Command: UME\n\t\tcase IRCLocalCommandUmsg: // Command: UMSG\n\t\tcase IRCLocalCommandUnotice: // Command: UNOTICE\n\t\t{\n\t\t\t/* Where would se send data to? */\n\t\t\tif (self.isLoggedIn == NO) {\n\t\t\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[6rj-2r]\")];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Establish context for comand */\n\t\t\tNSString *channelNamePrefix = nil;\n\n\t\t\tBOOL isOperatorMessage = NO;\n\t\t\tBOOL isSecretMessage = NO;\n\t\t\tBOOL isUnencryptedMessage = NO;\n\n\t\t\tNSString *commandToSend = nil;\n\n\t\t\tTVCLogLineType lineType = TVCLogLineTypeUndefined;\n\n\t\t\tif (commandNumeric == IRCLocalCommandMsg ||\n\t\t\t\tcommandNumeric == IRCLocalCommandOmsg ||\n\t\t\t\tcommandNumeric == IRCLocalCommandSmsg ||\n\t\t\t\tcommandNumeric == IRCLocalCommandUmsg)\n\t\t\t{\n\t\t\t\tcommandToSend = @\"PRIVMSG\";\n\n\t\t\t\tlineType = TVCLogLineTypePrivateMessage;\n\n\t\t\t\tisOperatorMessage = (commandNumeric == IRCLocalCommandOmsg);\n\t\t\t\tisSecretMessage = (commandNumeric == IRCLocalCommandSmsg);\n\t\t\t\tisUnencryptedMessage = (commandNumeric == IRCLocalCommandUmsg);\n\t\t\t}\n\t\t\telse if (commandNumeric == IRCLocalCommandMe ||\n\t\t\t\t\t commandNumeric == IRCLocalCommandSme ||\n\t\t\t\t\t commandNumeric == IRCLocalCommandUme)\n\t\t\t{\n\t\t\t\tcommandToSend = @\"PRIVMSG\";\n\n\t\t\t\tlineType = TVCLogLineTypeAction;\n\n\t\t\t\tisSecretMessage = (commandNumeric == IRCLocalCommandSme);\n\t\t\t\tisUnencryptedMessage = (commandNumeric == IRCLocalCommandUme);\n\t\t\t}\n\t\t\telse if (commandNumeric == IRCLocalCommandNotice || // Command: NOTICE\n\t\t\t\t\t commandNumeric == IRCLocalCommandOnotice || // Command: ONOTICE\n\t\t\t\t\t commandNumeric == IRCLocalCommandUnotice)   // Command: UNOTICE\n\t\t\t{\n\t\t\t\tcommandToSend = @\"NOTICE\";\n\n\t\t\t\tlineType = TVCLogLineTypeNotice;\n\n\t\t\t\tisOperatorMessage = (commandNumeric == IRCLocalCommandOnotice);\n\t\t\t\tisUnencryptedMessage = (commandNumeric == IRCLocalCommandUnotice);\n\t\t\t}\n\n\t\t\tif (isOperatorMessage) {\n\t\t\t\tchannelNamePrefix = [self.supportInfo statusMessagePrefixForModeSymbol:@\"o\"];\n\n\t\t\t\t/* If the user is sending an operator message and the user mode +o does \n\t\t\t\t not exist, then fail here. The user may be trying to send something \n\t\t\t\t secret with an expectation for privacy and we cannot deliver that. */\n\t\t\t\tif (channelNamePrefix == nil) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[54l-h7]\", @\"o\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Pick the best target */\n\t\t\t/* All actions except (SME) should use the target channel */\n\t\t\t/* Operator messages should use the target channel unless the\n\t\t\t string in is a channel name */\n\t\t\t/* All other scenarios use the string in (token) */\n\t\t\tif (isSecretMessage == NO && lineType == TVCLogLineTypeAction && targetChannel) {\n\t\t\t\tif (targetChannel.isUtility) {\n\t\t\t\t\t[self printDebugInformation:TXTLS(@\"sxf-qx\")];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t} else if (isOperatorMessage && [self stringIsChannelName:stringIn.string] == NO && targetChannel.isChannel) {\n\t\t\t\ttargetChannelName = targetChannel.name;\n\t\t\t} else {\n\t\t\t\ttargetChannelName = stringIn.tokenAsString;\n\t\t\t}\n\n\t\t\tif (targetChannelName.length == 0) {\n\t\t\t\t[self printInvalidSyntaxMessageForCommand:command];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Actions are allowed to have an empty message but all other\n\t\t\t types are not. Empty actions use a whitespace. */\n\t\t\tif (stringIn.length == 0) {\n\t\t\t\tif (lineType == TVCLogLineTypeAction) {\n\t\t\t\t\t[stringIn replaceCharactersInRange:NSMakeRange(0, 0)\n\t\t\t\t\t\t\t\t\t\t\twithString:@\" \"];\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* At this point, the following will occur:\n\t\t\t 1. Each destination is looped over\n\t\t\t\t1. Prefix characters are removed from the destination name\n\t\t\t\t2. Try to find channel that already exists which matches\n\t\t\t\t   the destination. If a channel does not exist, then we \n\t\t\t\t   create one depending on whether this is a secret message.\n\t\t\t\t3. The message is then encrypted and sent off.\n\t\t\t */\n\t\t\tNSArray *destinations = [targetChannelName componentsSeparatedByString:@\",\"];\n\n\t\t\tIRCChannel *destinationToSelect = nil;\n\n\t\t\tfor (__strong NSString *destinationName in destinations) {\n\t\t\t\t/* If the user prefixed the target with a mode (e.g. +#channel)\n\t\t\t\t to indicate that they want the message only seen by that group\n\t\t\t\t of users, then we first have to remove that prefix to perform\n\t\t\t\t our own processing of the target. When it comes time to send \n\t\t\t\t the message, then the prefix is added back to the target name. */\n\t\t\t\tNSString *destinationNamePrefix = [self.supportInfo extractStatusMessagePrefixFromChannelNamed:destinationName];\n\n\t\t\t\tif (destinationNamePrefix.length == 0) {\n\t\t\t\t\tdestinationNamePrefix = channelNamePrefix;\n\t\t\t\t} else {\n\t\t\t\t\tdestinationName = [destinationName substringFromIndex:1];\n\t\t\t\t}\n\n\t\t\t\t/* Locate object that matches destination */\n\t\t\t\tIRCChannel *destination = [self findChannel:destinationName];\n\n\t\t\t\tif (isSecretMessage == NO) {\n\t\t\t\t\t/* If the destination does not exist and this isn't a secret\n\t\t\t\t\t message, then create a private message if the destination \n\t\t\t\t\t is believed to be a user. */\n\t\t\t\t\tif (destination == nil && [self stringIsNickname:destinationName]) {\n\t\t\t\t\t\tdestination = [worldController() createPrivateMessage:destinationName onClient:self];\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Define the channel that will be selected */\n\t\t\t\t\tif ([TPCPreferences giveFocusOnMessageCommand]) {\n\t\t\t\t\t\tif (destinationToSelect == nil) {\n\t\t\t\t\t\t\tdestinationToSelect = destination;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* Add prefix back if the destination is a channel */\n\t\t\t\tBOOL destinationIsChannel =\n\t\t\t\t(destination.isChannel || (destination == nil && [self stringIsChannelName:destinationName]));\n\n\t\t\t\tif (destinationNamePrefix && destinationIsChannel) {\n\t\t\t\t\tdestinationName = [destinationNamePrefix stringByAppendingString:destinationName];\n\t\t\t\t}\n\n\t\t\t\t/* Break text up into substrings which can then be sent. */\n\t\t\t\tNSMutableAttributedString *lineMutable = [stringIn mutableCopy];\n\n\t\t\t\twhile (lineMutable.length > 0)\n\t\t\t\t{\n\t\t\t\t\tNSString *unencryptedMessage = [lineMutable stringFormattedForChannel:destinationName onClient:self withLineType:lineType];\n\n\t\t\t\t\tTLOEncryptionManagerEncodingDecodingCallbackBlock encryptionBlock = ^(NSString *originalString, BOOL wasEncrypted) {\n\t\t\t\t\t\tif (destination == nil) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage] && wasEncrypted == NO) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t[self print:originalString\n\t\t\t\t\t\t\t\t by:self.userNickname\n\t\t\t\t\t\t  inChannel:destination\n\t\t\t\t\t\t\t asType:lineType\n\t\t\t\t\t\t\tcommand:command\n\t\t\t\t\t\t receivedAt:[NSDate date]\n\t\t\t\t\t\tisEncrypted:wasEncrypted];\n\t\t\t\t\t};\n\n\t\t\t\t\tTLOEncryptionManagerInjectCallbackBlock injectionBlock = ^(NSString *encodedString) {\n\t\t\t\t\t\tNSString *sendMessage = encodedString;\n\n\t\t\t\t\t\tif (lineType == TVCLogLineTypeAction) {\n\t\t\t\t\t\t\tsendMessage = [NSString stringWithFormat:@\"%cACTION %@%c\", 0x01, sendMessage, 0x01];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t[self send:commandToSend, destinationName, sendMessage, nil];\n\t\t\t\t\t};\n\n\t\t\t\t\tif (destination == nil || isUnencryptedMessage) {\n\t\t\t\t\t\tencryptionBlock(unencryptedMessage, NO);\n\n\t\t\t\t\t\tinjectionBlock(unencryptedMessage);\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t[self encryptMessage:unencryptedMessage\n\t\t\t\t\t\t\t  directedAt:destination.name\n\t\t\t\t\t\tencodingCallback:encryptionBlock\n\t\t\t\t\t   injectionCallback:injectionBlock];\n\t\t\t\t}\n\t\t\t} // destination for()\n\n\t\t\t/* Focus destination */\n\t\t\tif (destinationToSelect) {\n\t\t\t\t[mainWindow() select:destinationToSelect];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t/* Find an addon responsible for this command. */\n\t\t\tNSString *addonPath = nil;\n\n\t\t\tBOOL pluginFound = NO;\n\t\t\tBOOL scriptFound = NO;\n\n\t\t\tBOOL commandIsReserved = NO;\n\n\t\t\t[sharedPluginManager() findHandlerForOutgoingCommand:lowercaseCommand path:&addonPath isReserved:&commandIsReserved isScript:&scriptFound isExtension:&pluginFound];\n\n\t\t\tif (commandIsReserved) {\n\t\t\t\t[sharedPluginManager() extrasInstallerAskUserIfTheyWantToInstallCommand:lowercaseCommand];\n\t\t\t}\n\n\t\t\t/* Perform script or plugin. */\n\t\t\tif (pluginFound && scriptFound)\n\t\t\t{\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[d3c-9b]\", uppercaseCommand)];\n\t\t\t\t\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (pluginFound && scriptFound == NO)\n\t\t\t{\n\t\t\t\t[self processBundlesUserMessage:stringIn.string command:lowercaseCommand];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (pluginFound == NO && scriptFound)\n\t\t\t{\n\t\t\t\tNSMutableDictionary<NSString *, NSString *> *context = [NSMutableDictionary dictionaryWithCapacity:3];\n\n\t\t\t\t[context maybeSetObject:stringIn.string forKey:@\"inputString\"];\n\n\t\t\t\t[context maybeSetObject:addonPath forKey:@\"path\"];\n\n\t\t\t\t[context maybeSetObject:targetChannel.name forKey:@\"targetChannel\"];\n\n\t\t\t\t[self executeTextualCmdScriptInContext:context];\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Send input to server */\n\t\t\t[self sendCommand:uppercaseCommand withData:stringIn.string];\n\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n- (void)sendCommand:(NSString *)command withData:(NSString *)data\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(data != nil);\n\n\tNSString *stringToSend = [NSString stringWithFormat:@\"%@ %@\", command, data];\n\n\t[self sendLine:stringToSend];\n}\n\n- (void)printInvalidSyntaxMessageForCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\t\n\tNSString *syntax = [IRCCommandIndex syntaxForLocalCommand:command];\n\t\n\tif (syntax == nil) {\n\t\treturn;\n\t}\n\t\n\t[self printDebugInformation:TXTLS(@\"IRC[atq-93]\", syntax)];\n}\n\n#pragma mark -\n#pragma mark Log File\n\n- (void)reopenLogFileIfNeeded\n{\n\tif ([TPCPreferences logToDiskIsEnabled]) {\n\t\tif ( self.logFile) {\n\t\t\t[self.logFile reopenIfNeeded];\n\t\t}\n\t} else {\n\t\t[self closeLogFile];\n\t}\n}\n\n- (void)closeLogFile\n{\n\tif (self.logFile == nil) {\n\t\treturn;\n\t}\n\n\t[self.logFile close];\n}\n\n- (void)writeToLogLineToLogFile:(TVCLogLine *)logLine\n{\n\tNSParameterAssert(logLine != nil);\n\n\tif ([TPCPreferences logToDiskIsEnabled] == NO) {\n\t\treturn;\n\t}\n\n\t// Perform addition before if statement to avoid infinite loop\n\tself.logFileSessionCount += 1;\n\n\tif (self.logFileSessionCount == 1) {\n\t\t[self logFileWriteSessionBegin];\n\t}\n\n\tif (self.logFile == nil) {\n\t\tself.logFile = [[TLOFileLogger alloc] initWithClient:self];\n\t}\n\n\t[self.logFile writeLogLine:logLine];\n}\n\n- (void)logFileRecordSessionChanged:(BOOL)toNewSession inChannel:(nullable IRCChannel *)channel\n{\n\tNSParameterAssert(channel.isUtility == NO);\n\n\tNSString *localization = nil;\n\n\tif (toNewSession) {\n\t\tlocalization = @\"IRC[qrg-ua]\";\n\t} else {\n\t\tlocalization = @\"IRC[d5d-uy]\";\n\t}\n\n\tTVCLogLineMutable *logLine = [TVCLogLineMutable new];\n\n\t/* ============================ */\n\n\tlogLine.messageBody = @\" \";\n\n\tif (channel) {\n\t\t[channel writeToLogLineToLogFile:logLine];\n\t} else {\n\t\t[self writeToLogLineToLogFile:logLine];\n\t}\n\n\t/* ============================ */\n\n\tlogLine.messageBody = TXTLS(localization);\n\n\tif (channel) {\n\t\t[channel writeToLogLineToLogFile:logLine];\n\t} else {\n\t\t[self writeToLogLineToLogFile:logLine];\n\t}\n\n\t/* ============================ */\n\n\tlogLine.messageBody = @\" \";\n\n\tif (channel) {\n\t\t[channel writeToLogLineToLogFile:logLine];\n\t} else {\n\t\t[self writeToLogLineToLogFile:logLine];\n\t}\n}\n\n- (void)endLoggingSessions\n{\n\tfor (IRCChannel *channel in self.channelList) {\n\t\tif (channel.isUtility) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[channel logFileWriteSessionEnd];\n\t}\n\n\t[self logFileWriteSessionEnd];\n}\n\n- (void)logFileWriteSessionBegin\n{\n\t[self logFileRecordSessionChanged:YES inChannel:nil];\n}\n\n- (void)logFileWriteSessionEnd\n{\n\t[self logFileRecordSessionChanged:NO inChannel:nil];\n\n\tself.logFileSessionCount = 0;\n}\n\n#pragma mark -\n#pragma mark Print\n\n- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel\n{\n\treturn [self formatNickname:nickname inChannel:channel withFormat:nil];\n}\n\n- (NSString *)formatNickname:(NSString *)nickname inChannel:(nullable IRCChannel *)channel withFormat:(nullable NSString *)format\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (format.length == 0) {\n\t\tformat = themeSettings().themeNicknameFormat;\n\t}\n\n\tif (format.length == 0) {\n\t\tformat = [TPCPreferences themeNicknameFormat];\n\t}\n\n\tif (format.length == 0) {\n\t\tformat = [TPCPreferences themeNicknameFormatDefault];\n\t}\n\n\tNSString *modeSymbol = @\"\";\n\n\tif (channel.isChannel) {\n\t\tIRCChannelUser *member = [channel findMember:nickname];\n\n\t\tif (member) {\n\t\t\tmodeSymbol = member.mark;\n\t\t}\n\t}\n\n\tNSString *formatMarker = @\"%\";\n\n\tNSString *chunk = nil;\n\n\tNSScanner *scanner = [NSScanner scannerWithString:format];\n\n\tscanner.charactersToBeSkipped = nil;\n\n\tNSMutableString *buffer = [NSMutableString new];\n\n\twhile (scanner.atEnd == NO) {\n\t\tif ([scanner scanUpToString:formatMarker intoString:&chunk]) {\n\t\t\t[buffer appendString:chunk];\n\t\t}\n\n\t\tif ([scanner scanString:formatMarker intoString:nil] == NO) {\n\t\t\tbreak;\n\t\t}\n\n\t\tNSInteger paddingWidth = 0;\n\n\t\t[scanner scanInteger:&paddingWidth];\n\n\t\t/* Read the output type marker */\n\t\tNSString *outputValue = nil;\n\n\t\tif ([scanner scanString:@\"@\" intoString:nil]) {\n\t\t\toutputValue = modeSymbol;\n\t\t} else if ([scanner scanString:@\"n\" intoString:nil]) {\n\t\t\toutputValue = nickname;\n\t\t} else if ([scanner scanString:formatMarker intoString:nil]) {\n\t\t\toutputValue = formatMarker;\n\t\t}\n\n\t\tif (outputValue) {\n\t\t\tif (paddingWidth < 0 && ABS(paddingWidth) > outputValue.length) {\n\t\t\t\tNSString *paddedString = [@\"\" stringByPaddingToLength:(ABS(paddingWidth) - outputValue.length) withString:@\" \" startingAtIndex:0];\n\n\t\t\t\t[buffer appendString:paddedString];\n\t\t\t}\n\n\t\t\t[buffer appendString:outputValue];\n\n\t\t\tif (paddingWidth > 0 && paddingWidth > outputValue.length) {\n\t\t\t\tNSString *paddedString = [@\"\" stringByPaddingToLength:(paddingWidth - outputValue.length) withString:@\" \" startingAtIndex:0];\n\n\t\t\t\t[buffer appendString:paddedString];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [buffer copy];\n}\n\n- (void)printAndLog:(TVCLogLine *)logLine completionBlock:(TVCLogControllerPrintOperationCompletionBlock)completionBlock\n{\n\tNSParameterAssert(logLine != nil);\n\n\t[self.viewController print:logLine completionBlock:completionBlock];\n\n\t[self writeToLogLineToLogFile:logLine];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:[NSDate date] isEncrypted:NO escapeMessage:YES referenceMessage:nil completionBlock:nil];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command escapeMessage:(BOOL)escapeMessage\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:[NSDate date] isEncrypted:NO escapeMessage:escapeMessage referenceMessage:nil completionBlock:nil];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:receivedAt isEncrypted:NO escapeMessage:YES referenceMessage:nil completionBlock:nil];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:receivedAt isEncrypted:isEncrypted escapeMessage:YES referenceMessage:nil completionBlock:nil];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:receivedAt isEncrypted:isEncrypted escapeMessage:YES referenceMessage:referenceMessage completionBlock:nil];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted referenceMessage:(nullable IRCMessage *)referenceMessage completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock\n{\n\t[self print:messageBody by:nickname inChannel:channel asType:lineType command:command receivedAt:receivedAt isEncrypted:isEncrypted escapeMessage:YES referenceMessage:referenceMessage completionBlock:completionBlock];\n}\n\n- (void)print:(NSString *)messageBody by:(nullable NSString *)nickname inChannel:(nullable IRCChannel *)channel asType:(TVCLogLineType)lineType command:(nullable NSString *)command receivedAt:(NSDate *)receivedAt isEncrypted:(BOOL)isEncrypted escapeMessage:(BOOL)escapeMessage referenceMessage:(nullable IRCMessage *)referenceMessage completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock\n{\n\tNSParameterAssert(messageBody != nil);\n\tNSParameterAssert(command != nil || referenceMessage != nil);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\t/* If an operation does not specify a command value, \n\t then try to obtain it from the reference message. */\n\tif (command == nil) {\n\t\tcommand = referenceMessage.command;\n\t}\n\n\t/* Prevent stupid plugin authors */\n\tif ([channel isKindOfClass:[IRCChannel class]] == NO) {\n\t\tchannel = nil;\n\t}\n\n\t/* Do not print this message? */\n\tif (channel) {\n\t\tif ([self outputRuleMatchedInMessage:messageBody inChannel:channel]) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Define where the message originated */\n\tNSString *localNickname = self.userNickname;\n\n\tTVCLogLineMemberType memberType = TVCLogLineMemberTypeNormal;\n\n\tif ([nickname isEqualToString:localNickname]) {\n\t\tmemberType = TVCLogLineMemberTypeLocalUser;\n\t}\n\n\t/* Define list of highlight keywords */\n\tBOOL matchHighlights =\n\t\t(channel &&\n\t\t channel.config.ignoreHighlights == NO &&\n\t\t (lineType == TVCLogLineTypePrivateMessage || lineType == TVCLogLineTypeAction) &&\n\t\t memberType == TVCLogLineMemberTypeNormal);\n\n\tNSMutableArray<NSString *> *excludeKeywords = nil;\n\tNSMutableArray<NSString *> *matchKeywords = nil;\n\t\n\tif (matchHighlights) {\n\t\t/* Global highlight keywords */\n\t\texcludeKeywords = [[TPCPreferences highlightExcludeKeywords] mutableCopy];\n\t\tmatchKeywords = [[TPCPreferences highlightMatchKeywords] mutableCopy];\n\n\t\t/* Self nickname keyword */\n\t\tif ([TPCPreferences highlightMatchingMethod] != TXNicknameHighlightMatchTypeRegularExpression &&\n\t\t\t[TPCPreferences highlightCurrentNickname])\n\t\t{\n\t\t\t[matchKeywords addObjectWithoutDuplication:localNickname];\n\t\t}\n\n\t\t/* Client/channel specific keywords */\n\t\tNSArray *clientHighlightList = self.config.highlightList;\n\n\t\tNSString *channelId = channel.uniqueIdentifier;\n\n\t\tfor (IRCHighlightMatchCondition *e in clientHighlightList) {\n\t\t\tNSString *matchChannelId = e.matchChannelId;\n\t\t\t\n\t\t\tif (matchChannelId.length > 0) {\n\t\t\t\tif ([matchChannelId isEqualToString:channelId] == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (e.matchIsExcluded) {\n\t\t\t\t[excludeKeywords addObjectWithoutDuplication:e.matchKeyword];\n\t\t\t} else {\n\t\t\t\t[matchKeywords addObjectWithoutDuplication:e.matchKeyword];\n\t\t\t}\n\t\t}\n\t} // matchKeywords\n\n\tif (lineType == TVCLogLineTypeActionNoHighlight) {\n\t\tlineType = TVCLogLineTypeAction;\n\t} else if (lineType == TVCLogLineTypePrivateMessageNoHighlight) {\n\t\tlineType = TVCLogLineTypePrivateMessage;\n\t}\n\n\t/* Renderer attributes */\n\tNSDictionary<NSString *, id> *rendererAttributes = nil;\n\n\tif (escapeMessage == NO) {\n\t\trendererAttributes = @{\n\t\t\tTVCLogRendererConfigurationDoNotEscapeBodyAttribute : @(YES)\n\t\t};\n\t}\n\n\t/* Create new log entry */\n\tTVCLogLineMutable *logLine = [TVCLogLineMutable new];\n\n\tlogLine.command\t= command.lowercaseString;\n\n\tlogLine.lineType = lineType;\n\tlogLine.memberType = memberType;\n\n\tlogLine.isEncrypted = isEncrypted;\n\n\tlogLine.excludeKeywords = excludeKeywords;\n\tlogLine.highlightKeywords = matchKeywords;\n\n\tlogLine.rendererAttributes = rendererAttributes;\n\n\tlogLine.nickname = nickname;\n\n\tlogLine.messageBody = messageBody;\n\n\t/* Has the date changed */\n\tTVCLogLine *lastLine = ((channel) ? channel.lastLine : self.lastLine);\n\n\tif (lastLine == nil) {\n\t\tlogLine.isFirstForDay = YES;\n\t} else {\n\t\tlogLine.isFirstForDay = ([receivedAt isInSameDayAsDate:lastLine.receivedAt] == NO);\n\t}\n\n\tlogLine.receivedAt = receivedAt;\n\n\t/* Print to server console if there is no channel */\n\tif (channel == nil) {\n\t\t[self printAndLog:logLine completionBlock:completionBlock];\n\n\t\treturn;\n\t}\n\n\t/* Add scrollback marker to channel if conditions are met */\n\tif ([TPCPreferences autoAddScrollbackMark]) {\n\t\tif ([mainWindow() isItemVisible:channel] == NO || mainWindow().mainWindow == NO) {\n\t\t\tif (channel.isUnread == NO &&\n\t\t\t\t(lineType == TVCLogLineTypePrivateMessage ||\n\t\t\t\t lineType == TVCLogLineTypeAction ||\n\t\t\t\t lineType == TVCLogLineTypeNotice))\n\t\t\t{\n\t\t\t\t[channel.viewController mark];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Print to channel */\n\t[channel print:logLine completionBlock:completionBlock];\n}\n\n- (void)printReply:(IRCMessage *)message\n{\n\t[self printReply:message inChannel:nil];\n}\n\n- (void)printReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel\n{\n\t[self printReply:message inChannel:channel withSequence:1];\n}\n\n- (void)printReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel withSequence:(NSUInteger)sequence\n{\n\tNSParameterAssert(message != nil);\n\n\t[self print:[message sequence:sequence] by:nil inChannel:channel asType:TVCLogLineTypeDebug command:message.command receivedAt:message.receivedAt];\n}\n\n- (void)printUnknownReply:(IRCMessage *)message\n{\n\t[self printUnknownReply:message inChannel:nil];\n}\n\n- (void)printUnknownReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel\n{\n\t[self printUnknownReply:message inChannel:channel withSequence:1];\n}\n\n- (void)printUnknownReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel withSequence:(NSUInteger)sequence\n{\n\tNSParameterAssert(message != nil);\n\n\t[self print:[message sequence:sequence] by:nil inChannel:channel asType:TVCLogLineTypeDebug command:message.command receivedAt:message.receivedAt];\n}\n\n- (void)printErrorReply:(IRCMessage *)message\n{\n\t[self printErrorReply:message inChannel:nil];\n}\n\n- (void)printErrorReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel\n{\n\t[self printErrorReply:message inChannel:channel withSequence:NSNotFound];\n}\n\n- (void)printErrorReply:(IRCMessage *)message inChannel:(nullable IRCChannel *)channel withSequence:(NSUInteger)sequence\n{\n\tNSParameterAssert(message != nil);\n\n\tNSString *sequenceMessage = nil;\n\n\tif (sequence == NSNotFound) {\n\t\tsequenceMessage = message.sequence;\n\t} else {\n\t\tsequenceMessage = [message sequence:sequence];\n\t}\n\n\tNSString *errorMessage = TXTLS(@\"IRC[3yo-gw]\", message.commandNumeric, sequenceMessage);\n\n\t[self print:errorMessage by:nil inChannel:channel asType:TVCLogLineTypeDebug command:message.command];\n}\n\n- (void)printError:(NSString *)errorMessage asCommand:(NSString *)command\n{\n\t[self print:errorMessage by:nil inChannel:nil asType:TVCLogLineTypeDebug command:command];\n}\n\n- (void)printDebugInformationToConsole:(NSString *)message\n{\n\t[self printDebugInformationToConsole:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:YES];\n}\n\n- (void)printDebugInformationToConsole:(NSString *)message asCommand:(NSString *)command\n{\n\t[self printDebugInformationToConsole:message asCommand:command escapeMessage:YES];\n}\n\n- (void)printDebugInformationToConsole:(NSString *)message escapeMessage:(BOOL)escapeMessage\n{\n\t[self printDebugInformationToConsole:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformationToConsole:(NSString *)message asCommand:(NSString *)command escapeMessage:(BOOL)escapeMessage\n{\n\t[self print:message by:nil inChannel:nil asType:TVCLogLineTypeDebug command:command escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformation:(NSString *)message\n{\n\t[self printDebugInformation:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:YES];\n}\n\n- (void)printDebugInformationMultiline:(NSString *)message\n{\n\t[message enumerateSplitOnNewLinesWithBlock:^(NSString *sequence, BOOL *stop) {\n\t\t[self printDebugInformation:sequence];\n\t}];\n}\n\n- (void)printDebugInformation:(NSString *)message asCommand:(NSString *)command\n{\n\t[self printDebugInformation:message asCommand:command escapeMessage:YES];\n}\n\n- (void)printDebugInformation:(NSString *)message escapeMessage:(BOOL)escapeMessage\n{\n\t[self printDebugInformation:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformation:(NSString *)message asCommand:(NSString *)command escapeMessage:(BOOL)escapeMessage\n{\n\tIRCChannel *channel = [mainWindow() selectedChannelOn:self];\n\n\t[self printDebugInformation:message inChannel:channel asCommand:TVCLogLineDefaultCommandValue escapeMessage:YES];\n}\n\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel\n{\n\t[self printDebugInformation:message inChannel:channel asCommand:TVCLogLineDefaultCommandValue escapeMessage:YES];\n}\n\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel asCommand:(NSString *)command\n{\n\t[self print:message by:nil inChannel:channel asType:TVCLogLineTypeDebug command:command escapeMessage:YES];\n}\n\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel escapeMessage:(BOOL)escapeMessage\n{\n\t[self printDebugInformation:message inChannel:channel asCommand:TVCLogLineDefaultCommandValue escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformation:(NSString *)message inChannel:(IRCChannel *)channel asCommand:(NSString *)command escapeMessage:(BOOL)escapeMessage\n{\n\t[self print:message by:nil inChannel:channel asType:TVCLogLineTypeDebug command:command escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformationInAllViews:(NSString *)message\n{\n\t[self printDebugInformationInAllViews:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:YES];\n}\n\n- (void)printDebugInformationInAllViews:(NSString *)message asCommand:(NSString *)command\n{\n\t[self printDebugInformationInAllViews:message asCommand:command escapeMessage:YES];\n}\n\n- (void)printDebugInformationInAllViews:(NSString *)message escapeMessage:(BOOL)escapeMessage\n{\n\t[self printDebugInformationInAllViews:message asCommand:TVCLogLineDefaultCommandValue escapeMessage:escapeMessage];\n}\n\n- (void)printDebugInformationInAllViews:(NSString *)message asCommand:(NSString *)command escapeMessage:(BOOL)escapeMessage\n{\n\tfor (IRCChannel *channel in self.channelList) {\n\t\t[self printDebugInformation:message inChannel:channel asCommand:command escapeMessage:escapeMessage];\n\t}\n\n\t[self printDebugInformationToConsole:message asCommand:command escapeMessage:escapeMessage];\n}\n\n#pragma mark -\n#pragma mark IRCConnection Delegate\n\n- (void)resetAllPropertyValues\n{\n\t// Some properties are purposely excluded from this method\n\t// because their state must be kept or they are reset elsewhere\n\n\t[self.batchMessages dequeueEntries];\n\n\tself.connectDelay = 0;\n\n\tself.invokingISONCommandForFirstTime = NO;\n\n\tself.isAutojoining = NO;\n\tself.isAutojoined = NO;\n\n\tself.autojoinDelayedWarningCount = 0;\n\n\tself.isConnected = NO;\n\tself.isConnecting = NO;\n\tself.isLoggedIn = NO;\n\tself.isQuitting = NO;\n\tself.isDisconnecting = NO;\n\n\tself.inWhoisResponse = NO;\n\tself.inWhowasResponse = NO;\n\n\tself.isWaitingForNickServ = NO;\n\tself.serverHasNickServ = NO;\n\tself.userIsIdentifiedWithNickServ = NO;\n\n\tself.userIsAway = NO;\n\tself.userIsIRCop = NO;\n\n\tself.isConnectedToZNC = NO;\n\tself.zncBouncerIsSendingCertificateInfo = NO;\n\tself.zncBouncerCertificateChainDataMutable = nil;\n\tself.zncBouncerIsPlayingBackHistory = NO;\n\n\tself.reconnectEnabled = NO;\n\n\tself.timeoutWarningShownToUser = NO;\n\n\tself.lastWhoRequestChannelListIndex = 0;\n\n\tself.server = nil;\n\n\tself.userHostmask = nil;\n\tself.userNickname = nil;\n\n\tself.tryingNicknameNumber = 0;\n\tself.tryingNicknameSentNickname = nil;\n\n\tself.preAwayUserNickname = nil;\n\n\tself.lastMessageReceived = 0;\n\n\tself.capabilities = 0;\n\tself.capabilityNegotiationIsPaused = NO;\n\n\t@synchronized (self.capabilitiesPending) {\n\t\t[self.capabilitiesPending removeAllObjects];\n\t}\n\n\t@synchronized (self.userListPrivate) {\n\t\t[self.userListPrivate removeAllObjects];\n\t}\n}\n\n- (void)changeStateOff\n{\n\t[self changeStateOffWithError:nil];\n}\n\n- (void)changeStateOffWithError:(nullable NSError *)disconnectError\n{\n\tif (self.isConnecting == NO && self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tBOOL isTerminating = self.isTerminating;\n\n\tself.socket = nil;\n\n\t[self removeTimedCommands];\n\n\t[self removeRequestedCommands];\n\n\t[self stopAutojoinTimer];\n\t[self stopAutojoinNextJoinTimer];\n\t[self stopAutojoinDelayedWarningTimer];\n\t[self stopISONTimer];\n\t[self stopPongTimer];\n\t[self stopRetryTimer];\n\n\t[self cancelPerformRequests];\n\n\tif (isTerminating == NO && self.reconnectEnabled) {\n\t\t[self startReconnectTimer];\n\t}\n\n\t[self.supportInfo reset];\n\n\t[self clearAddressBookCache];\n\n\t[self clearTrackedUsers];\n\n\tif (isTerminating == NO) {\n\t\t/* -prepareForApplicationTermination in TVCLogController will cancel\n\t\t all operations for this client for us during termination. */\n\t\t[[TXSharedApplication sharedPrintingQueue] cancelOperationsForClient:self];\n\n\t\tIRCClientDisconnectMode disconnectType = self.disconnectType;\n\n\t\tif (disconnectError) {\n\t\t\t// TODO: Don't hardcode the error domain and code\n\t\t\tif ( disconnectError.code == IRCConnectionErrorCodeBadCertificate &&\n\t\t\t\t[disconnectError.domain isEqualToString:IRCConnectionErrorDomain])\n\t\t\t{\n\t\t\t\tdisconnectType = IRCClientDisconnectModeBadCertificate;\n\t\t\t}\n\n\t\t\t[self printError:disconnectError.localizedDescription asCommand:TVCLogLineDefaultCommandValue];\n\t\t}\n\n\t\tNSString *disconnectMessage = nil;\n\n\t\tswitch (disconnectType) {\n\t\t\tcase IRCClientDisconnectModeNormal:\n\t\t\t{\n\t\t\t\tdisconnectMessage = TXTLS(@\"IRC[9b4-10]\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCClientDisconnectModeComputerSleep:\n\t\t\t{\n\t\t\t\tdisconnectMessage = TXTLS(@\"IRC[drg-b7]\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCClientDisconnectModeBadCertificate:\n\t\t\t{\n\t\t\t\tdisconnectMessage = TXTLS(@\"IRC[zro-bg]\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCClientDisconnectModeServerRedirect:\n\t\t\t{\n\t\t\t\tdisconnectMessage = TXTLS(@\"IRC[wcl-po]\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCClientDisconnectModeReachabilityChange:\n\t\t\t{\n\t\t\t\tdisconnectMessage = TXTLS(@\"IRC[isx-fi]\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // switch()\n\n\t\tfor (IRCChannel *channel in self.channelList) {\n\t\t\tif (channel.isActive == NO) {\n\t\t\t\tchannel.errorOnLastJoinAttempt = NO;\n\t\t\t} else {\n\t\t\t\t[channel deactivate];\n\n\t\t\t\tif (channel.isUtility) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[self printDebugInformation:disconnectMessage inChannel:channel];\n\t\t\t}\n\t\t}\n\n\t\t[self printDebugInformationToConsole:disconnectMessage];\n\n\t\t[self.viewController mark];\n\n\t\tif (self.isConnected) {\n\t\t\t[self notifyEvent:TXNotificationTypeDisconnect lineType:TVCLogLineTypeDebug];\n\t\t}\n\n\t\t[self postEventToViewController:@\"serverDisconnected\"];\n\t}\n\n\t[self endLoggingSessions];\n\n\t[self resetAllPropertyValues];\n\n\tif (isTerminating == NO) {\n\t\t[mainWindow() reloadTreeGroup:self];\n\n\t\t[mainWindow() updateTitleFor:self];\n\t}\n}\n\n- (void)ircConnection:(IRCConnection *)sender willConnectToProxy:(NSString *)proxyHost port:(uint16_t)proxyPort\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tIRCConnectionProxyType proxyType = self.socket.config.proxyType;\n\n\tif (proxyType == IRCConnectionProxyTypeSocks4) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[p7h-un]\", proxyHost, proxyPort)];\n\t} else if (proxyType == IRCConnectionProxyTypeSocks5) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[ni5-cy]\", proxyHost, proxyPort)];\n\t} else if (proxyType == IRCConnectionProxyTypeHTTP) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[oby-av]\", proxyHost, proxyPort)];\n\t}\n}\n\n- (void)ircConnectionDidSecureConnection:(IRCConnection *)sender withProtocolType:(tls_protocol_version_t)protocolType cipherSuite:(tls_ciphersuite_t)cipherSuite\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tNSString *protocolDescription = [RCMSecureTransport descriptionForProtocolType:protocolType];\n\n\tNSString *cipherDescription = [RCMSecureTransport descriptionForCipherSuite:cipherSuite];\n\n\tif (protocolDescription == nil || cipherDescription == nil) {\n\t\treturn;\n\t}\n\n\tNSString *description = nil;\n\n\tif ([RCMSecureTransport isCipherSuiteDeprecated:cipherSuite] == NO) {\n\t\tdescription = TXTLS(@\"IRC[uyz-4r]\", protocolDescription, cipherDescription);\n\t} else {\n\t\tdescription = TXTLS(@\"IRC[xwj-xy]\", protocolDescription, cipherDescription);\n\t}\n\n\t[self printDebugInformationToConsole:TXTLS(@\"IRC[ex4-f8]\", description)];\n}\n\n- (void)ircConnectionDidConnect:(IRCConnection *)sender\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\t[self startRetryTimer];\n\n\t/* If the address we are connecting to is not an IP address,\n\t then we report back the actual IP address it was resolved to. */\n\tNSString *connectedAddress = self.socket.connectedAddress;\n\n\tif (connectedAddress == nil || self.socket.config.serverAddress.IPAddress) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[4vt-ow]\")];\n\t} else {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[l21-p7]\", connectedAddress)];\n\t}\n\n\tself.isConnecting = NO;\n\tself.isConnected = YES;\n\n\tself.userNickname = self.config.nickname;\n\n\tself.tryingNicknameSentNickname = self.config.nickname;\n\n\t[mainWindow() updateTitleFor:self];\n\n\t[RZNotificationCenter() postNotificationName:IRCClientDidConnectNotification object:self];\n\n\tNSString *username = self.config.username;\n\tNSString *realName = self.config.realName;\n\n\tNSString *modeSymbols = @\"0\";\n\n\tNSString *serverPassword = self.server.serverPassword;\n\n\tif (self.config.setInvisibleModeOnConnect) {\n\t\tmodeSymbols = @\"8\";\n\t}\n\n\tif (username.length == 0) {\n\t\tusername = self.config.nickname;\n\t}\n\n\tif (realName.length == 0) {\n\t\trealName = self.config.nickname;\n\t}\n\n\t[self sendCapability:@\"LS\" data:@\"302\"];\n\n\tif (serverPassword) {\n\t\t[self sendPassword:serverPassword];\n\t}\n\n\t[self changeNickname:self.tryingNicknameSentNickname];\n\n\t[self send:@\"USER\", username, modeSymbols, @\"*\", realName, nil];\n}\n\n- (void)ircConnection:(IRCConnection *)sender didDisconnectWithError:(nullable NSError *)disconnectError\n{\n\tNSParameterAssert(sender == self.socket);\n\n//\tif (self.isTerminating) {\n//\t\treturn;\n//\t}\n\n\t[self changeStateOffWithError:disconnectError];\n\n\tif (self.disconnectCallback) {\n\t\tself.disconnectCallback();\n\t\tself.disconnectCallback = nil;\n\t}\n\n\t[RZNotificationCenter() postNotificationName:IRCClientDidDisconnectNotification object:self];\n}\n\n- (void)ircConnectionDidCloseReadStream:(IRCConnection *)sender\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tif (self.isDisconnecting) {\n\t\treturn;\n\t}\n\n\tif (self.isQuitting) {\n\t\t[self disconnect];\n\n\t\treturn;\n\t}\n\n\t[self printDebugInformationToConsole:TXTLS(@\"IRC[5h5-sl]\")];\n}\n\n/* This delegate call is not invoked on the main thread\n which means if it is modified to interact with UI,\n then it must invoke on the main thread eventually. */\n- (void)ircConnection:(IRCConnection *)sender didReceiveData:(NSString *)data\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tif (self.isConnected == NO || self.isTerminating) {\n\t\treturn;\n\t}\n\n\tif (data.length == 0) {\n\t\treturn;\n\t}\n\n\tself.lastMessageReceived = [NSDate timeIntervalSince1970];\n\n\tworldController().bandwidthIn += data.length;\n\n\tworldController().messagesReceived += 1;\n\n\t[self rawDataLogIncomingTraffic:data];\n\n\tif ([TPCPreferences removeAllFormatting]) {\n\t\tdata = data.stripIRCEffects;\n\t}\n\n\tIRCMessage *message = [[IRCMessage alloc] initWithLine:data onClient:self];\n\n\tif (message == nil) {\n\t\treturn;\n\t}\n\n\tmessage = [THOPluginDispatcher interceptServerInput:message for:self];\n\n\tif (message == nil) {\n\t\treturn;\n\t}\n\n\tif ([self filterBatchCommandIncomingData:message]) {\n\t\treturn;\n\t}\n\n\t[self processIncomingMessage:message];\n}\n\n- (void)processIncomingMessageAttributes:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (message.isHistoric == NO) {\n\t\treturn;\n\t}\n\n\tNSTimeInterval receivedTime = message.receivedAt.timeIntervalSince1970;\n\n\tif (receivedTime <= self.lastMessageServerTime) {\n\t\treturn;\n\t}\n\n\tself.lastMessageServerTime = receivedTime;\n\n\t/* If the playback module is in use, then all messages are\n\t set as historic, so we set any lines above our current \n\t reference date as not historic to avoid collisions. */\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityPlayback]) {\n\t\t[message markAsNotHistoric];\n\t}\n}\n\n- (void)processIncomingMessage:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self _processIncomingMessage:message];\n\t});\n}\n\n- (void)_processIncomingMessage:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\t[self processIncomingMessageAttributes:message];\n\n\tif (message.commandNumeric > 0) {\n\t\t[self receiveNumericReply:message];\n\t} else {\n\t\tNSUInteger commandNumeric = [IRCCommandIndex indexOfRemoteCommand:message.command];\n\n\t\tswitch (commandNumeric) {\n\t\t\tcase IRCRemoteCommandNotice: // Command: NOTICE\n\t\t\tcase IRCRemoteCommandPrivmsg: // Command: PRIVMSG\n\t\t\t{\n\t\t\t\t[self receivePrivmsgAndNotice:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandError: // Command: ERROR\n\t\t\t{\n\t\t\t\t[self receiveError:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandInvite: // Command: INVITE\n\t\t\t{\n\t\t\t\t[self receiveInvite:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandJoin: // Command: JOIN\n\t\t\t{\n\t\t\t\t[self receiveJoin:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandKick: // Command: KICK\n\t\t\t{\n\t\t\t\t[self receiveKick:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandKill: // Command: KILL\n\t\t\t{\n\t\t\t\t[self receiveKill:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandMode: // Command: MODE\n\t\t\t{\n\t\t\t\t[self receiveMode:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandNick: // Command: NICK\n\t\t\t{\n\t\t\t\t[self receiveNick:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandPart: // Command: PART\n\t\t\t{\n\t\t\t\t[self receivePart:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandPing: // Command: PING\n\t\t\t{\n\t\t\t\t[self receivePing:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandQuit: // Command: QUIT\n\t\t\t{\n\t\t\t\t[self receiveQuit:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandTopic: // Command: TOPIC\n\t\t\t{\n\t\t\t\t[self receiveTopic:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandWallops: // Command: WALLOPS\n\t\t\t{\n\t\t\t\t[self receiveWallops:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandAuthenticate: // Command: AUTHENTICATE\n\t\t\tcase IRCRemoteCommandCap: // Command: CAP\n\t\t\t{\n\t\t\t\t[self updateConnectedToZNCPropertyWithMessage:message];\n\n\t\t\t\t[self receiveCapabilityOrAuthenticationRequest:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandAway: // Command: AWAY (away-notify CAP)\n\t\t\t{\n\t\t\t\t[self receiveAwayNotifyCapability:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandBatch: // BATCH\n\t\t\t{\n\t\t\t\t[self receiveBatch:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandCertinfo: // CERTINFO\n\t\t\t{\n\t\t\t\t[self receiveCertInfo:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCRemoteCommandChghost:\n\t\t\t{\n\t\t\t\t[self receiveChangeHost:message];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // switch\n\t}\n\n\t[self processBundlesServerMessage:message];\n}\n\n- (void)ircConnection:(IRCConnection *)sender willSendData:(NSString *)data\n{\n\tNSParameterAssert(sender == self.socket);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\t[self rawDataLogOutgoingTraffic:data];\n}\n\n#pragma mark -\n#pragma mark Raw Data Logging\n\n- (void)createRawDataLogQuery\n{\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tif (self.rawDataLogQuery != nil) {\n\t\treturn;\n\t}\n\n\tIRCChannel *query = [self findChannelOrCreate:@\"Server Traffic\" isUtility:YES];\n\n\tself.rawDataLogQuery = query;\n\n\t[mainWindow() select:query];\n\n\t[self rawDataLog:TXTLS(@\"IRC[ik6-dl]\")];\n}\n\n- (void)destroyRawDataLogQuery\n{\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tif (self.rawDataLogQuery == nil) {\n\t\treturn;\n\t}\n\n\t[worldController() destroyChannel:self.rawDataLogQuery];\n}\n\n- (void)rawDataLog:(NSString *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self printDebugInformation:data inChannel:self.rawDataLogQuery];\n\t});\n}\n\n- (void)rawDataLogOutgoingTraffic:(NSString *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tif (self.rawDataLogQuery == nil) {\n\t\treturn;\n\t}\n\n\tNSString *dataToLog = [NSString stringWithFormat:@\"<< %@\", data];\n\n\t[self rawDataLog:dataToLog];\n}\n\n- (void)rawDataLogIncomingTraffic:(NSString *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tif (self.rawDataLogQuery == nil) {\n\t\treturn;\n\t}\n\n\tNSString *dataToLog = [NSString stringWithFormat:@\">> %@\", data];\n\n\t[self rawDataLog:dataToLog];\n}\n\n#pragma mark -\n#pragma mark NickServ Information\n\n- (NSArray<NSString *> *)nickServSupportedNeedIdentificationTokens\n{\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"IRCClient List of NickServ Needs Identification Tokens\"];\n}\n\n- (NSArray<NSString *> *)nickServSupportedSuccessfulIdentificationTokens\n{\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"IRCClient List of NickServ Successfully Identified Tokens\"];\n}\n\n#pragma mark -\n#pragma mark Protocol Handlers\n\n- (void)receiveWallops:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\t/* WALLOPS are rewritten so that they can be parsed as regular notices */\n\tNSMutableArray *paramsMutable = [m.params mutableCopy];\n\n\t[paramsMutable insertObject:self.userNickname atIndex:0];\n\n\tNSString *text = [NSString stringWithFormat:TVCLogLineSpecialNoticeMessageFormat, m.command, paramsMutable[1]];\n\n\tparamsMutable[1] = text;\n\n\t/* ======================================== */\n\n\tIRCMessageMutable *messageMutable = [m mutableCopy];\n\n\tmessageMutable.command = @\"NOTICE\";\n\n\tmessageMutable.params = paramsMutable;\n\n\t/* ======================================== */\n\n\t[self receivePrivmsgAndNotice:[messageMutable copy]];\n}\n\n- (void)receivePrivmsgAndNotice:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 1);\n\n\tNSString *text = [m paramAt:1];\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityIdentifyCTCP] && ([text hasPrefix:@\"+\\x01\"] || [text hasPrefix:@\"-\\x01\"])) {\n\t\ttext = [text substringFromIndex:1];\n\t} else if ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityIdentifyMsg] && ([text hasPrefix:@\"+\"] || [text hasPrefix:@\"-\"])) {\n\t\ttext = [text substringFromIndex:1];\n\t}\n\n\tTVCLogLineType lineType = TVCLogLineTypePrivateMessage;\n\n\tBOOL isPlainText = [m.command isEqualToString:@\"PRIVMSG\"];\n\n\tif ([text hasPrefix:@\"\\x01\"]) {\n\t\ttext = [text substringFromIndex:1];\n\n\t\tNSInteger closingIndex = [text stringPosition:@\"\\x01\"];\n\n\t\tif (closingIndex >= 0) {\n\t\t\ttext = [text substringToIndex:closingIndex];\n\t\t}\n\n\t\tif (isPlainText) {\n\t\t\tif ([text hasPrefixIgnoringCase:@\"ACTION \"]) {\n\t\t\t\ttext = [text substringFromIndex:7];\n\n\t\t\t\tlineType = TVCLogLineTypeAction;\n\t\t\t} else {\n\t\t\t\tlineType = TVCLogLineTypeCTCPQuery;\n\t\t\t}\n\t\t} else {\n\t\t\tlineType = TVCLogLineTypeCTCPReply; // notice -> query\n\t\t}\n\t} else if (isPlainText == NO) {\n\t\tlineType = TVCLogLineTypeNotice;\n\t}\n\n\tif (lineType == TVCLogLineTypeAction ||\n\t\tlineType == TVCLogLineTypePrivateMessage ||\n\t\tlineType == TVCLogLineTypeNotice)\n\t{\n\t\t[self receiveText:m lineType:lineType text:text];\n\t} else if (lineType == TVCLogLineTypeCTCPQuery) {\n\t\t[self receiveCTCPQuery:m text:text];\n\t} else if (lineType == TVCLogLineTypeCTCPReply) {\n\t\t[self receiveCTCPReply:m text:text];\n\t}\n}\n\n- (void)receiveText:(IRCMessage *)m lineType:(TVCLogLineType)lineType text:(NSString *)text\n{\n\tNSParameterAssert(m != nil);\n\n\tNSParameterAssert(lineType == TVCLogLineTypeAction ||\n\t\t\t\t\t  lineType == TVCLogLineTypeActionNoHighlight ||\n\t\t\t\t\t  lineType == TVCLogLineTypePrivateMessage ||\n\t\t\t\t\t  lineType == TVCLogLineTypePrivateMessageNoHighlight ||\n\t\t\t\t\t  lineType == TVCLogLineTypeNotice);\n\n\tNSParameterAssert(text != nil);\n\n\tNSAssertReturn([m paramsCount] > 1);\n\n\t/* Allow empty actions but no other type */\n\tif (text.length == 0) {\n\t\tif (lineType == TVCLogLineTypeAction ||\n\t\t\tlineType == TVCLogLineTypeActionNoHighlight)\n\t\t{\n\t\t\ttext = @\" \";\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Process target */\n\tNSString *target = [m paramAt:0];\n\n\tif (target.length == 0) {\n\t\treturn;\n\t}\n\n\t/* It is possible for a channel to have a user mode character in front\n\t of it when the message is being addressed to a specific group of users.\n\t For example, \"+#channel\" as the channel name means that the message is\n\t addressed to only the voiced users of #channel. We don't care about this\n\t mode but we still have to remove it while also taking into account\n\t channels who use a character other than the pound symbol as their prefix. */\n\tNSString *targetPrefix = [self.supportInfo extractStatusMessagePrefixFromChannelNamed:target];\n\n\tif (targetPrefix.length == 1) {\n\t\ttarget = [target substringFromIndex:1];\n\t}\n\n\t/* Perform ignore check */\n\tIRCAddressBookEntry *ignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\tif (ignoreInfo.ignorePublicMessageHighlights) {\n\t\tif (lineType == TVCLogLineTypeAction) {\n\t\t\tlineType = TVCLogLineTypeActionNoHighlight;\n\t\t} else if (lineType == TVCLogLineTypePrivateMessage) {\n\t\t\tlineType = TVCLogLineTypePrivateMessageNoHighlight;\n\t\t}\n\t}\n\n\tif (lineType == TVCLogLineTypeNotice) {\n\t\tif (ignoreInfo.ignoreNoticeMessages) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Even though OTR doesn't allow channel decryption, we still wrap everything\n\t in a decryption block because Blowfish plugin may swizzle the logic.\n\t That plugin does support channel decryption. */\n\tBOOL performDecryption = YES;\n\n\tTLOEncryptionManagerEncodingDecodingCallbackBlock decryptionBlock = nil;\n\n\t/* Public message (directed at channel) */\n\tif ([self stringIsChannelName:target]) {\n\t\tif (ignoreInfo.ignorePublicMessages) {\n\t\t\treturn;\n\t\t}\n\n\t\tdecryptionBlock = ^(NSString *originalString, BOOL wasEncrypted) {\n\t\t\t[self _receiveText_Public:m lineType:lineType target:target text:originalString wasEncrypted:wasEncrypted];\n\t\t};\n\t}\n\n\t/* Private message (from user) */\n\telse if (m.senderIsServer == NO) {\n\t\tif (ignoreInfo.ignorePrivateMessages) {\n\t\t\treturn;\n\t\t}\n\n\t\tdecryptionBlock = ^(NSString *originalString, BOOL wasEncrypted) {\n\t\t\t[self _receiveText_Private:m lineType:lineType target:target text:originalString wasEncrypted:wasEncrypted];\n\t\t};\n\t}\n\n\t/* Private message (from server) */\n\telse {\n\t\t/* It is not possible to hold an OTR conversation with a server. */\n\t\tperformDecryption = NO;\n\n\t\tdecryptionBlock = ^(NSString *originalString, BOOL wasEncrypted) {\n\t\t\t[self _receiveText_PrivateServer:m lineType:lineType target:target text:originalString wasEncrypted:wasEncrypted];\n\t\t};\n\t}\n\n\t/* Perform decryption */\n\tif (performDecryption) {\n\t\tNSString *sender = m.senderNickname;\n\n\t\t[self decryptMessage:text from:sender target:target decodingCallback:decryptionBlock];\n\t} else {\n\t\tdecryptionBlock(text, NO);\n\t}\n}\n\n- (void)_receiveText_Public:(IRCMessage *)m lineType:(TVCLogLineType)lineType target:(NSString *)target text:(NSString *)text wasEncrypted:(BOOL)wasEncrypted\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(target != nil);\n\tNSParameterAssert(text != nil);\n\n\tIRCChannel *channel = [self findChannel:target];\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\tNSString *sender = m.senderNickname;\n\n\tBOOL isSelfMessage = NO;\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage]) {\n\t\tisSelfMessage = [self nicknameIsMyself:sender];\n\t}\n\n\tTVCLogControllerPrintOperationCompletionBlock printCompletionBlock = nil;\n\n\tBOOL isPlainText = (lineType != TVCLogLineTypeNotice);\n\n\tif (isPlainText == NO) {\n\t\t/* Completion block for notices */\n\n\t\tprintCompletionBlock =\n\t\t^(TVCLogControllerPrintOperationContext *context)\n\t\t{\n\t\t\tif ([self isSafeToPostNotificationForMessage:m inChannel:channel]) {\n\t\t\t\t[self notifyText:TXNotificationTypeChannelNotice lineType:lineType target:channel nickname:sender text:text];\n\t\t\t}\n\t\t};\n\t} else {\n\t\t/* Completion block for regular messages */\n\n\t\tprintCompletionBlock =\n\t\t^(TVCLogControllerPrintOperationContext *context)\n\t\t{\n\t\t\tif (isSelfMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBOOL isHighlight = context.highlight;\n\n\t\t\tBOOL postEvent = YES;\n\n\t\t\tif ([self isSafeToPostNotificationForMessage:m inChannel:channel]) {\n\t\t\t\tif (isHighlight) {\n\t\t\t\t\tpostEvent = [self notifyText:TXNotificationTypeHighlight lineType:lineType target:channel nickname:sender text:text];\n\t\t\t\t} else {\n\t\t\t\t\tpostEvent = [self notifyText:TXNotificationTypeChannelMessage lineType:lineType target:channel nickname:sender text:text];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (postEvent == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (isHighlight) {\n\t\t\t\t[self setHighlightStateForChannel:channel];\n\t\t\t}\n\n\t\t\t[self setUnreadStateForChannel:channel isHighlight:isHighlight];\n\t\t};\n\t}\n\n\t/* Ask for permission to print message */\n\tBOOL printMessage = YES;\n\n\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent]) {\n\t\tprintMessage = [THOPluginDispatcher receivedText:text\n\t\t\t\t\t\t\t\t\t\t\t  authoredBy:m.sender\n\t\t\t\t\t\t\t\t\t\t\t destinedFor:channel\n\t\t\t\t\t\t\t\t\t\t\t  asLineType:lineType\n\t\t\t\t\t\t\t\t\t\t\t\tonClient:self\n\t\t\t\t\t\t\t\t\t\t\t  receivedAt:m.receivedAt\n\t\t\t\t\t\t\t\t\t\t\twasEncrypted:wasEncrypted];\n\t}\n\n\t/* Print message */\n\tif (printMessage) {\n\t\t[self print:text\n\t\t\t\t by:sender\n\t\t  inChannel:channel\n\t\t\t asType:lineType\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt\n\t\tisEncrypted:wasEncrypted\n   referenceMessage:m\n\tcompletionBlock:printCompletionBlock];\n\t}\n\n\t/* The remaining logic does not apply to notices */\n\tif (isPlainText == NO) {\n\t\treturn;\n\t}\n\n\t/* Update weights of user we're talking with */\n\tIRCChannelUser *senderMember = [channel findMember:sender];\n\n\tif (senderMember == nil) {\n\t\treturn;\n\t}\n\n\tNSString *localNickname = [self.userNickname trimCharacters:@\"_\"]; // Remove any underscores from around nickname (Guest___ becomes Guest)\n\n\t/* If we are mentioned in this piece of text, then update our weight for the user */\n\tif ([text contains:localNickname]) {\n\t\t[senderMember outgoingConversation];\n\t} else {\n\t\t[senderMember conversation];\n\t}\n}\n\n- (void)_receiveText_Private:(IRCMessage *)m lineType:(TVCLogLineType)lineType target:(NSString *)target text:(NSString *)text wasEncrypted:(BOOL)wasEncrypted\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(target != nil);\n\tNSParameterAssert(text != nil);\n\n\tNSString *sender = m.senderNickname;\n\n\tTVCLogControllerPrintOperationCompletionBlock printCompletionBlock = nil;\n\n\tBOOL isPlainText = (lineType != TVCLogLineTypeNotice);\n\n\t/* If the self-message CAP is not enabled, we still check if we are on a ZNC\n\t based connections because older versions of ZNC combined with the privmsg\n\t module need the correct behavior which the self-message CAP evolved into. */\n\tBOOL isSelfMessage = NO;\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage] ||\n\t\t[self isCapabilityEnabled:ClientIRCv3SupportedCapabilityZNCSelfMessage] ||\n\t\tself.isConnectedToZNC)\n\t{\n\t\tisSelfMessage = [self nicknameIsMyself:sender];\n\t}\n\n\t/* Does the query for the sender already exist?... */\n\tIRCChannel *query = nil;\n\n\tif (isSelfMessage) {\n\t\tquery = [self findChannel:target]; // Look for a query related to target, rather than sender\n\t} else {\n\t\tquery = [self findChannel:sender];\n\t}\n\n\tBOOL newPrivateMessage = NO;\n\n\tif (isPlainText == NO) {\n\t\t/* Logic for notices */\n\n\t\t/* Process services */\n\t\tif ([sender isEqualToStringIgnoringCase:@\"ChanServ\"]) {\n\t\t\t[self _receiveText_PrivateNoticeFromChanServ:&query text:&text];\n\t\t} else if ([sender isEqualToStringIgnoringCase:@\"NickServ\"]) {\n\t\t\t[self _receiveText_PrivateNoticeFromNickServ:&query text:&text];\n\t\t}\n\n\t\t/* Determine where to send notice messages */\n\t\tif ([TPCPreferences locationToSendNotices] == TXNoticeSendLocationSelectedChannel) {\n\t\t\tquery = [mainWindow() selectedChannelOn:self];\n\t\t}\n\n\t\t/* Do not create query until after ChanServ notices have been processed\n\t\t so that entry messages do not create a new window. */\n\t\tif (query == nil) {\n\t\t\tif ([TPCPreferences locationToSendNotices] == TXNoticeSendLocationQuery) {\n//\t\t\t\tnewPrivateMessage = YES;\n\n\t\t\t\tif (isSelfMessage) {\n\t\t\t\t\tquery = [worldController() createPrivateMessage:target onClient:self];\n\t\t\t\t} else {\n\t\t\t\t\tquery = [worldController() createPrivateMessage:sender onClient:self];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tprintCompletionBlock =\n\t\t^(TVCLogControllerPrintOperationContext *context)\n\t\t{\n\t\t\tif (isSelfMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBOOL postEvent = YES;\n\n\t\t\tif ([self isSafeToPostNotificationForMessage:m inChannel:query]) {\n\t\t\t\tpostEvent = [self notifyText:TXNotificationTypePrivateNotice lineType:lineType target:query nickname:sender text:text];\n\t\t\t}\n\n\t\t\tif (postEvent && query != nil) {\n\t\t\t\t[self setUnreadStateForChannel:query];\n\t\t\t}\n\t\t};\n\t}\n\telse // NOTICE message\n\t{\n\t\t/* Logic for regular messages */\n\n\t\tif (query == nil) {\n\t\t\tnewPrivateMessage = YES;\n\n\t\t\tif (isSelfMessage) {\n\t\t\t\tquery = [worldController() createPrivateMessage:target onClient:self];\n\t\t\t} else {\n\t\t\t\tquery = [worldController() createPrivateMessage:sender onClient:self];\n\t\t\t}\n\t\t}\n\n\t\tprintCompletionBlock =\n\t\t^(TVCLogControllerPrintOperationContext *context)\n\t\t{\n\t\t\tif (isSelfMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBOOL isHighlight = context.highlight;\n\n\t\t\tBOOL postEvent = YES;\n\n\t\t\tif ([self isSafeToPostNotificationForMessage:m inChannel:query]) {\n\t\t\t\tif (isHighlight) {\n\t\t\t\t\tpostEvent = [self notifyText:TXNotificationTypeHighlight lineType:lineType target:query nickname:sender text:text];\n\t\t\t\t} else {\n\t\t\t\t\tif (newPrivateMessage) {\n\t\t\t\t\t\tpostEvent = [self notifyText:TXNotificationTypeNewPrivateMessage lineType:lineType target:query nickname:sender text:text];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpostEvent = [self notifyText:TXNotificationTypePrivateMessage lineType:lineType target:query nickname:sender text:text];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (postEvent == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (isHighlight) {\n\t\t\t\t[self setHighlightStateForChannel:query];\n\t\t\t}\n\n\t\t\t[self setUnreadStateForChannel:query isHighlight:isHighlight];\n\t\t};\n\t}\n\n\t/* Ask for permission to print message */\n\tBOOL printMessage = YES;\n\n\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent]) {\n\t\tprintMessage = [THOPluginDispatcher receivedText:text\n\t\t\t\t\t\t\t\t\t\t\t  authoredBy:m.sender\n\t\t\t\t\t\t\t\t\t\t\t destinedFor:query\n\t\t\t\t\t\t\t\t\t\t\t  asLineType:lineType\n\t\t\t\t\t\t\t\t\t\t\t\tonClient:self\n\t\t\t\t\t\t\t\t\t\t\t  receivedAt:m.receivedAt\n\t\t\t\t\t\t\t\t\t\t\twasEncrypted:wasEncrypted];\n\t}\n\n\t/* Print message */\n\tif (printMessage) {\n\t\t[self print:text\n\t\t\t\t by:sender\n\t\t  inChannel:query\n\t\t\t asType:lineType\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt\n\t\tisEncrypted:wasEncrypted\n   referenceMessage:m\n\tcompletionBlock:printCompletionBlock];\n\t}\n\n\t/* The remaining logic does not apply to notices */\n\tif (isPlainText == NO) {\n\t\treturn;\n\t}\n\n\t/* Update query status */\n\tif (query.isActive == NO) {\n\t\t[query activate];\n\n\t\t[mainWindow() reloadTreeItem:query];\n\t}\n}\n\n- (void)_receiveText_PrivateNoticeFromChanServ:(IRCChannel **)target text:(NSString **)text\n{\n\tNSParameterAssert(target != NULL);\n\tNSParameterAssert(text != NULL);\n\n\tNSString *textIn = (*text);\n\n\t/* Forward entry messages to the channel they are associated with. */\n\t/* Format we are going for: -ChanServ- [#channelname] blah blah... */\n\tNSInteger spacePosition = [textIn stringPosition:@\" \"];\n\n\tif ([textIn hasPrefix:@\"[\"] == NO || spacePosition < 4) {\n\t\treturn;\n\t}\n\n\tNSString *textHead = [textIn substringToIndex:spacePosition];\n\n\tif ([textHead hasSuffix:@\"]\"] == NO) {\n\t\treturn;\n\t}\n\n\ttextHead = [textHead substringToIndex:(textHead.length - 1)]; // Remove the ]\n\ttextHead = [textHead substringFromIndex:1]; // Remove the [\n\n\tif ([self stringIsChannelName:textHead] == NO) {\n\t\treturn;\n\t}\n\n\tIRCChannel *channel = [self findChannel:textHead];\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\t*text = [textIn substringFromIndex:(textHead.length + 2)]; // Remove the [#channelname] from the text\n\n\t*target = channel;\n}\n\n- (void)_receiveText_PrivateNoticeFromNickServ:(IRCChannel **)target text:(NSString **)text\n{\n\tNSParameterAssert(target != NULL);\n\tNSParameterAssert(text != NULL);\n\n\tself.serverHasNickServ = YES;\n\n\tNSString *textIn = nil;\n\n\tif ([TPCPreferences removeAllFormatting] == NO) {\n\t\ttextIn = (*text).stripIRCEffects;\n\t} else {\n\t\ttextIn = (*text);\n\t}\n\n\t/* If we are not waiting for a response from NickServ, \n\t then try sending our password if that's what it requested. */\n\tif (self.isWaitingForNickServ == NO) {\n\t\tNSString *nicknamePassword = self.config.nicknamePassword;\n\n\t\tif (nicknamePassword.length == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (NSString *token in self.nickServSupportedNeedIdentificationTokens) {\n\t\t\tif ([textIn containsIgnoringCase:token] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Send password\n\t\t\tif ([self.serverAddress hasSuffix:@\".dal.net\"])\n\t\t\t{\n\t\t\t\tNSString *message = [NSString stringWithFormat:@\"IDENTIFY %@\", nicknamePassword];\n\n\t\t\t\t[self send:@\"PRIVMSG\", @\"NickServ@services.dal.net\", message, nil];\n\t\t\t}\n\t\t\telse if (self.config.sendAuthenticationRequestsToUserServ)\n\t\t\t{\n\t\t\t\tNSString *message = [NSString stringWithFormat:@\"login %@ %@\", self.config.nickname, nicknamePassword];\n\n\t\t\t\t[self send:@\"PRIVMSG\", @\"userserv\", message, nil];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tNSString *message = [NSString stringWithFormat:@\"IDENTIFY %@\", nicknamePassword];\n\n\t\t\t\t[self send:@\"PRIVMSG\", @\"NickServ\", message, nil];\n\t\t\t}\n\n\t\t\t// Reset properties\n\t\t\tself.isWaitingForNickServ = YES;\n\n\t\t\tself.userIsIdentifiedWithNickServ = NO;\n\n\t\t\tbreak;\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Scan for messages telling us that we are now identified */\n\tfor (NSString *token in self.nickServSupportedSuccessfulIdentificationTokens) {\n\t\tif ([textIn containsIgnoringCase:token] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tself.isWaitingForNickServ = NO;\n\n\t\tself.userIsIdentifiedWithNickServ = YES;\n\n\t\tif (self.config.autojoinWaitsForNickServ) {\n\t\t\t[self performAutoJoin];\n\t\t}\n\n\t\tbreak;\n\t}\n}\n\n- (void)_receiveText_PrivateServer:(IRCMessage *)m lineType:(TVCLogLineType)lineType target:(NSString *)target text:(NSString *)text wasEncrypted:(BOOL)wasEncrypted\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(target != nil);\n\tNSParameterAssert(text != nil);\n\n\tNSString *sender = m.senderNickname;\n\n\tBOOL isPlainText = (lineType != TVCLogLineTypeNotice);\n\n\tIRCChannel *query = nil;\n\n\t/* For notices, send to a query if a query for the server already exists.\n\t Otherwise, it is always sent to the console. Plain text messages always\n\t create a new query but does not post a notification. */\n\tif (isPlainText == NO) {\n\t\tquery = [self findChannel:sender];\n\t} else { // NOTICE message\n\t\tquery = [self findChannelOrCreate:sender isPrivateMessage:YES];\n\t}\n\n\t/* Print message */\n\tBOOL printMessage = YES;\n\n\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureDidReceivePlainTextMessageEvent]) {\n\t\tprintMessage = [THOPluginDispatcher receivedText:text\n\t\t\t\t\t\t\t\t\t\t\t  authoredBy:m.sender\n\t\t\t\t\t\t\t\t\t\t\t destinedFor:query\n\t\t\t\t\t\t\t\t\t\t\t  asLineType:lineType\n\t\t\t\t\t\t\t\t\t\t\t\tonClient:self\n\t\t\t\t\t\t\t\t\t\t\t  receivedAt:m.receivedAt\n\t\t\t\t\t\t\t\t\t\t\twasEncrypted:wasEncrypted];\n\t}\n\n\tif (printMessage) {\n\t\t[self print:text\n\t\t\t\t by:sender\n\t\t  inChannel:query\n\t\t\t asType:lineType\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt\n\t\tisEncrypted:wasEncrypted];\n\t}\n\n\t/* Disconnect and reconnect if message is believed to be from an irssi proxy */\n\t/* If we do not do this, the internal state of the client becomes fucked all around */\n\tif ([sender hasSuffix:@\".proxy\"] && [text isEqualToString:@\"Connected to server\"]) {\n\t\t__weak IRCClient *weakSelf = self;\n\n\t\tself.disconnectCallback = ^{\n\t\t\t[weakSelf printDebugInformationToConsole:TXTLS(@\"IRC[5i4-qq]\")];\n\n\t\t\t[weakSelf connect:IRCClientConnectModeReconnect];\n\t\t};\n\n\t\t[self disconnect];\n\t}\n}\n\n- (void)receiveCTCPQuery:(IRCMessage *)m text:(NSString *)text\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(text != nil);\n\n\tNSString *sender = m.senderNickname;\n\n\tBOOL myself = [self nicknameIsMyself:sender];\n\n\tIRCAddressBookEntry *ignoreInfo = nil;\n\n\tif (myself) {\n\t\t/* Ignore messages echoed back to ourselves */\n\t\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage]) {\n\t\t\treturn;\n\t\t}\n\t} else {\n\t\t/* Find ignore for sender and possibly exit method */\n\t\tignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\t\tif (ignoreInfo.ignoreClientToClientProtocol) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Context */\n\tNSMutableString *textMutable = [text mutableCopy];\n\n\tNSString *command = textMutable.uppercaseGetToken;\n\n\tif (command.length == 0) {\n\t\treturn;\n\t}\n\n\t/* Lag check responses should only ever come from ourselves so we\n\t let it through. The method we call into already has a built-in\n\t check for myself so no need to wrap an if statement here. */\n\tif ([command isEqualToString:@\"LAGCHECK\"]) {\n\t\t[self receiveCTCPLagCheckQuery:m text:textMutable];\n\n\t\treturn;\n\t}\n\n\t/* Ignore query if the user has configured Textual to do so */\n\tif ([TPCPreferences replyToCTCPRequests] == NO) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[bg3-h2]\", command, sender)];\n\n\t\treturn;\n\t}\n\n\t/* Process DCC requests elsewhere */\n\tif ([command isEqualToString:@\"DCC\"]) {\n\t\t[self receivedDCCQuery:m text:textMutable ignoreInfo:ignoreInfo];\n\n\t\treturn;\n\t}\n\n\t/* Print message */\n\tIRCChannel *printTarget = nil;\n\n\tif ([TPCPreferences locationToSendNotices] == TXNoticeSendLocationSelectedChannel) {\n\t\tprintTarget = [mainWindow() selectedChannelOn:self];\n\t}\n\n\tNSString *messageToPrint = TXTLS(@\"IRC[6o8-eu]\", command, sender);\n\n\t[self print:messageToPrint\n\t\t\t by:nil\n\t  inChannel:printTarget\n\t\t asType:TVCLogLineTypeCTCPQuery\n\t\tcommand:m.command\n\t receivedAt:m.receivedAt];\n\n\t/* CLIENTINFO command */\n\tif ([command isEqualToString:@\"CLIENTINFO\"])\n\t{\n\t\t[self sendCTCPReply:sender command:command text:TXTLS(@\"IRC[jer-ju]\")];\n\t}\n\n\t/* FINGER command */\n\telse if ([command isEqualToString:@\"FINGER\"])\n\t{\n\t\t[self sendCTCPReply:sender command:command text:TXTLS(@\"IRC[en6-mw]\")];\n\t}\n\n\t/* PING command */\n\telse if ([command isEqualToString:@\"PING\"])\n\t{\n\t\tif (textMutable.length > 50) {\n\t\t\tLogToConsoleFault(\"Ignoring PING query that exceeds 50 bytes\");\n\n\t\t\treturn;\n\t\t}\n\n\t\t[self sendCTCPReply:sender command:command text:textMutable];\n\t}\n\n\t/* TIME command */\n\telse if ([command isEqualToString:@\"TIME\"])\n\t{\n\t\tNSDateFormatter *dateFormatter = TXSharedISOStandardDateFormatter();\n\n\t\tNSString *text = [dateFormatter stringFromDate:[NSDate date]];\n\n\t\t[self sendCTCPReply:sender command:command text:text];\n\t}\n\n\t/* USERINFO command */\n\telse if ([command isEqualToString:@\"USERINFO\"])\n\t{\n\t\t[self sendCTCPReply:sender command:command text:self.config.realName];\n\t}\n\n\t/* VERSION command */\n\telse if ([command isEqualToString:@\"VERSION\"])\n\t{\n\t\tNSString *fakeVersion = [TPCPreferences masqueradeCTCPVersion];\n\n\t\tif (fakeVersion.length > 0) {\n\t\t\t[self sendCTCPReply:sender command:command text:fakeVersion];\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *applicationName = [TPCApplicationInfo applicationNameWithoutVersion];\n\t\tNSString *versionShort = [TPCApplicationInfo applicationVersionShort];\n\n\t\tNSString *text = TXTLS(@\"IRC[vzu-u7]\", applicationName, versionShort);\n\n\t\t[self sendCTCPReply:sender command:command text:text];\n\t}\n}\n\n- (void)receiveCTCPLagCheckQuery:(IRCMessage *)m text:(NSString *)text\n{\n\tNSParameterAssert(m != nil);\n\n\tif ([self messageIsFromMyself:m] == NO) {\n\t\treturn;\n\t}\n\t\n\tNSDictionary *lagCheckContext = [text formDataUsingSeparator:@\"&\"];\n\t\n\tif (lagCheckContext.count == 0) {\n\t\treturn;\n\t}\n\n\tNSString *connectionIdentifier = lagCheckContext[@\"connection\"];\n\t\n\tif ([connectionIdentifier isEqualToString:self.socket.uniqueIdentifier] == NO) {\n\t\t/* We check which connection this event is linked to so that\n\t\t we ignore events after reconnects (such as from a bouncer). */\n\n\t\treturn;\n\t}\n\t\n\tNSTimeInterval firstTime = [lagCheckContext doubleForKey:@\"time\"];\n\n\tdouble delta = (([NSDate timeIntervalSince1970] - firstTime) * 1000);\n\t\n\tNSString *ratingString = nil;\n\t\n\tif (delta < 10) { // Yeah, okay…\n\t\tratingString = TXTLS(@\"IRC[58g-m9]\");\n\t} else if (delta > 10 && delta <= 25) { // Are you plugged into the server?\n\t\tratingString = TXTLS(@\"IRC[0jp-93]\");\n\t} else if (delta > 25 && delta <= 100) { // Pretty good\n\t\tratingString = TXTLS(@\"IRC[yym-8y]\");\n\t} else if (delta > 100 && delta <= 125) { // Not bad\n\t\tratingString = TXTLS(@\"IRC[mic-qe]\");\n\t} else if (delta > 125 && delta <= 200) { // Okay\n\t\tratingString = TXTLS(@\"IRC[mqg-wi]\");\n\t} else if (delta > 200 && delta <= 225) { // Needs work\n\t\tratingString = TXTLS(@\"IRC[ut8-7s]\");\n\t} else if (delta > 225 && delta <= 300) { // Slow\n\t\tratingString = TXTLS(@\"IRC[8fo-ss]\");\n\t} else if (delta > 300) { // Very Slow\n\t\tratingString = TXTLS(@\"IRC[4oc-p2]\");\n\t}\n\t\n\tNSString *message = TXTLS(@\"IRC[5bf-jp]\", self.serverAddress, delta, ratingString);\n\t\n\tNSString *channelName = lagCheckContext[@\"channel\"];\n\t\n\tIRCChannel *channel = nil;\n\t\n\tif (channelName) {\n\t\tchannel = [self findChannel:channelName];\n\t}\n\n\tif (channel) {\n\t\t[self sendPrivmsg:message toChannel:channel];\n\t} else {\n\t\t[self printDebugInformation:message];\n\t}\n}\n\n- (void)receiveCTCPReply:(IRCMessage *)m text:(NSString *)text\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(text != nil);\n\n\t/* Find ignore for sender and possibly exit method */\n\tIRCAddressBookEntry *ignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\tif (ignoreInfo.ignoreClientToClientProtocol) {\n\t\treturn;\n\t}\n\n\t/* Context */\n\tNSMutableString *textMutable = [text mutableCopy];\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *command = textMutable.uppercaseGetToken;\n\n\tif (command.length == 0) {\n\t\treturn;\n\t}\n\n\t/* Print message */\n\tIRCChannel *printTarget = nil;\n\n\tif ([TPCPreferences locationToSendNotices] == TXNoticeSendLocationSelectedChannel) {\n\t\tprintTarget = [mainWindow() selectedChannelOn:self];\n\t}\n\n\tNSString *messageToPrint = nil;\n\n\tif ([command isEqualToString:@\"PING\"]) {\n\t\tdouble delta = ([NSDate timeIntervalSince1970] - textMutable.doubleValue);\n\n\t\tmessageToPrint = TXTLS(@\"IRC[vy7-pk]\", sender, command, delta);\n\t} else {\n\t\tmessageToPrint = TXTLS(@\"IRC[dri-l7]\", sender, command, textMutable);\n\t}\n\n\t[self print:messageToPrint\n\t\t\t by:nil\n\t  inChannel:printTarget\n\t\t asType:TVCLogLineTypeCTCPReply\n\t\tcommand:m.command\n\t receivedAt:m.receivedAt];\n}\n\n- (void)receiveJoin:(IRCMessage *)m\n{\n\tNSAssertReturn([m paramsCount] > 0);\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *sender = m.senderNickname;\n\n\tBOOL myself = [self nicknameIsMyself:sender];\n\n\tNSString *channelName = [m paramAt:0];\n\n\tIRCChannel *channel = nil;\n\n\tif (isPrintOnlyMessage == NO && myself)\n\t{\n\t\tchannel = [self findChannelOrCreate:channelName];\n\n\t\tif (channel.isActive == NO && channel.isChannel) {\n\t\t\t[channel activate];\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tself.userHostmask = m.senderHostmask;\n\n\t\t[mainWindow() reloadTreeItem:channel];\n\t}\n\telse // myself\n\t{\n\t\tchannel = [self findChannel:channelName];\n\n\t\tif (channel == nil || channel.isChannel == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\t/* A user might already exist by having a private message open */\n\t\tIRCUserMutable *userMutable = [self mutableCopyOfUserWithNickname:sender];\n\n\t\tuserMutable.nickname = m.senderNickname;\n\t\tuserMutable.username = m.senderUsername;\n\t\tuserMutable.address = m.senderAddress;\n\n\t\tIRCUser *userAdded = [self addUserAndReturn:userMutable];\n\n\t\tIRCChannelUser *member = [[IRCChannelUser alloc] initWithUser:userAdded];\n\n\t\t[channel addMember:member checkForDuplicates:YES];\n\t}\n\n\tif (isPrintOnlyMessage == NO && myself == NO) {\n\t\tIRCChannel *senderQuery = [self findChannel:sender];\n\n\t\tif (senderQuery && senderQuery.isActive == NO) {\n\t\t\t[senderQuery activate];\n\n\t\t\t[self print:TXTLS(@\"IRC[q0q-ch]\", sender)\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:senderQuery\n\t\t\t\t asType:TVCLogLineTypeJoin\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\t[mainWindow() reloadTreeItem:senderQuery];\n\t\t}\n\t}\n\n\tIRCAddressBookEntry *ignoreInfo = nil;\n\n\tif (myself == NO) {\n\t\tignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\t\tif (ignoreInfo && isPrintOnlyMessage == NO) {\n\t\t\t[self updateUserTrackingStatusForEntry:ignoreInfo withMessage:m];\n\t\t}\n\t}\n\n\tBOOL printMessage = [self postReceivedMessage:m withText:nil destinedFor:channel];\n\n\tif (printMessage && myself == NO)\n\t{\n\t\tif ([TPCPreferences showJoinLeave] == NO) {\n\t\t\tprintMessage = NO;\n\t\t} else if (channel.config.ignoreGeneralEventMessages) {\n\t\t\tprintMessage = NO;\n\t\t} else if (ignoreInfo) {\n\t\t\tprintMessage = (ignoreInfo.ignoreGeneralEventMessages == NO);\n\t\t}\n\t}\n\n\tif (printMessage) {\n\t\tNSString *message = TXTLS(@\"IRC[ziu-p9]\", sender, m.senderUsername, m.senderAddress.stringByAppendingIRCFormattingStop);\n\n\t\t[self print:message\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeJoin\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n\n\tif (isPrintOnlyMessage) {\n\t\treturn;\n\t}\n\n\t[mainWindow() updateTitleFor:channel];\n\n\tif (myself) {\n\t\tif (self.config.sendWhoCommandRequestsToChannels && self.isBrokenIRCd_aka_Twitch == NO) {\n\t\t\t[self requestModesForChannel:channel];\n\t\t}\n\t} else {\n\t\t[self notifyEvent:TXNotificationTypeUserJoined lineType:TVCLogLineTypeJoin target:channel nickname:sender text:nil];\n\t}\n}\n\n- (void)receivePart:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 0);\n\n\t/* ZNC sends PART messages for every channel when the client disconnects to force\n\t it to update its local status. This is incredibly misleading to the user, as they\n\t see the message that they left the channel and believe they did. This condition\n\t filters out these messages. Because Textual is intelligent enough to clear status\n\t related to channels when the connection is quit, this is safe. */\n\tif (self.isQuitting && self.isConnectedToZNC) {\n\t\treturn;\n\t}\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *channelName = [m paramAt:0];\n\n\tIRCChannel *channel = [self findChannel:channelName];\n\n\tif (channel == nil || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *comment = [m paramAt:1];\n\n\tBOOL myself = [self nicknameIsMyself:sender];\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tif (myself) {\n\t\t\t[channel deactivate];\n\n\t\t\t[mainWindow() reloadTreeItem:channel];\n\t\t} else {\n\t\t\t[channel removeMemberWithNickname:sender];\n\n\t\t\t/* Notify user */\n\t\t\t[self notifyEvent:TXNotificationTypeUserParted lineType:TVCLogLineTypePart target:channel nickname:sender text:comment];\n\t\t}\n\t}\n\n\tBOOL printMessage = [self postReceivedMessage:m withText:comment destinedFor:channel];\n\n\tif (printMessage && myself == NO)\n\t{\n\t\tif ([TPCPreferences showJoinLeave] == NO) {\n\t\t\tprintMessage = NO;\n\t\t} else if (channel.config.ignoreGeneralEventMessages) {\n\t\t\tprintMessage = NO;\n\t\t} else {\n\t\t\tIRCAddressBookEntry *ignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\t\t\tif (ignoreInfo) {\n\t\t\t\tprintMessage = (ignoreInfo.ignoreGeneralEventMessages == NO);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (printMessage) {\n\t\tNSString *message = TXTLS(@\"IRC[nkr-kf]\", sender, m.senderUsername, m.senderAddress.stringByAppendingIRCFormattingStop);\n\n\t\tif (comment.length > 0) {\n\t\t\tmessage = TXTLS(@\"IRC[ozy-6i]\", message, comment.stringByAppendingIRCFormattingStop);\n\t\t}\n\n\t\t[self print:message\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypePart\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\t[mainWindow() updateTitleFor:channel];\n\t}\n}\n\n- (void)receiveKick:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 1);\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *channelName = [m paramAt:0];\n\n\tIRCChannel *channel = [self findChannel:channelName];\n\n\tif (channel == nil || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *target = [m paramAt:1];\n\tNSString *comment = [m paramAt:2];\n\n\tBOOL myself = [self nicknameIsMyself:target];\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tif (myself)\n\t\t{\n\t\t\t[channel deactivate];\n\n\t\t\t[mainWindow() reloadTreeItem:channel];\n\n\t\t\t/* Notify user */\n\t\t\t[self notifyEvent:TXNotificationTypeKick lineType:TVCLogLineTypeKick target:channel nickname:sender text:comment];\n\n\t\t\t/* Rejoin channel */\n\t\t\tif ([TPCPreferences rejoinOnKick] && channel.errorOnLastJoinAttempt == NO) {\n\t\t\t\t[self printDebugInformation:TXTLS(@\"IRC[zzj-2h]\") inChannel:channel];\n\n\t\t\t\t[self cancelPerformRequestsWithSelector:@selector(joinKickedChannel:) object:channel];\n\n\t\t\t\t[self performSelectorInCommonModes:@selector(joinKickedChannel:) withObject:channel afterDelay:3.0];\n\t\t\t}\n\t\t}\n\t\telse // myself\n\t\t{\n\t\t\t[channel removeMemberWithNickname:target];\n\t\t}\n\t}\n\n\tBOOL printMessage = [self postReceivedMessage:m withText:comment destinedFor:channel];\n\n\tif (printMessage && myself == NO)\n\t{\n\t\tif ([TPCPreferences showJoinLeave] == NO) {\n\t\t\tprintMessage = NO;\n\t\t} else if (channel.config.ignoreGeneralEventMessages) {\n\t\t\tprintMessage = NO;\n\t\t} else {\n\t\t\tIRCAddressBookEntry *ignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\t\t\tif (ignoreInfo) {\n\t\t\t\tprintMessage = (ignoreInfo.ignoreGeneralEventMessages == NO);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (printMessage) {\n\t\tNSString *message = TXTLS(@\"IRC[9aj-bd]\", sender, target, comment.stringByAppendingIRCFormattingStop);\n\n\t\t[self print:message\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeKick\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\t[mainWindow() updateTitleFor:channel];\n\t}\n}\n\n- (void)receiveQuit:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 0);\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *channelName = nil;\n\n\tNSString *comment = nil;\n\n\tif (isPrintOnlyMessage) {\n\t\tchannelName = [m paramAt:0];\n\n\t\tcomment = [m paramAt:1];\n\t} else {\n\t\tcomment = [m paramAt:0];\n\t}\n\n\tNSString *sender = m.senderNickname;\n\n\tBOOL myself = [self nicknameIsMyself:sender];\n\n\tIRCUser *user = nil;\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tuser = [self findUser:sender];\n\n\t\tif (user == nil) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tIRCAddressBookEntry *ignoreInfo = nil;\n\n\tif (myself == NO) {\n\t\tignoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\n\t\tif (ignoreInfo && isPrintOnlyMessage == NO) {\n\t\t\t[self updateUserTrackingStatusForEntry:ignoreInfo withMessage:m];\n\t\t}\n\t}\n\n\tNSString *messageToPrint = TXTLS(@\"IRC[53b-dm]\", sender, m.senderUsername, m.senderAddress.stringByAppendingIRCFormattingStop);\n\n\tif (comment.length > 0) {\n\t\tmessageToPrint = TXTLS(@\"IRC[tok-st]\", messageToPrint, comment.stringByAppendingIRCFormattingStop);\n\t}\n\n\tvoid (^printingBlock)(IRCChannel *) = ^(IRCChannel *channel)\n\t{\n\t\tif (myself == NO && isPrintOnlyMessage == NO) {\n\t\t\tswitch (channel.type) {\n\t\t\t\tcase IRCChannelTypeChannel:\n\t\t\t\t{\n\t\t\t\t\tIRCChannelUser *member = [user userAssociatedWithChannel:channel];\n\n\t\t\t\t\tif (member == nil) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t[channel removeMember:member];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IRCChannelTypePrivateMessage:\n\t\t\t\t{\n\t\t\t\t\tif ([sender isEqualToStringIgnoringCase:channel.name] == NO) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (channel.isActive) {\n\t\t\t\t\t\t[channel deactivate];\n\n\t\t\t\t\t\t[mainWindow() reloadTreeItem:channel];\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tNSString *message = messageToPrint;\n\n\t\tif (channel.isChannel)\n\t\t{\n\t\t\tBOOL printMessage = [self postReceivedMessage:m withText:comment destinedFor:channel];\n\n\t\t\tif (printMessage && myself == NO)\n\t\t\t{\n\t\t\t\tif ([TPCPreferences showJoinLeave] == NO) {\n\t\t\t\t\tprintMessage = NO;\n\t\t\t\t} else if (channel.config.ignoreGeneralEventMessages) {\n\t\t\t\t\tprintMessage = NO;\n\t\t\t\t} else if (ignoreInfo) {\n\t\t\t\t\tprintMessage = (ignoreInfo.ignoreGeneralEventMessages == NO);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[mainWindow() updateTitleFor:channel];\n\n\t\t\tif (printMessage == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse // -isChannel\n\t\t{\n\t\t\tmessage = TXTLS(@\"IRC[8bk-mx]\", sender);\n\t\t}\n\n\t\t[self print:message\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeQuit\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t};\n\n\tif (isPrintOnlyMessage) {\n\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tprintingBlock(channel);\n\n\t\treturn;\n\t}\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\tprintingBlock(c);\n\t}\n\n\tif (myself == NO) {\n\t\t[mainWindow() updateTitleFor:self];\n\n\t\t[self notifyEvent:TXNotificationTypeUserDisconnected lineType:TVCLogLineTypeQuit target:nil nickname:sender text:comment];\n\t}\n}\n\n- (void)receiveKill:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 0);\n\n\tNSString *nickname = [m paramAt:0];\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\t[c removeMemberWithNickname:nickname];\n\t}\n}\n\n- (void)receiveNick:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] == 1);\n\n\t/* Print only messages target specific channels which means\n\t the index of incoming data will be different */\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *channelName = nil;\n\n\tNSString *newNickname = nil;\n\n\tif (isPrintOnlyMessage) {\n\t\tchannelName = [m paramAt:0];\n\n\t\tnewNickname = [m paramAt:1];\n\t} else {\n\t\tnewNickname = [m paramAt:0];\n\t}\n\n\t/* There's no reason to perform an update if nothing changed */\n\tNSString *oldNickname = m.senderNickname;\n\n\tif ([oldNickname isEqualToString:newNickname]) {\n\t\treturn;\n\t}\n\n\tBOOL myself = [self nicknameIsMyself:oldNickname];\n\n\t/* Find address book entry for old nickname and update tracking\n\t status. This entry will also be used later on,\t when printing, \n\t to decide whether to print the message. */\n\tIRCAddressBookEntry *oldNicknameIgnoreInfo = nil;\n\n\tif (myself == NO) {\n\t\toldNicknameIgnoreInfo = [self findAddressBookEntryForHostmask:m.senderHostmask];\n\t}\n\n\t/* Perform restricted actions */\n\tif (isPrintOnlyMessage == NO) {\n\t\tif (myself)\n\t\t{\n\t\t\tself.userNickname = newNickname;\n\n\t\t\tif (self.tryingNicknameSentNickname != nil) {\n\t\t\t\tself.tryingNicknameSentNickname = newNickname;\n\t\t\t}\n\n\t\t\t/* Reload window title (our nickname is shown there) */\n\t\t\t[mainWindow() updateTitleFor:self];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Update user tracking status for old nickname */\n\t\t\tif (oldNicknameIgnoreInfo) {\n\t\t\t\t[self updateUserTrackingStatusForEntry:oldNicknameIgnoreInfo withMessage:m];\n\t\t\t}\n\n\t\t\t/* Update user tracking status for new nickname */\n\t\t\tIRCAddressBookEntry *newNicknameIgnoreInfo = [self findUserTrackingAddressBookEntryForNickname:newNickname];\n\n\t\t\tif (newNicknameIgnoreInfo) {\n\t\t\t\t[self updateUserTrackingStatusForEntry:newNicknameIgnoreInfo withMessage:m];\n\t\t\t}\n\t\t}\n\n\t\t/* Inform style of change */\n\t\t[self postEventToViewController:@\"nicknameChanged\"];\n\t}\n\n\t/* Inform observers */\n\t[RZNotificationCenter() postNotificationName:IRCClientUserNicknameChangedNotification\n\t\t\t\t\t\t\t\t\t\t  object:self\n\t\t\t\t\t\t\t\t\t\tuserInfo:@{\n\t\t\t\t\t\t\t\t\t\t\t@\"oldNickname\" : oldNickname,\n\t\t\t\t\t\t\t\t\t\t\t@\"newNickname\" : newNickname\n\t\t\t\t\t\t\t\t\t\t}];\n\n\t/* Look for user */\n\tIRCUser *user = nil;\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tuser = [self findUser:oldNickname];\n\n\t\tif (user == nil) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Setup block that is used by printing operations */\n\tNSString *messageToPrint = nil;\n\n\tif (myself) {\n\t\tmessageToPrint = TXTLS(@\"IRC[rr6-yo]\", newNickname);\n\t} else {\n\t\tmessageToPrint = TXTLS(@\"IRC[fxw-5s]\", oldNickname, newNickname);\n\t}\n\n\tvoid (^printingBlock)(IRCChannel *) = ^(IRCChannel *channel)\n\t{\n\t\tif (isPrintOnlyMessage == NO) {\n\t\t\tswitch (channel.type) {\n\t\t\t\tcase IRCChannelTypeChannel:\n\t\t\t\t{\n\t\t\t\t\t/* Rename the user in the channel */\n\t\t\t\t\tIRCChannelUser *member = [user userAssociatedWithChannel:channel];\n\n\t\t\t\t\tif (member == nil) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t[channel resortMember:member];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase IRCChannelTypePrivateMessage:\n\t\t\t\t{\n\t\t\t\t\t/* Rename private message if one with old name is found */\n\t\t\t\t\tif ([oldNickname isEqualToStringIgnoringCase:channel.name] == NO) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tIRCChannel *newNicknameQuery = [self findChannel:newNickname];\n\n\t\t\t\t\tif (newNicknameQuery) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tchannel.name = newNickname;\n\n\t\t\t\t\t[mainWindow() reloadTreeItem:channel];\n\n\t\t\t\t\t[mainWindow() updateTitleFor:channel]; // Refresh hostmask\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t} // isPrintOnlyMessage == NO\n\n\t\t/* Determine whether the message should be printed */\n\t\tif (channel.isChannel) {\n\t\t\tBOOL printMessage = [self postReceivedMessage:m withText:newNickname destinedFor:channel];\n\n\t\t\tif (printMessage && myself == NO)\n\t\t\t{\n\t\t\t\tif ([TPCPreferences showJoinLeave] == NO) {\n\t\t\t\t\tprintMessage = NO;\n\t\t\t\t} else if (channel.config.ignoreGeneralEventMessages) {\n\t\t\t\t\tprintMessage = NO;\n\t\t\t\t} else if (oldNicknameIgnoreInfo) {\n\t\t\t\t\tprintMessage = (oldNicknameIgnoreInfo.ignoreGeneralEventMessages == NO);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (printMessage == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t/* Print message */\n\t\t[self print:messageToPrint\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeNick\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t};\n\n\t/* Target print */\n\tif (isPrintOnlyMessage) {\n\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tprintingBlock(channel);\n\n\t\treturn;\n\t}\n\n\t/* Continue with normal operations */\n\t[self renameUser:user to:newNickname];\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\tprintingBlock(c);\n\t}\n}\n\n- (void)receiveMode:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 1);\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *channelName = [m paramAt:0];\n\tNSString *modeString = [m sequence:1];\n\n\t/* Present user modes */\n\tif ([self stringIsChannelName:channelName] == NO) {\n\t\tBOOL printMessage = [self postReceivedCommand:@\"UMODE\" withText:modeString destinedFor:nil referenceMessage:m];\n\n\t\tif (printMessage) {\n\t\t\t[self print:TXTLS(@\"IRC[v5d-ix]\", sender, modeString)\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:nil\n\t\t\t\t asType:TVCLogLineTypeMode\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Present channel modes */\n\tIRCChannel *channel = [self findChannel:channelName];\n\n\tif (channel == nil || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tNSArray *modes = [channel.modeInfo updateModes:modeString];\n\n\t\tfor (IRCModeInfo *mode in modes) {\n\t\t\tif ([mode isModeForChangingMemberModeOn:self] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[channel changeMember:mode.modeParameter mode:mode.modeSymbol value:mode.modeIsSet];\n\t\t}\n\t}\n\n\tBOOL printMessage = [self postReceivedMessage:m withText:modeString destinedFor:channel];\n\n\tif (printMessage) {\n\t\tprintMessage = ([TPCPreferences showJoinLeave] && channel.config.ignoreGeneralEventMessages == NO);\n\t}\n\n\tif (printMessage) {\n\t\t[self print:TXTLS(@\"IRC[v5d-ix]\", sender, modeString)\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeMode\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\t[mainWindow() updateTitleFor:channel];\n\t}\n}\n\n- (void)receiveTopic:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] == 2);\n\n\tBOOL isPrintOnlyMessage = m.isPrintOnlyMessage;\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *channelName = [m paramAt:0];\n\tNSString *topic = [m paramAt:1];\n\n\tIRCChannel *channel = [self findChannel:channelName];\n\n\tif (channel == nil || channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tif (isPrintOnlyMessage == NO) {\n\t\tchannel.topic = topic;\n\t}\n\n\tBOOL printMessage = [self postReceivedMessage:m withText:topic destinedFor:channel];\n\n\tif (printMessage) {\n\t\t[self print:TXTLS(@\"IRC[qq2-66]\", sender, topic)\n\t\t\t\t by:nil\n\t\t  inChannel:channel\n\t\t\t asType:TVCLogLineTypeTopic\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n}\n\n- (void)receiveInvite:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] == 2);\n\n\tNSString *sender = m.senderNickname;\n\n\tNSString *channelName = [m paramAt:1];\n\n\tNSString *message = TXTLS(@\"IRC[qw4-t3]\", sender, m.senderUsername, m.senderAddress, channelName);\n\n\t/* Invite notifications are sent to frontmost channel on server of if it is\n\t not on server, then it will be redirected to console. */\n\tBOOL printMessage = [self postReceivedMessage:m withText:channelName destinedFor:nil];\n\n\tif (printMessage) {\n\t\t[self print:message\n\t\t\t\t by:nil\n\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t asType:TVCLogLineTypeInvite\n\t\t\tcommand:m.command\n\t\t receivedAt:m.receivedAt];\n\t}\n\n\t[self notifyEvent:TXNotificationTypeInvite lineType:TVCLogLineTypeInvite target:nil nickname:sender text:channelName];\n\n\tif ([TPCPreferences autoJoinOnInvite]) {\n\t\t[self joinUnlistedChannel:channelName];\n\t}\n}\n\n- (void)receiveError:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSString *message = m.sequence;\n\n\tif (([message hasPrefix:@\"Closing Link:\"] && [message hasSuffix:@\"(Excess Flood)\"]) ||\n\t\t([message hasPrefix:@\"Closing Link:\"] && [message hasSuffix:@\"(Max SendQ exceeded)\"]))\n\t{\n\t\t__weak IRCClient *weakSelf = self;\n\n\t\tself.disconnectCallback = ^{\n\t\t\t[weakSelf cancelReconnect];\n\t\t};\n\t}\n\n\t[self printError:message asCommand:m.command];\n}\n\n- (void)receiveCertInfo:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] == 2);\n\n\t/* CERTINFO is not a standard command for Textual to\n\t receive which means we should be strict about what\n\t conditions we will accept it under. */\n\tif (self.zncBouncerIsSendingCertificateInfo == NO ||\n\t\tm.senderIsServer == NO ||\n\t\t[m.senderNickname isEqualToString:@\"znc.in\"] == NO)\n\t{\n\t\treturn;\n\t}\n\n\t/* The data we expect to receive should be chunk split \n\t which means it is safe to assume a maximum length. */\n\tNSString *data = m.sequence;\n\n\tif (data.length < 2 || data.length > 65) {\n\t\treturn;\n\t}\n\n\t/* Write line to the mutable buffer */\n\tif ( self.zncBouncerCertificateChainDataMutable) {\n\t\t[self.zncBouncerCertificateChainDataMutable appendFormat:@\"%@\\n\", data];\n\t}\n}\n\n- (void)receiveBatch:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] >= 1);\n\n\tNSString *batchToken = [m paramAt:0];\n\n\tif (batchToken.length <= 1) {\n\t\tLogToConsoleError(\"Cannot process BATCH command because [batchToken length] <= 1\");\n\n\t\treturn;\n\t}\n\n\tNSString *batchType = [m paramAt:1];\n\n\tBOOL isBatchOpening = NO;\n\n\tif ([batchToken hasPrefix:@\"+\"]) {\n\t\t batchToken = [batchToken substringFromIndex:1];\n\n\t\tisBatchOpening = YES;\n\t} else if ([batchToken hasPrefix:@\"-\"]) {\n\t\tbatchToken = [batchToken substringFromIndex:1];\n\n\t\tisBatchOpening = NO;\n\t} else {\n\t\tLogToConsoleError(\"Cannot process BATCH command because there was no open or close modifier\");\n\n\t\treturn;\n\t}\n\n\tif ([batchToken onlyContainsCharactersFromCharacterSet:[NSCharacterSet Ato9UnderscoreDash]] == NO) {\n\t\tLogToConsoleError(\"Cannot process BATCH command because the batch token contains illegal characters\");\n\n\t\treturn;\n\t}\n\n\tif (isBatchOpening == NO)\n\t{\n\t\t/* Find batch message matching known token */\n\t\tIRCMessageBatchMessage *thisBatchMessage = [self.batchMessages queuedEntryWithBatchToken:batchToken];\n\n\t\tif (thisBatchMessage == nil) {\n\t\t\tLogToConsoleError(\"Cannot process BATCH command because -queuedEntryWithBatchToken: returned nil\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tthisBatchMessage.batchIsOpen = NO;\n\n\t\t/* If this batch message has a parent batch, then we \n\t\t do not remove this batch or process it until the close\n\t\t statement for the parent is received. */\n\t\tif (thisBatchMessage.parentBatchMessage) {\n\t\t\treturn; // Nothing left to do...\n\t\t}\n\n\t\tbatchType = thisBatchMessage.batchType;\n\n\t\t/* Process queued entries for this batch message. */\n\t\t/* The method used for processing queued entries will \n\t\t also remove it from queue once completed. */\n\t\t[self recursivelyProcessBatchMessage:thisBatchMessage];\n\n\t\t/* Set vendor specific flags based on BATCH command values */\n\t\tif ([batchType isEqualToString:@\"znc.in/playback\"]) {\n\t\t\tself.zncBouncerIsPlayingBackHistory = NO;\n\t\t} else if ([batchType isEqualToString:@\"znc.in/tlsinfo\"]) {\n\t\t\tself.zncBouncerIsSendingCertificateInfo = NO;\n\t\t}\n\t}\n\telse // isBatchOpening == NO\n\t{\n\t\t/* Check batch= value to look for possible parent batch.*/\n\t\tIRCMessageBatchMessage *parentBatchMessage = nil;\n\n\t\tNSString *parentBatchMessageToken = m.batchToken;\n\n\t\tif (parentBatchMessageToken) {\n\t\t\tparentBatchMessage = [self.batchMessages queuedEntryWithBatchToken:parentBatchMessageToken];\n\t\t}\n\n\t\t/* Create new batch message and queue it. */\n\t\tIRCMessageBatchMessage *newBatchMessage = [IRCMessageBatchMessage new];\n\n\t\tnewBatchMessage.batchIsOpen = YES;\n\n\t\tnewBatchMessage.batchToken = batchToken;\n\t\tnewBatchMessage.batchType = batchType;\n\n\t\tnewBatchMessage.parentBatchMessage = parentBatchMessage;\n\n\t\t[self.batchMessages queueEntry:newBatchMessage];\n\n\t\t/* Set vendor specific flags based on BATCH command values */\n\t\tif ([batchType isEqualToString:@\"znc.in/playback\"]) {\n\t\t\tself.zncBouncerIsPlayingBackHistory = self.isConnectedToZNC;\n\t\t} else if ([batchType isEqualToString:@\"znc.in/tlsinfo\"]) {\n\t\t\tself.zncBouncerIsSendingCertificateInfo = self.isConnectedToZNC;\n\n\t\t\t/* If this is parent batch (there is no @batch=), then we\n\t\t\t reset the mutable object to read new data. */\n\t\t\tif (parentBatchMessageToken == nil) {\n\t\t\t\tself.zncBouncerCertificateChainDataMutable = [NSMutableString string];\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)receiveChangeHost:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] == 2);\n\n\tNSString *username = [m paramAt:0];\n\n\tif ([username isHostmaskUsernameOn:self] == NO) {\n\t\tLogToConsoleError(\"Username ('%{private}@') received from CHGHOST command is improperly formatted\", username);\n\n\t\treturn;\n\t}\n\n\tNSString *address = [m paramAt:1];\n\n\tif ([address isHostmaskAddressOn:self] == NO) {\n\t\tLogToConsoleError(\"Address ('%{private}@') received from CHGHOST command is improperly formatted\", address);\n\n\t\treturn;\n\t}\n\n\tNSString *nickname = m.senderNickname;\n\n\t[self modifyUserUserWithNickname:nickname withBlock:^(IRCUserMutable *userMutable) {\n\t\tuserMutable.username = username;\n\t\tuserMutable.address = address;\n\t}];\n}\n\n#pragma mark -\n#pragma mark BATCH Command\n\n- (id)queuedBatchMessageWithToken:(NSString *)batchToken\n{\n\treturn [self.batchMessages queuedEntryWithBatchToken:batchToken];\n}\n\n- (BOOL)filterBatchCommandIncomingData:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSString *batchToken = m.batchToken;\n\n\tif (batchToken) {\n\t\tIRCMessageBatchMessage *thisBatchMessage = [self.batchMessages queuedEntryWithBatchToken:batchToken];\n\n\t\tif (thisBatchMessage.batchIsOpen) {\n\t\t\t[thisBatchMessage queueEntry:m];\n\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n- (void)recursivelyProcessBatchMessage:(IRCMessageBatchMessage *)batchMessage\n{\n\t[self recursivelyProcessBatchMessage:batchMessage depth:0];\n}\n\n- (void)recursivelyProcessBatchMessage:(IRCMessageBatchMessage *)batchMessage depth:(NSInteger)recursionDepth\n{\n\tNSParameterAssert(batchMessage != nil);\n\n\tif (batchMessage.batchIsOpen) {\n\t\treturn;\n\t}\n\n\tNSArray *queuedEntries = batchMessage.queuedEntries;\n\n\tfor (id queuedEntry in queuedEntries) {\n\t\tif ([queuedEntry isKindOfClass:[IRCMessage class]]) {\n\t\t\t[self processIncomingMessage:queuedEntry];\n\t\t} else if ([queuedEntry isKindOfClass:[IRCMessageBatchMessage class]]) {\n\t\t\t[self recursivelyProcessBatchMessage:queuedEntry depth:(recursionDepth + 1)];\n\t\t}\n\t}\n\n\tif (recursionDepth == 0) {\n\t\t[self.batchMessages dequeueEntry:batchMessage];\n\t}\n}\n\n#pragma mark -\n#pragma mark Server Capability\n\n- (void)enableCapability:(ClientIRCv3SupportedCapability)capability\n{\n\tif ([self isCapabilityEnabled:capability] == NO) {\n\t\tself->_capabilities |= capability;\n\t}\n}\n\n- (void)disableCapability:(ClientIRCv3SupportedCapability)capability\n{\n\tif ([self isCapabilityEnabled:capability]) {\n\t\tself->_capabilities &= ~capability;\n\t}\n}\n\n- (BOOL)isCapabilityEnabled:(ClientIRCv3SupportedCapability)capability\n{\n\treturn ((self->_capabilities & capability) == capability);\n}\n\n- (void)enablePendingCapability:(ClientIRCv3SupportedCapability)capability\n{\n\t@synchronized (self.capabilitiesPending) {\n\t\t[self.capabilitiesPending addObjectWithoutDuplication:@(capability)];\n\t}\n}\n\n- (void)disablePendingCapability:(ClientIRCv3SupportedCapability)capability\n{\n\t@synchronized (self.capabilitiesPending) {\n\t\t[self.capabilitiesPending removeObject:@(capability)];\n\t}\n}\n\n- (BOOL)isPendingCapabilityEnabled:(ClientIRCv3SupportedCapability)capability\n{\n\t@synchronized (self.capabilitiesPending) {\n\t\treturn [self.capabilitiesPending containsObject:@(capability)];\n\t}\n}\n\n- (nullable NSString *)capabilityStringValue:(ClientIRCv3SupportedCapability)capability\n{\n\tNSString *stringValue = nil;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wswitch\"\n\n\tswitch (capability) {\n\t\tcase ClientIRCv3SupportedCapabilityAwayNotify:\n\t\t{\n\t\t\tstringValue = @\"away-notify\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityBatch:\n\t\t{\n\t\t\tstringValue = @\"batch\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityChangeHost:\n\t\t{\n\t\t\tstringValue = @\"chghost\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityEchoMessage:\n\t\t{\n\t\t\tstringValue = @\"echo-message\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityIdentifyCTCP:\n\t\t{\n\t\t\tstringValue = @\"identify-ctcp\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityIdentifyMsg:\n\t\t{\n\t\t\tstringValue = @\"identify-msg\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityMultiPrefix:\n\t\t{\n\t\t\tstringValue = @\"multi-prefix\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityPlayback:\n\t\t{\n\t\t\tstringValue = @\"playback\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilitySASLExternal:\n\t\tcase ClientIRCv3SupportedCapabilitySASLPlainText:\n\t\tcase ClientIRCv3SupportedCapabilitySASLGeneric:\n\t\tcase ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL:\n\t\tcase ClientIRCv3SupportedCapabilityIsInSASLNegotiation:\n\t\t{\n\t\t\tstringValue = @\"sasl\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityServerTime:\n\t\t{\n\t\t\tstringValue = @\"server-time\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityUserhostInNames:\n\t\t{\n\t\t\tstringValue = @\"userhost-in-names\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityMonitorCommand:\n\t\t{\n\t\t\tstringValue = @\"monitor-command\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityWatchCommand:\n\t\t{\n\t\t\tstringValue = @\"watch-command\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityPlanioPlayback:\n\t\t{\n\t\t\tstringValue = @\"plan.io/playback\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityZNCCertInfoModule:\n\t\t{\n\t\t\tstringValue = @\"znc.in/tlsinfo\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityZNCPlaybackModule:\n\t\t{\n\t\t\tstringValue = @\"znc.in/playback\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityZNCSelfMessage:\n\t\t{\n\t\t\tstringValue = @\"znc.in/self-message\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityZNCServerTime:\n\t\t{\n\t\t\tstringValue = @\"znc.in/server-time\";\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ClientIRCv3SupportedCapabilityZNCServerTimeISO:\n\t\t{\n\t\t\tstringValue = @\"znc.in/server-time-iso\";\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n#pragma clang diagnostic pop\n\n\treturn stringValue;\n}\n\n- (ClientIRCv3SupportedCapability)capabilityFromStringValue:(NSString *)capabilityString\n{\n\tNSParameterAssert(capabilityString != nil);\n\n\tif ([capabilityString isEqualToStringIgnoringCase:@\"away-notify\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityAwayNotify;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"batch\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityBatch;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"chghost\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityChangeHost;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"echo-message\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityEchoMessage;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"multi-prefix\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityMultiPrefix;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"identify-msg\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityIdentifyMsg;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"identify-ctcp\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityIdentifyCTCP;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"sasl\"]) {\n\t\treturn ClientIRCv3SupportedCapabilitySASLGeneric;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"server-time\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityServerTime;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"userhost-in-names\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityUserhostInNames;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"plan.io/playback\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityPlanioPlayback;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"znc.in/playback\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityZNCPlaybackModule;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"znc.in/self-message\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityZNCSelfMessage;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"znc.in/server-time\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityZNCServerTime;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"znc.in/server-time-iso\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityZNCServerTimeISO;\n\t} else if ([capabilityString isEqualToStringIgnoringCase:@\"znc.in/tlsinfo\"]) {\n\t\treturn ClientIRCv3SupportedCapabilityZNCCertInfoModule;\n\t}\n\n\treturn 0;\n}\n\n- (NSString *)enabledCapabilitiesStringValue\n{\n\tNSMutableArray *enabledCapabilities = [NSMutableArray array];\n\n\tvoid (^appendValue)(ClientIRCv3SupportedCapability) = ^(ClientIRCv3SupportedCapability capability) {\n\t\tif ([self isCapabilityEnabled:capability] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *stringValue = [self capabilityStringValue:capability];\n\n\t\tif (stringValue) {\n\t\t\t[enabledCapabilities addObject:stringValue];\n\t\t}\n\t};\n\n\tappendValue(ClientIRCv3SupportedCapabilityAwayNotify);\n\tappendValue(ClientIRCv3SupportedCapabilityBatch);\n\tappendValue(ClientIRCv3SupportedCapabilityChangeHost);\n\tappendValue(ClientIRCv3SupportedCapabilityEchoMessage);\n\tappendValue(ClientIRCv3SupportedCapabilityIdentifyCTCP);\n\tappendValue(ClientIRCv3SupportedCapabilityIdentifyMsg);\n\tappendValue(ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL);\n\tappendValue(ClientIRCv3SupportedCapabilityMultiPrefix);\n\tappendValue(ClientIRCv3SupportedCapabilityPlayback);\n\tappendValue(ClientIRCv3SupportedCapabilityServerTime);\n\tappendValue(ClientIRCv3SupportedCapabilityUserhostInNames);\n\tappendValue(ClientIRCv3SupportedCapabilityZNCCertInfoModule);\n\tappendValue(ClientIRCv3SupportedCapabilityZNCPlaybackModule);\n\tappendValue(ClientIRCv3SupportedCapabilityZNCSelfMessage);\n\n\tNSString *stringValue = [enabledCapabilities componentsJoinedByString:@\", \"];\n\n\treturn stringValue;\n}\n\n- (void)sendNextCapability\n{\n\tif (self.capabilityNegotiationIsPaused) {\n\t\treturn;\n\t}\n\n\t@synchronized (self.capabilitiesPending) {\n\t\t/* -CapabilitiesPending can contain values that are used internally for state traking \n\t\t and should never meet the socket. To workaround this as best we can, we scan the \n\t\t array for the first capability that is acceptable for negotiation. */\n\t\tNSUInteger nextCapabilityIndex =\n\t\t[self.capabilitiesPending indexOfObjectPassingTest:^BOOL(NSNumber *capabilityPending, NSUInteger index, BOOL *stop) {\n\t\t\tClientIRCv3SupportedCapability capability = capabilityPending.unsignedIntegerValue;\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wtautological-compare\"\n\n\t\t\treturn\n\t\t\t(capability == ClientIRCv3SupportedCapabilityAwayNotify\t\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityBatch\t\t\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityChangeHost\t\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityEchoMessage\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityIdentifyCTCP\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityIdentifyMsg\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityMultiPrefix\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilitySASLGeneric\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityServerTime\t\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityUserhostInNames\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityPlanioPlayback\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityZNCCertInfoModule\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityZNCPlaybackModule\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityZNCSelfMessage\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityZNCServerTime\t\t\t||\n\t\t\t capability == ClientIRCv3SupportedCapabilityZNCServerTimeISO);\n\n#pragma clang diagnostic pop\n\t\t}];\n\n\t\tif (nextCapabilityIndex == NSNotFound) {\n\t\t\t[self sendCapability:@\"END\" data:nil];\n\n\t\t\treturn;\n\t\t}\n\n\t\tClientIRCv3SupportedCapability capability =\n\t\t[self.capabilitiesPending unsignedIntegerAtIndex:nextCapabilityIndex];\n\n\t\t[self.capabilitiesPending removeObjectAtIndex:nextCapabilityIndex];\n\n\t\tNSString *stringValue = [self capabilityStringValue:capability];\n\n\t\t[self sendCapability:@\"REQ\" data:stringValue];\n\t}\n}\n\n- (void)pauseCapabilityNegotiation\n{\n\tself.capabilityNegotiationIsPaused = YES;\n}\n\n- (void)resumeCapabilityNegotiation\n{\n\tself.capabilityNegotiationIsPaused = NO;\n\n\t[self sendNextCapability];\n}\n\n- (BOOL)isCapabilitySupported:(NSString *)capabilityString\n{\n\tNSParameterAssert(capabilityString != nil);\n\n\t// Information about several of these supported CAP\n\t// extensions can be found at: http://ircv3.atheme.org\n\n\tif ([capabilityString isEqualToStringIgnoringCase:@\"echo-message\"]) {\n\t\treturn [TPCPreferences enableEchoMessageCapability];\n\t}\n\n\treturn\n\t([capabilityString isEqualToStringIgnoringCase:@\"away-notify\"]\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"batch\"]\t\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"chghost\"]\t\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"identify-ctcp\"]\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"identify-msg\"]\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"multi-prefix\"]\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"sasl\"]\t\t\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"server-time\"]\t\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"userhost-in-names\"]\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"plan.io/playback\"]\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"znc.in/playback\"]\t\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"znc.in/self-message\"]\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"znc.in/server-time\"]\t\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"znc.in/server-time-iso\"]\t||\n\t [capabilityString isEqualToStringIgnoringCase:@\"znc.in/tlsinfo\"]);\n}\n\n- (void)toggleCapability:(NSString *)capabilityString enabled:(BOOL)enabled\n{\n\t[self toggleCapability:capabilityString enabled:enabled isUpdateRequest:NO];\n}\n\n- (void)toggleCapability:(NSString *)capabilityString enabled:(BOOL)enabled isUpdateRequest:(BOOL)isUpdateRequest\n{\n\tNSParameterAssert(capabilityString != nil);\n\n\tif ([capabilityString isEqualToStringIgnoringCase:@\"sasl\"]) {\n\t\tif (enabled) {\n\t\t\tif ([self sendSASLIdentificationRequest]) {\n\t\t\t\t[self pauseCapabilityNegotiation];\n\t\t\t}\n\t\t}\n\n\t\treturn;\n\t}\n\n\tClientIRCv3SupportedCapability capability = [self capabilityFromStringValue:capabilityString];\n\n\tif (capability == 0) {\n\t\treturn;\n\t}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wtautological-compare\"\n\n\tif (capability == ClientIRCv3SupportedCapabilityZNCServerTime ||\n\t\tcapability == ClientIRCv3SupportedCapabilityZNCServerTimeISO)\n\t{\n\t\tcapability = ClientIRCv3SupportedCapabilityServerTime;\n\t}\n\n\tif (capability == ClientIRCv3SupportedCapabilityPlanioPlayback ||\n\t\tcapability == ClientIRCv3SupportedCapabilityZNCPlaybackModule)\n\t{\n\t\tcapability = ClientIRCv3SupportedCapabilityPlayback;\n\t}\n\n#pragma clang diagnostic pop\n\n\tif (enabled) {\n\t\t[self enableCapability:capability];\n\t} else {\n\t\t[self disableCapability:capability];\n\t}\n}\n\n- (void)processPendingCapability:(NSString *)capabilityString\n{\n\tNSParameterAssert(capabilityString != nil);\n\n\tNSArray *components = [capabilityString componentsSeparatedByString:@\"=\"];\n\n\tNSString *capability = capabilityString;\n\n\tNSArray<NSString *> *capabilityOptions = nil;\n\n\tif (components.count == 2) {\n\t\tcapability = components[0];\n\n\t\tcapabilityOptions = [components[1] componentsSeparatedByString:@\",\"];\n\t}\n\n\t[self processPendingCapability:capability options:capabilityOptions];\n}\n\n- (void)processPendingCapability:(NSString *)capabilityString options:(nullable NSArray<NSString *> *)capabilityOptions\n{\n\tNSParameterAssert(capabilityString != nil);\n\n\tif ([self isCapabilitySupported:capabilityString] == NO) {\n\t\treturn;\n\t}\n\n\tif ([capabilityString isEqualToString:@\"sasl\"]) {\n\t\t[self processPendingCapabilityForSASL:capabilityOptions];\n\n\t\treturn;\n\t}\n\n\tClientIRCv3SupportedCapability capability = [self capabilityFromStringValue:capabilityString];\n\n\t[self enablePendingCapability:capability];\n}\n\n- (void)receiveCapabilityOrAuthenticationRequest:(IRCMessage *)m\n{\n\t/* Implementation based off Colloquy's own. */\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 0);\n\n\tNSString *command = m.command;\n\tNSString *modifier = [m paramAt:0];\n\tNSString *subcommand = [m paramAt:1];\n\tNSString *actions = [m sequence:2];\n\n\tif ([command isEqualToStringIgnoringCase:@\"CAP\"])\n\t{\n\t\tif ([subcommand isEqualToStringIgnoringCase:@\"LS\"]) {\n\t\t\tNSArray *caps = [actions componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *cap in caps) {\n\t\t\t\t[self processPendingCapability:cap];\n\t\t\t}\n\t\t} else if ([subcommand isEqualToStringIgnoringCase:@\"ACK\"]) {\n\t\t\tNSArray *caps = [actions componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *cap in caps) {\n\t\t\t\t[self toggleCapability:cap enabled:YES isUpdateRequest:NO];\n\t\t\t}\n\t\t} else if ([subcommand isEqualToStringIgnoringCase:@\"NAK\"]) {\n\t\t\tNSArray *caps = [actions componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *cap in caps) {\n\t\t\t\t[self toggleCapability:cap enabled:NO isUpdateRequest:NO];\n\t\t\t}\n\t\t} else if ([subcommand isEqualToStringIgnoringCase:@\"NEW\"]) {\n\t\t\tNSArray *caps = [actions componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *cap in caps) {\n\t\t\t\t[self processPendingCapability:cap];\n\t\t\t}\n\t\t} else if ([subcommand isEqualToStringIgnoringCase:@\"DEL\"]) {\n\t\t\tNSArray *caps = [actions componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *cap in caps) {\n\t\t\t\t[self toggleCapability:cap enabled:NO isUpdateRequest:YES];\n\t\t\t}\n\t\t}\n\n\t\t[self sendNextCapability];\n\t}\n\telse if ([command isEqualToStringIgnoringCase:@\"AUTHENTICATE\"])\n\t{\n\t\tif ([modifier isEqualToString:@\"+\"]) {\n\t\t\t[self sendSASLIdentificationInformation];\n\t\t}\n\t}\n\n\t[self postReceivedMessage:m];\n}\n\n#pragma mark -\n#pragma mark SASL Negotiation\n\n- (void)processPendingCapabilityForSASL:(nullable NSArray<NSString *> *)capabilityOptions\n{\n\tClientIRCv3SupportedCapability identificationMechanism = 0;\n\n\tif (self.socket.isConnectedWithClientSideCertificate &&\n\t\tself.config.saslAuthenticationDisableExternalMechanism == NO)\n\t{\n\t\tif (capabilityOptions.count == 0 ||\n\t\t\t[capabilityOptions containsObjectIgnoringCase:@\"EXTERNAL\"])\n\t\t{\n\t\t\tidentificationMechanism = ClientIRCv3SupportedCapabilitySASLExternal;\n\n\t\t\t[self enablePendingCapability:ClientIRCv3SupportedCapabilitySASLExternal];\n\t\t}\n\t}\n\n\tif (identificationMechanism == 0 &&\n\t\tself.config.nicknamePassword.length > 0)\n\t{\n\t\tif (capabilityOptions.count == 0 ||\n\t\t\t[capabilityOptions containsObjectIgnoringCase:@\"PLAIN\"])\n\t\t{\n\t\t\tidentificationMechanism = ClientIRCv3SupportedCapabilitySASLPlainText;\n\n\t\t\t[self enablePendingCapability:ClientIRCv3SupportedCapabilitySASLPlainText];\n\t\t}\n\t}\n\n\tif (identificationMechanism != 0) {\n\t\t[self enablePendingCapability:ClientIRCv3SupportedCapabilitySASLGeneric];\n\t}\n}\n\n- (void)sendSASLIdentificationInformation\n{\n\tif ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilityIsInSASLNegotiation] == NO) {\n\t\treturn;\n\t}\n\n\tif ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilitySASLPlainText])\n\t{\n\t\tNSString *authString = [NSString stringWithFormat:@\"%@%C%@%C%@\",\n\t\t\t\t\t\t\t\t self.config.username, 0x00,\n\t\t\t\t\t\t\t\t self.config.username, 0x00,\n\t\t\t\t\t\t\t\t self.config.nicknamePassword];\n\n\t\tNSArray *authStrings = [authString base64EncodingWithLineLength:400];\n\n\t\tfor (NSString *string in authStrings) {\n\t\t\t[self sendCapabilityAuthenticate:string];\n\t\t}\n\n\t\tif (authStrings.count == 0 || ((NSString *)authStrings.lastObject).length == 400) {\n\t\t\t[self sendCapabilityAuthenticate:@\"+\"];\n\t\t}\n\t}\n\telse if ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilitySASLExternal])\n\t{\n\t\t[self sendCapabilityAuthenticate:@\"+\"];\n\t}\n}\n\n- (BOOL)sendSASLIdentificationRequest\n{\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL]) {\n\t\treturn NO;\n\t}\n\n\tif ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilityIsInSASLNegotiation]) {\n\t\treturn NO;\n\t}\n\n\t[self enablePendingCapability:ClientIRCv3SupportedCapabilityIsInSASLNegotiation];\n\n\tif ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilitySASLPlainText]) {\n\t\t[self sendCapabilityAuthenticate:@\"PLAIN\"];\n\n\t\treturn YES;\n\t} else if ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilitySASLExternal]) {\n\t\t[self sendCapabilityAuthenticate:@\"EXTERNAL\"];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)resetSASLNegotiation\n{\n\t[self disablePendingCapability:ClientIRCv3SupportedCapabilitySASLGeneric];\n\t[self disablePendingCapability:ClientIRCv3SupportedCapabilitySASLPlainText];\n\t[self disablePendingCapability:ClientIRCv3SupportedCapabilitySASLExternal];\n\t[self disablePendingCapability:ClientIRCv3SupportedCapabilityIsInSASLNegotiation];\n\n\t[self disableCapability:ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL];\n}\n\n#pragma mark -\n#pragma mark Protocol Handlers\n\n- (void)receivePing:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSAssertReturn([m paramsCount] > 0);\n\n\tNSString *token = [m sequence:0];\n\n\t[self sendPong:token];\n\n\t[self postReceivedMessage:m];\n}\n\n- (void)receiveAwayNotifyCapability:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityAwayNotify] == NO) {\n\t\treturn;\n\t}\n\n\tBOOL away = (m.sequence.length > 0);\n\n\tNSString *nickname = m.senderNickname;\n\n\t[self modifyUserWithNickname:nickname asAway:away];\n}\n\n- (void)receiveInit:(IRCMessage *)m // Raw numeric = 001\n{\n\tNSParameterAssert(m != nil);\n\n\t/* Manage timers */\n\t[self startPongTimer];\n\n\t[self stopRetryTimer];\n\n\t/* Manage properties */\n\tself.isLoggedIn = YES;\n\n\tself.supportInfo.serverAddress = m.senderHostmask;\n\n\tself.invokingISONCommandForFirstTime = YES;\n\n\tself.reconnectEnabledBecauseOfSleepMode = NO;\n\n\tself.tryingNicknameSentNickname = nil;\n\n\tself.userNickname = [m paramAt:0];\n\n\tself.successfulConnects += 1;\n\n\t/* Begin enforcing flood control */\n\t[self.socket enforceFloodControl];\n\n\t/* Post event */\n\t[self postEventToViewController:@\"serverConnected\"];\n\n\t[self notifyEvent:TXNotificationTypeConnect lineType:TVCLogLineTypeDebug];\n\n\t/* Perform login commands */\n\tfor (__strong NSString *command in self.config.loginCommands) {\n\t\tif ([command hasPrefix:@\"/\"]) {\n\t\t\tcommand = [command substringFromIndex:1];\n\t\t}\n\n\t\t[self sendCommand:command completeTarget:NO target:nil];\n\t}\n\n\t/* Request certificate information */\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityZNCCertInfoModule]) {\n\t\t[self sendCommand:@\"send-data\" toZNCModuleNamed:@\"tlsinfo\"];\n\t}\n\n\t/* Request playback since the last seen message when previously connected */\n\t[self requestPlayback];\n\n\t/* Activate existing queries */\n\tfor (IRCChannel *c in self.channelList) {\n\t\tif (c.privateMessage) {\n\t\t\t[c activate];\n\n\t\t\t[mainWindow() reloadTreeItem:c];\n\t\t}\n\t}\n\n\t[mainWindow() reloadTreeItem:self];\n\n\t[mainWindow() updateTitleFor:self];\n\n\t[mainWindowTextField() updateSegmentedController];\n\n\t/* Everything else */\n\tif (self.config.autojoinWaitsForNickServ == NO || [self isCapabilityEnabled:ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL]) {\n\t\t[self performAutoJoin];\n\t} else {\n\t\t/* If we wait for NickServ we set a timer of 3.0 seconds before performing auto join.\n\t\t When this timer is executed, if we do not have any knowledge of NickServ existing\n\t\t on the current server, then we perform the autojoin. This is primarily a fix for the\n\t\t ZNC SASL module which will complete identification before connecting and once connected\n\t\t Textual will have no knowledge of whether the local user is identified or not. */\n\t\t/* NickServ will send a notice asking for identification as soon as connection occurs so\n\t\t this is the best patch. At least for right now. */\n\n\t\tif (self.isConnectedToZNC) {\n\t\t\t[self performSelectorInCommonModes:@selector(performAutoJoin) withObject:nil afterDelay:3.0];\n\t\t} else {\n\t\t\t[self startAutojoinDelayedWarningTimer];\n\t\t}\n\t}\n\n\t/* We need time for the server to send its configuration */\n\t[self performSelectorInCommonModes:@selector(populateISONTrackedUsersList) withObject:nil afterDelay:10.0];\n}\n\n- (void)receiveNumericReply:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSInteger numeric = m.commandNumeric;\n\n\tif (numeric > 400 && numeric < 597 && numeric != ERR_NOMOTD) {\n\t\t[self receiveErrorNumericReply:m];\n\n\t\treturn;\n\t}\n\n\tBOOL printMessage = YES;\n\n\t/* These numerics are treated differently below which is why the exception exists.\n\t For example, for channel topic, only the contents of the topic are sent to the filter. */\n\tif (numeric != RPL_UMODEIS &&\n\t\tnumeric != RPL_CHANNELMODEIS &&\n\t\tnumeric != RPL_TOPIC &&\n\t\tnumeric != RPL_TOPICWHOTIME)\n\t{\n\t\tprintMessage = [self postReceivedMessage:m];\n\t}\n\n\tswitch (numeric) {\n\t\tcase RPL_WELCOME:\n\t\t{\n\t\t\t[self receiveInit:m];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_YOURHOST:\n\t\tcase RPL_CREATED:\n\t\tcase RPL_MYINFO:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ISUPPORT:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] >= 3);\n\n\t\t\tNSMutableArray *params = [m.params mutableCopy];\n\n\t\t\t[params removeObjectAtIndex:0]; // Remove nickname\n\n\t\t\tNSString *message = params.lastObject;\n\n\t\t\t[params removeLastObject]; // Remove \"are supported by this server\"\n\n\t\t\tNSString *configuration = [params componentsJoinedByString:@\" \"];\n\n\t\t\t[self.supportInfo processConfigurationData:configuration];\n\n\t\t\tif (printMessage) {\n\t\t\t\tNSString *configurationFormatted = self.supportInfo.stringValueForLastUpdate;\n\n\t\t\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[u51-nn]\", configurationFormatted, message)\n\t\t\t\t\t\t\t\t\t\t   asCommand:m.command];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_REDIR:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\tNSString *serverAddress = [m paramAt:1];\n\t\t\tNSString *serverPort = [m paramAt:2];\n\n\t\t\tself.disconnectType = IRCClientDisconnectModeServerRedirect;\n\n\t\t\t/* If the address is thought to be invalid, then we still\n\t\t\t perform the disconnect suggested by the redirect, but\n\t\t\t we do not go any further than that. */\n\t\t\tif (serverAddress.validInternetAddress == NO ||\n\t\t\t\tserverPort.validInternetPort == NO)\n\t\t\t{\n\t\t\t\t[self disconnect];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Perform reconnect to specified locations */\n\t\t\t__weak IRCClient *weakSelf = self;\n\n\t\t\tself.disconnectCallback = ^{\n\t\t\t\t[weakSelf connect];\n\t\t\t};\n\n\t\t\t[self disconnect];\n\n\t\t\t/* -disconnect would destroy this so we set them after... */\n\t\t\tself.temporaryServerAddressOverride = serverAddress;\n\t\t\tself.temporaryServerPortOverride = serverPort.integerValue;\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_STATSCONN:\n\t\tcase RPL_LUSERCLIENT:\n\t\tcase RPL_LUSERHOP:\n\t\tcase RPL_LUSERUNKNOWN:\n\t\tcase RPL_LUSERCHANNELS:\n\t\tcase RPL_LUSERME:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LOCALUSERS:\n\t\tcase RPL_GLOBALUSERS:\n\t\t{\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *message = nil;\n\n\t\t\tif (m.paramsCount == 4) {\n\t\t\t\t/* Removes user count from in front of messages on IRCds that send them.\n\t\t\t\t Example: \">> :irc.example.com 265 Guest 2 3 :Current local users 2, max 3\" */\n\n\t\t\t\tmessage = [m sequence:3];\n\t\t\t} else {\n\t\t\t\tmessage = m.sequence;\n\t\t\t}\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:nil\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_MOTD:\n\t\tcase RPL_MOTDSTART:\n\t\tcase RPL_ENDOFMOTD:\n\t\tcase ERR_NOMOTD:\n\t\t{\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tif ([TPCPreferences displayServerMOTD] == NO) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (numeric == ERR_NOMOTD) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t} else {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_UMODEIS:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 1);\n\n\t\t\tNSString *nickname = [m paramAt:0];\n\n\t\t\tNSString *modeString = [m paramAt:1];\n\n\t\t\tif ([modeString isEqualToString:@\"+\"]) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintMessage = [self postReceivedMessage:m withText:modeString destinedFor:nil];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:TXTLS(@\"IRC[ipj-34]\", nickname, modeString)\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:nil\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_AWAY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSString *awayNickname = [m paramAt:1];\n\t\t\tNSString *awayComment = [m paramAt:2];\n\n\t\t\tIRCChannel *channel = [self findChannel:awayNickname];\n\n\t\t\tNSString *message = TXTLS(@\"IRC[c1h-fq]\", awayNickname, awayComment);\n\n\t\t\tif (channel == nil) {\n\t\t\t\tchannel = [mainWindow() selectedChannelOn:self];\n\t\t\t}\n\n\t\t\tIRCUser *user = [self findUser:awayNickname];\n\n\t\t\tif ( user) {\n\t\t\t\tif (self.monitorAwayStatus) {\n\t\t\t\t\t[user markAsAway];\n\t\t\t\t}\n\n\t\t\t\tif (user.presentAwayMessageFor301 == NO) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:message\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:channel\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_UNAWAY:\n\t\tcase RPL_NOWAWAY:\n\t\t{\n\t\t\tBOOL away = (numeric == RPL_NOWAWAY);\n\n\t\t\tself.userIsAway = away;\n\t\t\t\n\t\t\t[mainWindow() updateTitle];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\t/* Update our own status. This has to only be done with away-notify CAP enabled.\n\t\t\t Old, WHO based information requests will still show our own status. */\n\t\t\tIRCUser *myself = self.myself;\n\n\t\t\tif (myself == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self modifyUser:myself asAway:away];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_CHANNELSMSG:\n\t\tcase RPL_WHOISBOT:\n\t\tcase RPL_WHOISHELPOP:\n\t\tcase RPL_WHOISHOST:\n\t\tcase RPL_WHOISMODES:\n\t\tcase RPL_WHOISOPERATOR:\n\t\tcase RPL_WHOISREALIP:\n\t\tcase RPL_WHOISREGNICK:\n\t\tcase RPL_WHOISSECURE:\n\t\tcase RPL_WHOISSPECIAL:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 2);\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m inChannel:[mainWindow() selectedChannelOn:self]];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISACTUALLY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 5);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *hostmask = [m paramAt:2];\n\t\t\tNSString *ipAddress = [m paramAt:3];\n\n\t\t\tNSString *message = nil;\n\n\t\t\tif (self.inWhowasResponse) { // bahamut sends RPL_WHOISACTUALLY in WHOWAS\n\t\t\t\tmessage = TXTLS(@\"IRC[x69-rz]\", nickname, hostmask, ipAddress);\n\t\t\t} else {\n\t\t\t\tmessage = TXTLS(@\"IRC[3oa-mv]\", nickname, hostmask, ipAddress);\n\t\t\t}\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISUSER:\n\t\tcase RPL_WHOWASUSER:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] >= 6);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *username = [m paramAt:2];\n\t\t\tNSString *address = [m paramAt:3];\n\t\t\tNSString *realName = [m paramAt:5];\n\n\t\t\tif ([realName hasPrefix:@\":\"]) {\n\t\t\t\trealName = [realName substringFromIndex:1];\n\t\t\t}\n\n\t\t\tself.inWhoisResponse = (numeric == RPL_WHOISUSER);\n\t\t\tself.inWhowasResponse = (numeric == RPL_WHOWASUSER);\n\n\t\t\tNSString *message = nil;\n\n\t\t\tif (self.inWhowasResponse) {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\tmessage = TXTLS(@\"IRC[32c-87]\", nickname, username, address, realName);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\tmessage = TXTLS(@\"IRC[plg-lr]\", nickname, username, address, realName);\n\t\t\t\t}\n\n\t\t\t\t/* Update local cache of our hostmask */\n\t\t\t\tif ([self nicknameIsMyself:nickname]) {\n\t\t\t\t\tNSString *hostmask = [NSString stringWithFormat:@\"%@!%@@%@\", nickname, username, address];\n\n\t\t\t\t\tself.userHostmask = hostmask;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (message) {\n\t\t\t\t[self print:message\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISSERVER:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *serverAddress = [m paramAt:2];\n\t\t\tNSString *serverInfo = [m paramAt:3];\n\n\t\t\tNSString *message = nil;\n\n\t\t\tif (self.inWhowasResponse) { // bahamut sends RPL_WHOISSERVER in WHOWAS\n\t\t\t\tNSString *timeInfo = TXFormatDateLongStyle(serverInfo, YES);\n\n\t\t\t\tif (timeInfo == nil) {\n\t\t\t\t\ttimeInfo = serverInfo;\n\t\t\t\t}\n\n\t\t\t\tmessage = TXTLS(@\"IRC[cdu-ed]\", nickname, serverAddress, timeInfo);\n\t\t\t} else {\n\t\t\t\tmessage = TXTLS(@\"IRC[h19-n2]\", nickname, serverAddress, serverInfo);\n\t\t\t}\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISIDLE:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 5);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *idleTime = [m paramAt:2];\n\t\t\tNSString *connectTime = [m paramAt:3];\n\n\t\t\tidleTime = TXHumanReadableTimeInterval(idleTime.doubleValue, NO, 0);\n\n\t\t\tNSDate *connTimeDate = [NSDate dateWithTimeIntervalSince1970:connectTime.doubleValue];\n\n\t\t\tconnectTime = TXFormatDateLongStyle(connTimeDate, YES);\n\n\t\t\tNSString *message = TXTLS(@\"IRC[6hn-o6]\", nickname, connectTime, idleTime);\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISCHANNELS:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *channels = [m paramAt:2];\n\n\t\t\tNSString *message = TXTLS(@\"IRC[onk-l5]\", nickname, channels);\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOISACCOUNT:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *message = [NSString stringWithFormat:@\"%@ %@ %@\", [m paramAt:1], [m sequence:3], [m paramAt:2]];\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:[mainWindow() selectedChannelOn:self]\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFWHOIS:\n\t\t{\n\t\t\tself.inWhoisResponse = NO;\n\n/*\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m inChannel:[mainWindow() selectedChannelOn:self]];\n\t\t\t} */\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFWHOWAS:\n\t\t{\n\t\t\tself.inWhowasResponse = NO;\n\n/*\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m inChannel:[mainWindow() selectedChannelOn:self]];\n\t\t\t} */\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_CHANNELMODEIS:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 2);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tNSString *modeString = [m sequence:2];\n\n\t\t\tif ([modeString isEqualToString:@\"+\"]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (channel.isActive) {\n\t\t\t\t[channel.modeInfo clear];\n\n\t\t\t\t[channel.modeInfo updateModes:modeString];\n\t\t\t}\n\n\t\t\tprintMessage = [self postReceivedMessage:m withText:modeString destinedFor:channel];\n\n\t\t\t/* We perform this check after printMessage is defined so that\n\t\t\t filters have a chance to act on the input. */\n\t\t\t/* IRCClient perform mode requests for channels without the user\n\t\t\t asking for it so we must check that here. */\n\t\t\tif (channel.channelModesReceived == NO) {\n\t\t\t\tchannel.channelModesReceived = YES;\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\tNSString *message = channel.modeInfo.stringWithMaskedPassword;\n\n\t\t\t\t[self print:TXTLS(@\"IRC[obp-ww]\", message)\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:channel\n\t\t\t\t\t asType:TVCLogLineTypeMode\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_TOPIC:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\t\t\tNSString *topic = [m paramAt:2];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintMessage = [self postReceivedMessage:m withText:topic destinedFor:channel];\n\n\t\t\tchannel.topic = topic;\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:TXTLS(@\"IRC[7nm-7v]\", topic)\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:channel\n\t\t\t\t\t asType:TVCLogLineTypeTopic\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_TOPICWHOTIME:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tprintMessage = [self postReceivedMessage:m withText:nil destinedFor:channel];\n\n\t\t\tif (printMessage == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSString *topicSetter = [m paramAt:2];\n\t\t\tNSString *setTime = [m paramAt:3];\n\n\t\t\ttopicSetter = topicSetter.nicknameFromHostmask;\n\n\t\t\tNSDate *setTimeDate = [NSDate dateWithTimeIntervalSince1970:setTime.doubleValue];\n\n\t\t\tsetTime = TXFormatDateLongStyle(setTimeDate, YES);\n\n\t\t\tNSString *message = TXTLS(@\"IRC[y7s-3e]\", topicSetter, setTime);\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:channel\n\t\t\t\t asType:TVCLogLineTypeTopic\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_CREATIONTIME:\n\t\t{\n\t\t\tbreak; // Ignore\n\t\t}\n\t\tcase RPL_INVITING:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *channelName = [m paramAt:2];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self print:TXTLS(@\"IRC[wk4-rv]\", nickname, channelName)\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:channel\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ISON:\n\t\t{\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tBOOL visibleIsonRequest = self.requestedCommands.visibleIsonRequest;\n\n\t\t\t[self.requestedCommands recordIsonRequestClosed];\n\n\t\t\tif (visibleIsonRequest) {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t\t}\n\n\t\t\t\t/* It is important that we don't process logic for visible\n\t\t\t\t requests because if user does ISON for people that aren't\n\t\t\t\t on the tracked list and the logic below sees the response\n\t\t\t\t missing those, then it will think everyone tracked went offline. */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* If the ISON records were not requested by the user, then\n\t\t\t treat the results as user tracking information. */\n\t\t\tNSString *onlineNicknamesString = m.sequence;\n\n\t\t\tNSArray *onlineNicknames = [onlineNicknamesString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\t/* Start going over the list of tracked nicknames */\n\t\t\tNSDictionary *trackedUsers = self.trackedUsers.trackedUsers;\n\n\t\t\t[trackedUsers enumerateKeysAndObjectsUsingBlock:^(NSString *trackedUser, NSNumber *trackingStatusInt, BOOL *stop) {\n\t\t\t\tIRCAddressBookUserTrackingStatus trackingStatus =\n\t\t\t\tIRCAddressBookUserTrackingStatusUnknown;\n\n\t\t\t\t/* Was the user on during the last check? */\n\t\t\t\tBOOL ison = trackingStatusInt.boolValue;\n\n\t\t\t\tif (ison) {\n\t\t\t\t\t/* If the user was on before, but is not in the list of ISON\n\t\t\t\t\t users in this reply, then they are considered gone. Log that. */\n\t\t\t\t\tif ([onlineNicknames containsObjectIgnoringCase:trackedUser] == NO) {\n\t\t\t\t\t\tif (self.invokingISONCommandForFirstTime == NO) {\n\t\t\t\t\t\t\ttrackingStatus = IRCAddressBookUserTrackingStatusSignedOff;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t/* If they were not on but now are, then log that too. */\n\t\t\t\t\tif ([onlineNicknames containsObjectIgnoringCase:trackedUser]) {\n\t\t\t\t\t\tif (self.invokingISONCommandForFirstTime) {\n\t\t\t\t\t\t\ttrackingStatus = IRCAddressBookUserTrackingStatusAvailable;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttrackingStatus = IRCAddressBookUserTrackingStatusSignedOn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* If something changed (non-nil localization string), then scan \n\t\t\t\t the list of address book entries to report the result. */\n\t\t\t\tif (trackingStatus != IRCAddressBookUserTrackingStatusUnknown) {\n\t\t\t\t\t[self statusOfTrackedNickname:trackedUser changedTo:trackingStatus notify:YES];\n\t\t\t\t}\n\t\t\t}]; // for\n\n\t\t\tif (self.invokingISONCommandForFirstTime) { // Reset internal property\n\t\t\t\tself.invokingISONCommandForFirstTime = NO;\n\t\t\t}\n\n\t\t\t/* Update private messages */\n\t\t\tfor (IRCChannel *channel in self.channelList) {\n\t\t\t\tif (channel.privateMessage == NO) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (channel.isActive) {\n\t\t\t\t\t/* If the user is no longer on, deactivate the private message */\n\t\t\t\t\tif ([onlineNicknames containsObjectIgnoringCase:channel.name] == NO) {\n\t\t\t\t\t\t[channel deactivate];\n\n\t\t\t\t\t\t[mainWindow() reloadTreeItem:channel];\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t/* Activate the private message if the user is back online */\n\t\t\t\t\tif ([onlineNicknames containsObjectIgnoringCase:channel.name]) {\n\t\t\t\t\t\t[channel activate];\n\n\t\t\t\t\t\t[mainWindow() reloadTreeItem:channel];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WHOREPLY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 6);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (self.requestedCommands.visibleWhoRequest) {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t\t}\n\n\t\t\t\t/* We could remove this and be fine, but it's a lot\n\t\t\t\t over overhead to process WHO responses so let's just\n\t\t\t\t wait until the next automated one. */\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t/* Example incoming data:\n\t\t\t\t<channel> <user> <host> <server> <nick> <H|G>[*][@|+] <hopcount> <real name>\n\n\t\t\t\t#freenode znc unaffiliated/namikaze kornbluth.freenode.net Namikaze G 0 Christian\n\t\t\t\t#freenode ~D unaffiliated/solprefixer kornbluth.freenode.net solprefixer H 0 solprefixer\n\t\t\t*/\n\n\t\t\tNSString *nickname = [m paramAt:5];\n\t\t\tNSString *username = [m paramAt:2];\n\t\t\tNSString *address = [m paramAt:3];\n\t\t\tNSString *flags = [m paramAt:6];\n\t\t\tNSString *realName = [m paramAt:7];\n\n\t\t\tBOOL isAway = NO;\n\t\t\tBOOL isIRCop = NO;\n\n\t\t\t// Field Syntax: <H|G>[*][@|+]\n\t\t\t// Strip G or H (away status).\n\t\t\tNSMutableString *userModes = [NSMutableString string];\n\n\t\t\tfor (NSUInteger i = 0; i < flags.length; i++) {\n\t\t\t\tNSString *character = [flags stringCharacterAtIndex:i];\n\n\t\t\t\tif ([character isEqualToString:@\"G\"]) {\n\t\t\t\t\tisAway = self.monitorAwayStatus;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t} else if ([character isEqualToString:@\"*\"]) {\n\t\t\t\t\tisIRCop = YES;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tNSString *modeSymbol = [self.supportInfo modeSymbolForUserPrefix:character];\n\n\t\t\t\tif (modeSymbol == nil) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t[userModes appendString:modeSymbol];\n\t\t\t}\n\n\t\t\t/* Parameter 7 includes the hop count and real name because it begins with a :\n\t\t\t Therefore, we cut after the first space to get the real, real name value. */\n\t\t\tNSInteger realNameFirstSpace = [realName stringPosition:@\" \"];\n\n\t\t\tif (realNameFirstSpace > 0 && realNameFirstSpace < realName.length) {\n\t\t\t\trealName = [realName substringAfterIndex:realNameFirstSpace];\n\t\t\t}\n\n\t\t\t/* Find global user and create mutable copy */\n\t\t\tIRCUser *user = [self findUser:nickname];\n\n\t\t\tIRCUserMutable *userMutable = nil;\n\n\t\t\tif (user == nil) {\n\t\t\t\tuserMutable = [[IRCUserMutable alloc] initWithNickname:nickname onClient:self];\n\t\t\t} else {\n\t\t\t\tuserMutable = [user mutableCopy];\n\t\t\t}\n\n\t\t\tuserMutable.nickname = nickname;\n\t\t\tuserMutable.username = username;\n\t\t\tuserMutable.address = address;\n\n\t\t\tuserMutable.isAway = isAway;\n\t\t\tuserMutable.isIRCop = isIRCop;\n\n\t\t\tuserMutable.realName = realName;\n\n\t\t\t/* Insert the user into the client and return the final copy that was */\n\t\t\tBOOL userChanged = (user != nil && [user isEqual:userMutable] == NO);\n\n\t\t\tIRCUser *userAdded = nil;\n\n\t\t\tif (user == nil || userChanged) {\n\t\t\t\tuserAdded = [self addUserAndReturn:userMutable];\n\t\t\t} else {\n\t\t\t\tuserAdded = user;\n\t\t\t}\n\n\t\t\t/* Find the user associated with this channel  */\n\t\t\tIRCChannelUser *member = [user userAssociatedWithChannel:channel];\n\n\t\t\tif (member == nil)\n\t\t\t{\n\t\t\t\tIRCChannelUserMutable *memberMutable = [[IRCChannelUserMutable alloc] initWithUser:userAdded];\n\n\t\t\t\tmemberMutable.modes = userModes;\n\n\t\t\t\t[channel addMember:memberMutable];\n\t\t\t}\n\t\t\telse if (userChanged)\n\t\t\t{\n\t\t\t\t/* Determine whether the users were modified in such a way that\n\t\t\t\t they require their cell in the user list be resorted. */\n\t\t\t\t/* We do not want to resort unless absolutely necessary because\n\t\t\t\t sorting a channel with a few hundred users has overhead. */\n\t\t\t\tBOOL IRCopStatusChanged = (user.isIRCop != userAdded.isIRCop);\n\t\t\t\t\n\t\t\t\tBOOL resortMember = IRCopStatusChanged;\n\n\t\t\t\tBOOL replaceInAllChannels = (IRCopStatusChanged && [TPCPreferences memberListSortFavorsServerStaff]);\n\n\t\t\t\tif (resortMember) {\n\t\t\t\t\t[channel replaceMember:member\n\t\t\t\t\t\t\t\twithMember:member\n\t\t\t\t\t\t\t\t\tresort:resortMember\n\t\t\t\t\t  replaceInAllChannels:replaceInAllChannels];\n\t\t\t\t}\n\t\t\t\telse if (user.isAway != userAdded.isAway)\n\t\t\t\t{\n\t\t\t\t\t[mainWindow() updateDrawingForUserInUserList:userAdded];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Update local cache of our hostmask */\n\t\t\tif ([self nicknameIsMyself:nickname]) {\n\t\t\t\tNSString *hostmask = [NSString stringWithFormat:@\"%@!%@@%@\", nickname, username, address];\n\n\t\t\t\tself.userHostmask = hostmask;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFWHO:\n\t\t{\n\t\t\tBOOL visibleWhoRequest = self.requestedCommands.visibleWhoRequest;\n\n\t\t\t[self.requestedCommands recordWhoRequestClosed];\n\n\t\t\tif (visibleWhoRequest && printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_NAMEREPLY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 3);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *channelName = [m paramAt:2];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil || channel.channelNamesReceived) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tNSString *nicknamesString = [m paramAt:3];\n\n\t\t\tNSArray *nicknames = [nicknamesString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tfor (NSString *nickname in nicknames) {\n\t\t\t\tif (nickname.length == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t/* Find first character that is not a user mode */\n\t\t\t\tNSMutableString *memberModes = [NSMutableString string];\n\n\t\t\t\tNSUInteger characterIndex = 0;\n\n\t\t\t\tfor (characterIndex = 0; characterIndex < nickname.length; characterIndex++) {\n\t\t\t\t\tNSString *prefix = [nickname stringCharacterAtIndex:characterIndex];\n\n\t\t\t\t\tNSString *modeSymbol = [self.supportInfo modeSymbolForUserPrefix:prefix];\n\n\t\t\t\t\tif (modeSymbol == nil) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\t[memberModes appendString:modeSymbol];\n\t\t\t\t} // for\n\n\t\t\t\t/* Split away hostmask if available */\n\t\t\t\tNSString *newNickname = [nickname substringFromIndex:characterIndex];\n\n\t\t\t\tNSString *nicknameInt = nil;\n\t\t\t\tNSString *usernameInt = nil;\n\t\t\t\tNSString *addressInt = nil;\n\n\t\t\t\tif ([newNickname hostmaskComponents:&nicknameInt username:&usernameInt address:&addressInt onClient:self] == NO) {\n\t\t\t\t\t/* When NAMES reply is not a host, then set the nicknameInt\n\t\t\t\t\t to the value of nickname and leave the rest as nil. */\n\n\t\t\t\t\tnicknameInt = newNickname;\n\t\t\t\t}\n\n\t\t\t\t/* Find global user */\n\t\t\t\t/* An instance of IRCUser may already exist from a NAMES\n\t\t\t\t reply for another channel. If one already exist, then\n\t\t\t\t we don't make an effort to change it's credentials. */\n\t\t\t\tIRCUser *userAdded = nil;\n\n\t\t\t\tIRCUser *user = [self findUser:nicknameInt];\n\n\t\t\t\tif (user == nil) {\n\t\t\t\t\tIRCUserMutable *userMutable = [[IRCUserMutable alloc] initWithNickname:nicknameInt onClient:self];\n\n\t\t\t\t\tuserMutable.nickname = nicknameInt;\n\t\t\t\t\tuserMutable.username = usernameInt;\n\t\t\t\t\tuserMutable.address = addressInt;\n\n\t\t\t\t\tuserAdded = [self addUserAndReturn:userMutable];\n\t\t\t\t} else {\n\t\t\t\t\tuserAdded = user;\n\t\t\t\t}\n\n\t\t\t\t/* Find channel user */\n\t\t\t\tIRCChannelUser *member = [userAdded userAssociatedWithChannel:channel];\n\n\t\t\t\tIRCChannelUserMutable *memberMutable = nil;\n\n\t\t\t\tif (member == nil) {\n\t\t\t\t\tmemberMutable = [[IRCChannelUserMutable alloc] initWithUser:userAdded];\n\t\t\t\t} else if ([self nicknameIsMyself:nicknameInt]) {\n\t\t\t\t\tmemberMutable = [member mutableCopy];\n\t\t\t\t} else {\n\t\t\t\t\t/* If a user with this name already exists in the channel,\n\t\t\t\t\t then we do not continue unless its us. We are added to the\n\t\t\t\t\t channel when the JOIN is received, but we still need modes. */\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t/* Create channel user */\n\t\t\t\tmemberMutable.modes = memberModes;\n\n\t\t\t\t/* Add user to channel */\n\t\t\t\t[channel addMember:memberMutable checkForDuplicates:YES];\n\t\t\t} // for\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFNAMES:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil || channel.channelNamesReceived) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tchannel.channelNamesReceived = YES;\n\n\t\t\t/* We have to wait until names are processed before populating\n\t\t\t defaults for a channel so that we are certain there is actually\n\t\t\t only one user, which is us. */\n\t\t\tif (channel.numberOfMembers == 1 && self.isBrokenIRCd_aka_Twitch == NO) {\n\t\t\t\tNSString *defaultModes = channel.config.defaultModes;\n\n\t\t\t\tif (defaultModes.length > 0) {\n\t\t\t\t\t[self sendModes:defaultModes withParametersString:nil inChannel:channel];\n\t\t\t\t}\n\n\t\t\t\tNSString *defaultTopic = channel.config.defaultTopic;\n\n\t\t\t\tif (defaultTopic.length > 0) {\n\t\t\t\t\t[self sendTopicTo:defaultTopic inChannel:channel];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Update user count in title */\n\t\t\t[mainWindow() updateTitleFor:channel];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LISTSTART:\n\t\t{\n\t\t\tTDCServerChannelListDialog *channelListDialog = [self channelListDialog];\n\n\t\t\tif (channelListDialog) {\n\t\t\t\tchannelListDialog.contentAlreadyReceived = NO;\n\n\t\t\t\t[channelListDialog clear];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LIST:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 2);\n\n\t\t\tNSString *channel = [m paramAt:1];\n\t\t\tNSString *userCount = [m paramAt:2];\n\t\t\tNSString *topic = [m sequence:3];\n\n\t\t\tif ([channel isEqualToString:@\"*\"]) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tTDCServerChannelListDialog *channelListDialog = [self channelListDialog];\n\n\t\t\tif (channelListDialog) {\n\t\t\t\t[channelListDialog addChannel:channel count:userCount.integerValue topic:topic];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LISTEND:\n\t\t{\n\t\t\tTDCServerChannelListDialog *channelListDialog = [self channelListDialog];\n\n\t\t\tif (channelListDialog) {\n\t\t\t\tchannelListDialog.contentAlreadyReceived = YES;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_BANLIST:\n\t\tcase RPL_INVITELIST:\n\t\tcase RPL_EXCEPTLIST:\n\t\tcase RPL_QUIETLIST:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 2);\n\n\t\t\tNSUInteger paramsOffset = 0;\n\n\t\t\t/* Quiet list has an extra argument which is the string \"q\" */\n\t\t\tif (numeric == RPL_QUIETLIST && m.paramsCount == 6)\t{\n\t\t\t\tparamsOffset = 1;\n\t\t\t}\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tNSString *entryMask = [m paramAt:(2 + paramsOffset)];\n\n\t\t\tNSString *entryAuthor = nil;\n\n\t\t\tNSDate *entryCreationDate = nil;\n\n\t\t\tBOOL extendedLine = (m.paramsCount > (4 + paramsOffset));\n\n\t\t\tif (extendedLine) {\n\t\t\t\tentryAuthor = [m paramAt:(3 + paramsOffset)].nicknameFromHostmask;\n\n\t\t\t\tentryCreationDate = [NSDate dateWithTimeIntervalSince1970:[m paramAt:(4 + paramsOffset)].doubleValue];\n\t\t\t}\n\n\t\t\tTDCChannelBanListSheet *listSheet = [windowController() windowFromWindowList:@\"TDCChannelBanListSheet\"];\n\n\t\t\tif (listSheet) {\n\t\t\t\tif (listSheet.contentAlreadyReceived) {\n\t\t\t\t\tlistSheet.contentAlreadyReceived = NO;\n\n\t\t\t\t\t[listSheet clear];\n\t\t\t\t}\n\n\t\t\t\t[listSheet addEntry:entryMask setBy:entryAuthor creationDate:entryCreationDate];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (printMessage == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSString *localization = nil;\n\n\t\t\tif (numeric == RPL_BANLIST) {\n\t\t\t\tlocalization = @\"c04-d0\";\n\t\t\t} else if (numeric == RPL_INVITELIST) {\n\t\t\t\tlocalization = @\"py2-qh\";\n\t\t\t} else if (numeric == RPL_EXCEPTLIST) {\n\t\t\t\tlocalization = @\"ov2-ci\";\n\t\t\t} else if (numeric == RPL_QUIETLIST) {\n\t\t\t\tlocalization = @\"u5z-az\";\n\t\t\t}\n\n\t\t\tif (extendedLine) {\n\t\t\t\tlocalization = [NSString stringWithFormat:@\"IRC[%@-1]\", localization];\n\t\t\t} else {\n\t\t\t\tlocalization = [NSString stringWithFormat:@\"IRC[%@-2]\", localization];\n\t\t\t}\n\n\t\t\tNSString *message = nil;\n\n\t\t\tif (extendedLine) {\n\t\t\t\tmessage = TXTLS(localization, channelName, entryMask, entryAuthor, entryCreationDate);\n\t\t\t} else {\n\t\t\t\tmessage = TXTLS(localization, channelName, entryMask);\n\t\t\t}\n\n\t\t\t[self print:message\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:nil\n\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFBANLIST:\n\t\tcase RPL_ENDOFINVITELIST:\n\t\tcase RPL_ENDOFEXCEPTLIST:\n\t\tcase RPL_ENDOFQUIETLIST:\n\t\t{\n\t\t\tTDCChannelBanListSheet *listSheet = [windowController() windowFromWindowList:@\"TDCChannelBanListSheet\"];\n\n\t\t\tif (listSheet) {\n\t\t\t\tlistSheet.contentAlreadyReceived = YES;\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_YOUREOPER:\n\t\t{\n\t\t\tif (self.userIsIRCop == NO) {\n\t\t\t\tself.userIsIRCop = YES;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:TXTLS(@\"IRC[6bh-br]\", m.senderNickname)\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:nil\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_CHANNEL_URL:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\t\t\tNSString *website = [m paramAt:2];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self print:TXTLS(@\"IRC[8tq-g6]\", website)\n\t\t\t\t\t by:nil\n\t\t\t  inChannel:channel\n\t\t\t\t asType:TVCLogLineTypeWebsite\n\t\t\t\tcommand:m.command\n\t\t\t receivedAt:m.receivedAt];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WATCHSTAT:\n\t\tcase RPL_WATCHLIST:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_REAWAY:\n\t\tcase RPL_GONEAWAY:\n\t\tcase RPL_NOTAWAY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 4);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *nickname = [m paramAt:1];\n\n\t\t\tIRCAddressBookEntry *addressBookEntry =\t[self findUserTrackingAddressBookEntryForNickname:nickname];\n\n\t\t\tif (addressBookEntry == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (numeric) {\n\t\t\t\tcase RPL_REAWAY:\n\t\t\t\tcase RPL_GONEAWAY: // is away\n\t\t\t\t{\n\t\t\t\t\t[self modifyUserWithNickname:nickname asAway:YES];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase RPL_NOTAWAY: // is no longer away\n\t\t\t\t{\n\t\t\t\t\t[self modifyUserWithNickname:nickname asAway:NO];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} // switch()\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LOGON:\n\t\tcase RPL_LOGOFF:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 4);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t /* Process reply */\n\t\t\tNSString *nickname = [m paramAt:1];\n\n\t\t\tIRCAddressBookEntry *addressBookEntry =\t[self findUserTrackingAddressBookEntryForNickname:nickname];\n\n\t\t\tif (addressBookEntry == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (numeric) {\n\t\t\t\tcase RPL_LOGON: // logged online\n\t\t\t\t{\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusSignedOn notify:YES];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase RPL_LOGOFF: // logged offline\n\t\t\t\t{\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusSignedOff notify:YES];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} // switch()\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_NOWON:\n\t\tcase RPL_NOWOFF:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] > 4);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *nickname = [m paramAt:1];\n\n\t\t\tIRCAddressBookEntry *addressBookEntry =\t[self findUserTrackingAddressBookEntryForNickname:nickname];\n\n\t\t\tif (addressBookEntry == nil) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tswitch (numeric) {\n\t\t\t\tcase RPL_NOWON: // is online\n\t\t\t\t{\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusAvailable notify:NO];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase RPL_NOWOFF: // is offline\n\t\t\t\t{\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusNotAvailable notify:NO];\n\t\t\t\t\t\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t{\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} // switch()\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_WATCHOFF:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_TOOMANYWATCH:\n\t\t{\n\t\t\t/* This message is always printed because Textual does not\n\t\t\t make an effort to check the maximum allowance for this\n\t\t\t command. We therefore want a user to know why tracking\n\t\t\t breaks in Textual instead of blaming it on a bug. */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n//\t\tcase RPL_CLEARWATCH: /* Not implemented by any IRCd */\n\t\tcase RPL_ENDOFWATCHLIST:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_MONLIST:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_MONONLINE:\n\t\tcase RPL_MONOFFLINE:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 2);\n\n\t\t\t/* Present reply to the user if we have destination */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\t/* Process reply */\n\t\t\tNSString *changedUsersString = [m paramAt:1];\n\n\t\t\tNSArray *changedUsers = [changedUsersString componentsSeparatedByString:@\",\"];\n\n\t\t\tfor (NSString *changedUser in changedUsers) {\n\t\t\t\tNSString *nickname = nil;\n\n\t\t\t\tif ([changedUser hostmaskComponents:&nickname username:NULL address:NULL onClient:self] == NO) {\n\t\t\t\t\tnickname = changedUser;\n\t\t\t\t}\n\n\t\t\t\tIRCAddressBookEntry *addressBookEntry =\t[self findUserTrackingAddressBookEntryForNickname:nickname];\n\n\t\t\t\tif (addressBookEntry == nil) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (numeric == RPL_MONONLINE) { // logged online\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusSignedOn notify:YES];\n\t\t\t\t} else {\n\t\t\t\t\t[self statusOfTrackedNickname:nickname changedTo:IRCAddressBookUserTrackingStatusSignedOff notify:YES];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_MONLISTFULL:\n\t\t{\n\t\t\t/* See ERR_TOOMANYWATCH for reason we always print this. */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_ENDOFMONLIST:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printReplyToHiddenCommandResponsesQuery:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_TARGUMODEG:\n\t\t{\n\t\t\t// Ignore. 717 will take care of notification.\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_TARGNOTIFY:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\n\t\t\t[self printDebugInformation:TXTLS(@\"IRC[11i-ev]\", nickname)];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_UMODEGMSG:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *nickname = [m paramAt:1];\n\t\t\tNSString *hostmask = [m paramAt:2];\n\n\t\t\tNSString *message = TXTLS(@\"IRC[3yj-in]\", nickname, hostmask);\n\n\t\t\tIRCChannel *channel = nil;\n\n\t\t\tif ([TPCPreferences locationToSendNotices] == TXNoticeSendLocationSelectedChannel) {\n\t\t\t\tchannel = [mainWindow() selectedChannelOn:self];\n\t\t\t}\n\n\t\t\tif (channel) {\n\t\t\t\t[self printDebugInformation:message inChannel:channel];\n\t\t\t} else {\n\t\t\t\t[self printDebugInformationToConsole:message];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LOGGEDIN:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 4);\n\n\t\t\t[self enableCapability:ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:[m sequence:3]\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:nil\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_LOGGEDOUT:\n\t\t{\n\t\t\tNSAssertReturn([m paramsCount] == 3);\n\n\t\t\t[self resetSASLNegotiation];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self print:[m sequence:2]\n\t\t\t\t\t\t by:nil\n\t\t\t\t  inChannel:nil\n\t\t\t\t\t asType:TVCLogLineTypeDebug\n\t\t\t\t\tcommand:m.command\n\t\t\t\t receivedAt:m.receivedAt];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase RPL_SASLSUCCESS:\n\t\tcase ERR_NICKLOCKED:\n\t\tcase ERR_SASLFAIL:\n\t\tcase ERR_SASLTOOLONG:\n\t\tcase ERR_SASLABORTED:\n\t\tcase ERR_SASLALREADY:\n\t\tcase RPL_SASLMECHS: /* Treated as error */\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\tif (numeric == RPL_SASLSUCCESS) { // success\n\t\t\t\t\t[self printReply:m];\n\t\t\t\t} else {\n\t\t\t\t\t[self printErrorReply:m];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ([self isPendingCapabilityEnabled:ClientIRCv3SupportedCapabilityIsInSASLNegotiation]) {\n\t\t\t\t[self disablePendingCapability:ClientIRCv3SupportedCapabilityIsInSASLNegotiation];\n\n\t\t\t\t[self resumeCapabilityNegotiation];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t/* We will handle custom WHOIS responses here because there\n\t\t\t are so many that it is impossible to cover them all above. */\n\t\t\t/* For those that we don't handle, give a plugin a chance first. */\n\t\t\tNSString *numericString = [NSString stringWithUnsignedInteger:numeric];\n\n\t\t\tif ([sharedPluginManager().supportedServerInputCommands containsObject:numericString]) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\t/* Output custom WHOIS response to proper target */\n\t\t\t\tif (self.inWhoisResponse && m.paramsCount > 2) {\n\t\t\t\t\t[self printUnknownReply:m inChannel:[mainWindow() selectedChannelOn:self]];\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t/* Output unknown result */\n\t\t\t\t[self printUnknownReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n}\n\n- (void)receiveErrorNumericReply:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tNSUInteger numeric = m.commandNumeric;\n\n\tBOOL printMessage = [self postReceivedMessage:m];\n\n\tswitch (numeric) {\n\t\tcase ERR_NOSUCHNICK:\n\t\t{\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel) {\n\t\t\t\t[self printErrorReply:m inChannel:channel withSequence:2];\n\t\t\t} else {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_NOSUCHSERVER:\n\t\tcase ERR_NOSUCHCHANNEL:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_NICKNAMEINUSE:\n\t\tcase ERR_ERRONEUSNICKNAME:\n\t\t{\n\t\t\tif (self.isLoggedIn) {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\t[self printErrorReply:m];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self receiveNicknameCollisionError:m];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_UNAVAILRESOURCE:\n\t\t{\n\t\t\tNSString *target = [m paramAt:1];\n\n\t\t\tif (self.isLoggedIn || [self stringIsNickname:target] == NO) {\n\t\t\t\tif (printMessage) {\n\t\t\t\t\t[self printErrorReply:m];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t[self receiveNicknameCollisionError:m];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_CANNOTSENDTOCHAN:\n\t\t{\n\t\t\tNSAssertReturn(printMessage);\n\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel) {\n\t\t\t\t[self printErrorReply:m inChannel:channel withSequence:2];\n\t\t\t} else {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_ADMONLY:\n\t\tcase ERR_BADCHANMASK:\n\t\tcase ERR_BADCHANNAME:\n\t\tcase ERR_BADCHANNEL:\n\t\tcase ERR_BADCHANNELKEY:\n\t\tcase ERR_BANNEDFROMCHAN:\n\t\tcase ERR_CHANNELISFULL:\n\t\tcase ERR_DELAYREJOIN:\n\t\tcase ERR_FORBIDDENCHANNEL:\n\t\tcase ERR_INVITEONLYCHAN:\n\t\tcase ERR_LINKCHANNEL:\n\t\tcase ERR_NEEDREGGEDNICK:\n\t\tcase ERR_NOHIDING:\n\t\tcase ERR_OPERONLY:\n\t\tcase ERR_OPERSPVERIFY:\n\t\tcase ERR_SECUREONLYCHAN:\n\t\tcase ERR_THROTTLE:\n\t\tcase ERR_TOOMANYCHANNELS:\n\t\tcase ERR_TOOMANYJOINS:\n\t\t{\n\t\t\tNSString *channelName = [m paramAt:1];\n\n\t\t\tIRCChannel *channel = [self findChannel:channelName];\n\n\t\t\tif (channel) {\n\t\t\t\tchannel.errorOnLastJoinAttempt = YES;\n\n\t\t\t\t/* In addition to the console, print join errors in\n\t\t\t\t the channel itself because user might check there. */\n\t\t\t\tif (printMessage) {\n\t\t\t\t\t[self printErrorReply:m inChannel:channel withSequence:2];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Print to console */\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_WHOSYNTAX:\n\t\tcase ERR_WHOLIMEXCEED:\n\t\t{\n\t\t\t[self.requestedCommands recordWhoRequestClosed];\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ERR_DISABLED:\n\t\tcase ERR_UNKNOWNCOMMAND:\n\t\tcase ERR_NEEDMOREPARAMS:\n\t\t{\n\t\t\tNSString *command = [m paramAt:1];\n\n\t\t\tif ([command isEqualToString:@\"ISON\"]) {\n\t\t\t\t[self.requestedCommands recordIsonRequestClosed];\n\t\t\t} else if ([command isEqualToString:@\"WHO\"]) {\n\t\t\t\t[self.requestedCommands recordWhoRequestClosed];\n\t\t\t}\n\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tif (printMessage) {\n\t\t\t\t[self printErrorReply:m];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t} // switch()\n}\n\n- (void)receiveNicknameCollisionError:(IRCMessage *)m\n{\n\tNSParameterAssert(m != nil);\n\n\tif (self.isConnected == NO || self.isLoggedIn) {\n\t\treturn;\n\t}\n\n\tNSArray *alternateNicknames = self.config.alternateNicknames;\n\n\tNSString *tryingNickname = self.tryingNicknameSentNickname;\n\n\t[self printDebugInformationToConsole:TXTLS(@\"IRC[js3-9v]\", tryingNickname)];\n\n\tNSUInteger tryingNicknameNumber = self.tryingNicknameNumber;\n\n\tif (alternateNicknames.count > tryingNicknameNumber) {\n\t\tNSString *nickname = alternateNicknames[tryingNicknameNumber];\n\n\t\t[self changeNickname:nickname];\n\t} else {\n\t\t[self tryAnotherNickname];\n\t}\n\n\tself.tryingNicknameNumber += 1;\n}\n\n- (void)tryAnotherNickname\n{\n\tif (self.isConnected == NO || self.isLoggedIn) {\n\t\treturn;\n\t}\n\n\t/* IRCISupportInfo would not be populated by now which means we cannot use a\n\t server-specific maximum nickname length value at this point. */\n\tconst NSUInteger maximumLength = IRCProtocolDefaultNicknameMaximumLength;\n\n\tNSString *tryingNickname = [self.tryingNicknameSentNickname padNicknameWithCharacter:'_' maximumLength:maximumLength];\n\n\tif (tryingNickname) {\n\t\tself.tryingNicknameSentNickname = tryingNickname;\n\t} else {\n\t\tself.tryingNicknameSentNickname = @\"0\";\n\t}\n\n\t[self changeNickname:self.tryingNicknameSentNickname];\n}\n\n#pragma mark -\n#pragma mark Autojoin\n\n- (void)startAutojoinTimer\n{\n\tif (self.autojoinTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\tNSTimeInterval interval = [TPCPreferences autojoinDelayAfterIdentification];\n\n\tif (CGFloatAreEqual(interval, 0.0)) {\n\t\t[self onAutojoinTimer];\n\n\t\treturn;\n\t}\n\n\t[self.autojoinTimer start:interval onRepeat:NO];\n}\n\n- (void)stopAutojoinTimer\n{\n\tif (self.autojoinTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.autojoinTimer stop];\n}\n\n- (void)onAutojoinTimer\n{\n\t[self startAutojoinNextJoinTimer];\n}\n\n- (void)startAutojoinDelayedWarningTimer\n{\n\tif (self.autojoinDelayedWarningTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.autojoinDelayedWarningTimer start:_autojoinDelayedWarningInterval onRepeat:YES];\n}\n\n- (void)stopAutojoinDelayedWarningTimer\n{\n\tif (self.autojoinDelayedWarningTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.autojoinDelayedWarningTimer stop];\n}\n\n- (void)onAutojoinDelayedWarningTimer\n{\n\tif (self.isLoggedIn == NO ||\n\t\tself.config.hideAutojoinDelayedWarnings ||\n\t\tself.autojoinDelayedWarningCount >= _autojoinDelayedWarningMaxCount)\n\t{\n\t\t[self stopAutojoinDelayedWarningTimer];\n\n\t\treturn;\n\t}\n\n\tself.autojoinDelayedWarningCount += 1;\n\n\t/* This message is posted to the server console and the \n\t front most channel if it is on this server. */\n\tNSString *text = TXTLS(@\"IRC[r5h-fj]\");\n\n\t[self printDebugInformationToConsole:text];\n\n\tIRCChannel *c = [mainWindow() selectedChannelOn:self];\n\n\tif (c != nil) {\n\t\t[self printDebugInformation:text inChannel:c];\n\t}\n}\n\n- (void)startAutojoinNextJoinTimer\n{\n\tif (self.autojoinNextJoinTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\tNSTimeInterval interval = [TPCPreferences autojoinDelayBetweenChannelJoins];\n\n\t[self.autojoinNextJoinTimer start:interval onRepeat:YES];\n\n\t/* Fake first event */\n\t[self onAutojoinNextJoinTimer];\n}\n\n- (void)stopAutojoinNextJoinTimer\n{\n\tif (self.autojoinNextJoinTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.autojoinNextJoinTimer stop];\n\n\tself.channelsToAutojoin = nil;\n}\n\n- (void)onAutojoinNextJoinTimer\n{\n\t[self autojoinNextChannel];\n}\n\n- (void)autojoinNextChannel\n{\n\tif (self.isAutojoining == NO) {\n\t\treturn;\n\t}\n\n\t@synchronized (self.channelsToAutojoin) {\n\t\tNSUInteger numberOfChannelsRemaining = self.channelsToAutojoin.count;\n\n\t\tNSUInteger maximumNumberOfJoins = [TPCPreferences autojoinMaximumChannelJoins];\n\n\t\tNSRange arrayRange;\n\n\t\tBOOL endOfArray = (numberOfChannelsRemaining <= maximumNumberOfJoins);\n\n\t\tif (endOfArray == NO) {\n\t\t\tarrayRange = NSMakeRange(0, maximumNumberOfJoins);\n\t\t} else {\n\t\t\tarrayRange = NSMakeRange(0, numberOfChannelsRemaining);\n\t\t}\n\n\t\tNSArray *channelsToJoin = [self.channelsToAutojoin subarrayWithRange:arrayRange];\n\n\t\t[self autojoinChannels:channelsToJoin];\n\n\t\tif (endOfArray == NO) {\n\t\t\t[self.channelsToAutojoin removeObjectsInRange:arrayRange];\n\t\t} else {\n\t\t\tself.isAutojoining = NO;\n\n\t\t\tself.isAutojoined = YES;\n\n\t\t\t[self stopAutojoinNextJoinTimer];\n\t\t}\n\t}\n}\n\n- (void)autojoinChannels:(NSArray<IRCChannel *> *)channels\n{\n\tNSParameterAssert(channels != nil);\n\n\t[self joinChannels:channels];\n}\n\n- (void)performAutoJoin\n{\n\t[self performAutoJoinInitiatedByUser:NO];\n}\n\n- (void)performAutoJoinInitiatedByUser:(BOOL)initiatedByUser\n{\n\tif (self.isAutojoining) {\n\t\treturn;\n\t}\n\n\t[self stopAutojoinDelayedWarningTimer];\n\n\tif (initiatedByUser == NO) {\n\t\t/* Ignore previous invocations of this method */\n\t\tif (self.isAutojoined) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* Ignore autojoin based on ZNC preferences */\n\t\tif (self.isConnectedToZNC && self.config.zncIgnoreConfiguredAutojoin) {\n\t\t\tself.isAutojoined = YES;\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Do nothing unless certain conditions are met */\n\t\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityIsIdentifiedWithSASL] == NO) {\n\t\t\tif (self.config.autojoinWaitsForNickServ) {\n\t\t\t\tif (self.serverHasNickServ && self.userIsIdentifiedWithNickServ == NO) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNSMutableArray<IRCChannel *> *channelsToAutojoin = [NSMutableArray array];\n\n\tfor (IRCChannel *c in self.channelList) {\n\t\tif (c.isChannel && c.isActive == NO) {\n\t\t\tif (c.config.autoJoin) {\n\t\t\t\t[channelsToAutojoin addObject:c];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (channelsToAutojoin.count == 0) {\n\t\tself.isAutojoining = YES;\n\n\t\treturn;\n\t}\n\n\tself.isAutojoining = YES;\n\n\t@synchronized (self.channelsToAutojoin) {\n\t\t[channelsToAutojoin shuffle];\n\n\t\tself.channelsToAutojoin = channelsToAutojoin;\n\t}\n\n\t[self startAutojoinTimer];\n}\n\n#pragma mark -\n#pragma mark Post Events\n\n- (void)postEventToViewController:(NSString *)eventToken\n{\n\tif (themeSettings().js_postHandleEventNotifications == NO) {\n\t\treturn; // Cancel operation...\n\t}\n\n\t[self postEventToViewController:eventToken forItem:self];\n\n\tfor (IRCChannel *channel in self.channelList) {\n\t\t[self postEventToViewController:eventToken forItem:channel];\n\t}\n}\n\n- (void)postEventToViewController:(NSString *)eventToken forChannel:(IRCChannel *)channel\n{\n\tif (themeSettings().js_postHandleEventNotifications == NO) {\n\t\treturn; // Cancel operation...\n\t}\n\n\t[self postEventToViewController:eventToken forItem:channel];\n}\n\n- (void)postEventToViewController:(NSString *)eventToken forItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(eventToken != nil);\n\tNSParameterAssert(item != nil);\n\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\t[item.viewController evaluateFunction:@\"Textual.handleEvent\" withArguments:@[eventToken] onQueue:NO];\n}\n\n#pragma mark -\n#pragma mark Timers\n\n- (void)startPongTimer\n{\n\tif (self.pongTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.pongTimer start:_pongCheckInterval onRepeat:YES];\n}\n\n- (void)stopPongTimer\n{\n\tif (self.pongTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.pongTimer stop];\n}\n\n- (void)onPongTimer\n{\n\tif (self.isLoggedIn == NO) {\n\t\t[self stopPongTimer];\n\n\t\treturn;\n\t}\n\n\t/* Instead of stopping and starting the timer every time this changes, it\n\t it is easier to check if we should do it every timer iteration.\n\t The ability to disable this is important on PSYBNC connection because\n\t PSYBNC doesn't respond to PING commands. There are other irc daemons that\n\t don't reply to PING either and they should all be shot. */\n\tNSTimeInterval timeSpent = [NSDate timeIntervalSinceNow:self.lastMessageReceived];\n\n\tif (timeSpent >= _timeoutInterval)\n\t{\n\t\t/* If EOF Received when we were not expecting it, then timeout regardless\n\t\t of user preference once our timeout interval is reached. */\n\t\tif (self.socket.EOFReceived || self.config.performDisconnectOnPongTimer) {\n\t\t\t[self printDebugInformation:TXTLS(@\"IRC[bps-la]\", (timeSpent / 60.0)) inChannel:nil];\n\n\t\t\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t\t\t[self disconnect];\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (self.timeoutWarningShownToUser == NO) {\n\t\t\tself.timeoutWarningShownToUser = YES;\n\n\t\t\t[self printDebugInformation:TXTLS(@\"IRC[gzo-54]\", (timeSpent / 60.0)) inChannel:nil];\n\t\t}\n\t}\n\telse if (timeSpent >= _pingInterval)\n\t{\n\t\tif (self.config.performPongTimer == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self sendPing:self.serverAddress];\n\t}\n}\n\n- (void)startReconnectTimer\n{\n\tif ((self.reconnectEnabledBecauseOfSleepMode\t\t&& self.config.autoSleepModeDisconnect == NO) ||\n\t\t(self.reconnectEnabledBecauseOfSleepMode == NO  && self.config.autoReconnect == NO))\n\t{\n\t\treturn;\n\t}\n\n\tif (self.reconnectTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.reconnectTimer start:_reconnectInterval onRepeat:YES];\n}\n\n- (void)stopReconnectTimer\n{\n\tif (self.reconnectTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.reconnectTimer stop];\n}\n\n- (void)onReconnectTimer\n{\n\tif (self.isConnecting || self.isConnected) {\n\t\treturn;\n\t}\n\n\t[self connect:IRCClientConnectModeReconnect];\n}\n\n- (void)startRetryTimer\n{\n\tif (self.retryTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.retryTimer start:_retryInterval];\n}\n\n- (void)stopRetryTimer\n{\n\tif (self.retryTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.retryTimer stop];\n}\n\n- (void)onRetryTimer\n{\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t__weak IRCClient *weakSelf = self;\n\n\t\tself.disconnectCallback = ^{\n\t\t\t[weakSelf connect:IRCClientConnectModeRetry];\n\t\t};\n\n\t\t[self disconnect];\n\t});\n}\n\n#pragma mark -\n#pragma mark Requested Commands\n\n- (void)removeRequestedCommands\n{\n\t[self.requestedCommands removeCommands];\n}\n\n- (void)createHiddenCommandResponses\n{\n\tif (self.isTerminating) {\n\t\treturn;\n\t}\n\n\tif (self.rawDataLogQuery != nil) {\n\t\treturn;\n\t}\n\n\tIRCChannel *query = [self findChannelOrCreate:@\"Hidden Responses\" isUtility:YES];\n\n\tself.hiddenCommandResponsesQuery = query;\n\n\t[mainWindow() select:query];\n\n\t[self printDebugInformation:TXTLS(@\"IRC[yem-td]\") inChannel:query];\n}\n\n- (void)printReplyToHiddenCommandResponsesQuery:(IRCMessage *)message\n{\n\tIRCChannel *query = self.hiddenCommandResponsesQuery;\n\n\tif (query == nil) {\n\t\treturn;\n\t}\n\n\t[self printReply:message inChannel:query];\n}\n\n#pragma mark -\n#pragma mark Plugins and Scripts\n\n- (void)outputDescriptionForError:(NSError *)error forTextualCmdScriptAtPath:(NSString *)path inputString:(NSString *)inputString\n{\n\tNSString *filename = path.lastPathComponent;\n\n\tNSString *errorDescription = error.userInfo[NSAppleScriptErrorMessage];\n\n\tif (errorDescription == nil) {\n\t\terrorDescription = error.userInfo[NSAppleScriptErrorBriefMessage];\n\t}\n\n\tif (errorDescription == nil) {\n\t\terrorDescription = error.localizedFailureReason;\n\t}\n\n\tif (errorDescription == nil) {\n\t\terrorDescription = error.localizedDescription;\n\t}\n\n\tif (inputString.length == 0) {\n\t\tinputString = @\"(no input)\";\n\t}\n\n\t[self printDebugInformation:TXTLS(@\"IRC[2mc-h0]\", filename, inputString, errorDescription)];\n\n\tLogToConsoleError(\"%{public}@\", TXTLS(@\"IRC[ax0-mt]\", errorDescription));\n}\n\n- (void)sendTextualCmdScriptResult:(NSString *)resultString toChannel:(nullable NSString *)channel\n{\n\tNSParameterAssert(resultString != nil);\n\n\tIRCTreeItem *destination = nil;\n\n\tif (channel == nil) {\n\t\tdestination = self;\n\t} else {\n\t\tdestination = [self findChannel:channel];\n\t}\n\n\tif (destination == nil) {\n\t\tLogToConsoleFault(\"A script returned a result but its destination no longer exists\");\n\n\t\treturn;\n\t}\n\n\tresultString = resultString.trim;\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self inputText:resultString destination:destination];\n\t});\n}\n\n- (void)executeTextualCmdScriptInContext:(NSDictionary<NSString *, NSString *> *)context\n{\n\tXRPerformBlockAsynchronouslyOnQueue([THOPluginDispatcher dispatchQueue], ^{\n\t\t[self _executeTextualCmdScriptInContext:context];\n\t});\n}\n\n- (void)_executeTextualCmdScriptInContext:(NSDictionary<NSString *, NSString *> *)context\n{\n\tNSParameterAssert(context != nil);\n\n\tNSString *inputString = context[@\"inputString\"];\n\n\tNSString *path = context[@\"path\"];\n\n\tNSString *targetChannel = context[@\"targetChannel\"];\n\n\tNSParameterAssert(path != nil);\n\n\tNSURL *pathURL = [NSURL fileURLWithPath:path];\n\n\t/* Is it AppleScript? */\n\tif ([path hasSuffix:TPCResourceManagerScriptDocumentTypeExtension]) {\n\t\tBOOL isBuiltinScript = [path hasPrefix:[TPCPathInfo applicationResources]];\n\n\t\t/* /////////////////////////////////////////////////////// */\n\t\t/* Event Descriptor */\n\t\t/* /////////////////////////////////////////////////////// */\n\n\t\tNSAppleEventDescriptor *firstParameter = [NSAppleEventDescriptor descriptorWithString:inputString];\n\t\tNSAppleEventDescriptor *secondParameter = [NSAppleEventDescriptor descriptorWithString:targetChannel];\n\n\t\tNSAppleEventDescriptor *parameters = [NSAppleEventDescriptor listDescriptor];\n\n\t\t[parameters insertDescriptor:firstParameter atIndex:1];\n\t\t[parameters insertDescriptor:secondParameter atIndex:2];\n\n\t\tProcessSerialNumber process = { 0, kCurrentProcess };\n\n\t\tNSAppleEventDescriptor *target = [NSAppleEventDescriptor descriptorWithDescriptorType:typeProcessSerialNumber\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tbytes:&process\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   length:sizeof(ProcessSerialNumber)];\n\n\t\tNSAppleEventDescriptor *handler = [NSAppleEventDescriptor descriptorWithString:@\"textualcmd\"];\n\n\t\tNSAppleEventDescriptor *event = [NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t eventID:kASSubroutineEvent\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttargetDescriptor:target\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\treturnID:kAutoGenerateReturnID\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   transactionID:kAnyTransactionID];\n\n\t\t[event setParamDescriptor:handler forKeyword:keyASSubroutineName];\n\n\t\t[event setParamDescriptor:parameters forKeyword:keyDirectObject];\n\n\t\t/* /////////////////////////////////////////////////////// */\n\t\t/* Execute Event */\n\t\t/* /////////////////////////////////////////////////////// */\n\t\t/* NSUserAppleScriptTask expects the script to be in the Application Scripts folder \n\t\t which means if we want to execute scripts in the app's Resources folder, we use a\n\t\t regular call to NSAppleScript. It's pretty safe to say that scripts we make ourselves\n\t\t wont produce errors which means the logic for handling errors is ignored for scripts\n\t\t that are performed in the Resources folder. */\n\n\t\tif (isBuiltinScript)\n\t\t{\n\t\t\tNSAppleScript *appleScript = [[NSAppleScript alloc] initWithContentsOfURL:pathURL error:NULL];\n\n\t\t\tif (appleScript == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSAppleEventDescriptor *result = [appleScript executeAppleEvent:event error:NULL];\n\n\t\t\tif (result == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self sendTextualCmdScriptResult:result.stringValue toChannel:targetChannel];\n\t\t}\n\t\telse // isBuiltinScript\n\t\t{\n\t\t\tNSError *appleScriptError = nil;\n\n\t\t\tNSUserAppleScriptTask *appleScript = [[NSUserAppleScriptTask alloc] initWithURL:pathURL error:&appleScriptError];\n\n\t\t\tif (appleScript == nil) {\n\t\t\t\t[self outputDescriptionForError:appleScriptError forTextualCmdScriptAtPath:path inputString:inputString];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[appleScript executeWithAppleEvent:event\n\t\t\t\t\t\t\t completionHandler:^(NSAppleEventDescriptor *result, NSError *error)\n\t\t\t {\n\t\t\t\t if (result == nil) {\n\t\t\t\t\t [self outputDescriptionForError:error forTextualCmdScriptAtPath:path inputString:inputString];\n\t\t\t\t } else {\n\t\t\t\t\t [self sendTextualCmdScriptResult:result.stringValue toChannel:targetChannel];\n\t\t\t\t }\n\t\t\t }];\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* /////////////////////////////////////////////////////// */\n\t/* Execute Shell Script */\n\t/* /////////////////////////////////////////////////////// */\n\n\t/* Build list of arguments. */\n\tNSMutableArray *taskArguments = [NSMutableArray array];\n\n\tif (targetChannel) {\n\t\t[taskArguments addObject:targetChannel];\n\t} else {\n\t\t[taskArguments addObject:@\"\"];\n\t}\n\n\tNSArray *inputStringComponents = [inputString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t[taskArguments addObjectsFromArray:inputStringComponents];\n\n\t/* Create task object */\n\tNSError *taskError = nil;\n\n\tNSUserUnixTask *task = [[NSUserUnixTask alloc] initWithURL:pathURL error:&taskError];\n\n\tif (task == nil) {\n\t\t[self outputDescriptionForError:taskError forTextualCmdScriptAtPath:path inputString:inputString];\n\n\t\treturn;\n\t}\n\n\t/* Prepare pipe */\n\tNSPipe *standardOutputPipe = [NSPipe pipe];\n\n\tNSFileHandle *readingPipe = standardOutputPipe.fileHandleForReading;\n\tNSFileHandle *writingPipe = standardOutputPipe.fileHandleForWriting;\n\n\ttask.standardOutput = writingPipe;\n\n\t/* Try performing task */\n\t[task executeWithArguments:taskArguments completionHandler:^(NSError *error) {\n\t\tif (error) {\n\t\t\t[self outputDescriptionForError:error forTextualCmdScriptAtPath:path inputString:inputString];\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSData *result = [readingPipe readDataToEndOfFile];\n\n\t\tNSString *resultString = [NSString stringWithData:result encoding:NSUTF8StringEncoding];\n\n\t\t[self sendTextualCmdScriptResult:resultString toChannel:targetChannel];\n\t}];\n}\n\n- (void)processBundlesUserMessage:(NSString *)message command:(NSString *)command\n{\n\tNSParameterAssert(message != nil);\n\n\t[THOPluginDispatcher userInputCommandInvokedOnClient:self commandString:command messageString:message];\n}\n\n- (void)processBundlesServerMessage:(IRCMessage *)message\n{\n\tNSParameterAssert(message != nil);\n\n\t[THOPluginDispatcher didReceiveServerInput:message onClient:self];\n}\n\n- (BOOL)postReceivedMessage:(IRCMessage *)referenceMessage\n{\n\tNSParameterAssert(referenceMessage != nil);\n\n\treturn [self postReceivedMessage:referenceMessage\n\t\t\t\t\t\t\twithText:referenceMessage.sequence\n\t\t\t\t\t\t destinedFor:nil];\n}\n\n- (BOOL)postReceivedMessage:(IRCMessage *)referenceMessage withText:(nullable NSString *)text destinedFor:(nullable IRCChannel *)textDestination\n{\n\tNSParameterAssert(referenceMessage != nil);\n\n\treturn [self postReceivedCommand:referenceMessage.command\n\t\t\t\t\t\t\twithText:text\n\t\t\t\t\t\t destinedFor:textDestination\n\t\t\t\t\treferenceMessage:referenceMessage];\n}\n\n- (BOOL)postReceivedCommand:(NSString *)command withText:(nullable NSString *)text destinedFor:(nullable IRCChannel *)textDestination referenceMessage:(IRCMessage *)referenceMessage\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(referenceMessage != nil);\n\n\treturn [THOPluginDispatcher receivedCommand:command\n\t\t\t\t\t\t\t\t\t   withText:text\n\t\t\t\t\t\t\t\t\t authoredBy:referenceMessage.sender\n\t\t\t\t\t\t\t\t\tdestinedFor:textDestination\n\t\t\t\t\t\t\t\t\t   onClient:self\n\t\t\t\t\t\t\t\t\t receivedAt:referenceMessage.receivedAt\n\t\t\t\t\t\t\t   referenceMessage:referenceMessage];\n}\n\n#pragma mark -\n#pragma mark Commands\n\n- (void)connect\n{\n\t[self connect:IRCClientConnectModeNormal];\n}\n\n- (void)connect:(IRCClientConnectMode)connectMode\n{\n\t[self connect:connectMode bypassProxy:NO];\n}\n\n- (void)connect:(IRCClientConnectMode)connectMode bypassProxy:(BOOL)bypassProxy\n{\n\t/* Do not allow a connect to occur until the current \n\t socket has completed disconnecting */\n\tif (self.isConnecting || self.isConnected || self.isQuitting || self.isDisconnecting) {\n\t\treturn;\n\t}\n\n\t/* Check if system is sleeping. */\n\tif ([XRSystemInformation systemIsSleeping]) {\n\t\tLogToConsoleInfo(\"Refusing to connect because system is sleeping\");\n\n\t\treturn;\n\t}\n\n\t/* Do we have somewhere to connect to? */\n\tNSArray *servers = self.config.serverList;\n\n\tif (servers.count == 0) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[iaa-0u]\")];\n\n\t\treturn;\n\t}\n\n\t/* Begin populating configuration */\n\t/* Temporary values take priority. When a temporary server\n\t address is specified, then the temporary port is used too,\n\t or 6667 without SSL is used. Nothing from the current\n\t server configuration is read if there is temporary server. */\n\tNSString *serverAddress = nil;\n\n\tuint16_t serverPort = IRCConnectionDefaultServerPort;\n\n\tBOOL connectionPrefersSecuredConnection = NO;\n\n\tif (self.temporaryServerAddressOverride) {\n\t\tserverAddress = self.temporaryServerAddressOverride;\n\n\t\tif (self.temporaryServerPortOverride > 0 &&\n\t\t\tself.temporaryServerPortOverride <= TXMaximumTCPPort)\n\t\t{\n\t\t\tserverPort = self.temporaryServerPortOverride;\n\t\t}\n\t}\n\n\tif (serverAddress.isValidInternetAddress == NO) {\n\t\tNSUInteger serverIndex = self.lastServerSelected;\n\n\t\tif (serverIndex == NSNotFound) {\n\t\t\tserverIndex = 0;\n\t\t} else {\n\t\t\tserverIndex += 1;\n\n\t\t\tif (serverIndex >= servers.count) {\n\t\t\t\tserverIndex = 0;\n\t\t\t}\n\t\t}\n\n\t\tself.lastServerSelected = serverIndex;\n\n\t\tIRCServer *server = servers[serverIndex];\n\n\t\tserverAddress = server.serverAddress;\n\t\tserverPort = server.serverPort;\n\n\t\tconnectionPrefersSecuredConnection = server.prefersSecuredConnection;\n\n\t\tself.server = server;\n\t}\n\n\t/* Do not wait for an actual connect before destroying the temporary\n\t store. Once its defined, its to be nil'd out no matter what. */\n\tself.temporaryServerAddressOverride = nil;\n\tself.temporaryServerPortOverride = 0;\n\n\t/* Reset status */\n\tself.connectType = connectMode;\n\n\tself.disconnectType = IRCClientDisconnectModeNormal;\n\n\tself.isConnecting = YES;\n\n\t/* Disable reconnect attempt but permit more */\n\t[self stopReconnectTimer];\n\n\tself.reconnectEnabled = YES;\n\n\t/* Present status to user */\n\t[mainWindow() updateTitleFor:self];\n\n\tif (connectMode == IRCClientConnectModeReconnect) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[xxb-y2]\")];\n\t} else if (connectMode == IRCClientConnectModeRetry) {\n\t\t[self printDebugInformationToConsole:TXTLS(@\"IRC[ky3-36]\")];\n\t}\n\n\t/* To provide user with similar behavior, when migrating -connectionPrefersIPv4\n\t in IRCClientConfig, we set the address type to IRCConnectionAddressTypeIPv4.\n\t We check if both values are set to offer the user a warning that the preference\n\t they had has changed in a way they may not want. When user changes the address\n\t type in Server Properties, we unset -connectionPrefersIPv4 so that the warning\n\t does not appear again, ever. */\n\tIRCConnectionAddressType addressType = self.config.addressType;\n\n\tif (self.config.showConnectionPrefersIPv4Warning) {\n\t\t[self printDebugInformation:TXTLS(@\"IRC[w05-ph]\")];\n\t}\n\n\t[self printDebugInformationToConsole:TXTLS(@\"IRC[o77-ls]\", serverAddress, serverPort)];\n\n\t[RZNotificationCenter() postNotificationName:IRCClientWillConnectNotification object:self];\n\n\t/* Create socket */\n\tIRCConnectionConfigMutable *socketConfig = [IRCConnectionConfigMutable new];\n\n\tsocketConfig.addressType = addressType;\n\n\tsocketConfig.serverAddress = serverAddress;\n\tsocketConfig.serverPort = serverPort;\n\n\tIRCConnectionProxyType proxyType = self.config.proxyType;\n\n\t/* Network.framework cannot use a custom proxy so we can only either use none\n\t or allow it to automatically configure the connection using the system proxy. */\n\tsocketConfig.connectionPrefersModernSockets = ([TPCPreferences preferModernSockets] &&\n\t\t\t\t\t\t\t\t\t\t\t\t   (proxyType == IRCConnectionProxyTypeNone ||\n\t\t\t\t\t\t\t\t\t\t\t\t\tproxyType == IRCConnectionProxyTypeAutomatic));\n\n\tsocketConfig.cipherSuites = self.config.cipherSuites;\n\n\tsocketConfig.connectionPrefersSecuredConnection = connectionPrefersSecuredConnection;\n\tsocketConfig.connectionShouldValidateCertificateChain = self.config.validateServerCertificateChain;\n\n\tsocketConfig.identityClientSideCertificate = self.config.identityClientSideCertificate;\n\n\tif (bypassProxy == NO) {\n\t\tsocketConfig.proxyType = proxyType;\n\n\t\tif (socketConfig.proxyType == IRCConnectionProxyTypeSocks4 ||\n\t\t\tsocketConfig.proxyType == IRCConnectionProxyTypeSocks5 ||\n\t\t\tsocketConfig.proxyType == IRCConnectionProxyTypeHTTP ||\n\t\t\tsocketConfig.proxyType == IRCConnectionProxyTypeHTTPS)\n\t\t{\n\t\t\tsocketConfig.proxyPort = self.config.proxyPort;\n\t\t\tsocketConfig.proxyAddress = self.config.proxyAddress;\n\t\t\tsocketConfig.proxyPassword = self.config.proxyPassword;\n\t\t\tsocketConfig.proxyUsername = self.config.proxyUsername;\n\t\t}\n\t}\n\n\tsocketConfig.floodControlDelayInterval = self.config.floodControlDelayTimerInterval;\n\tsocketConfig.floodControlMaximumMessages = self.config.floodControlMaximumMessages;\n\n\tsocketConfig.connectionPrefersModernCiphersOnly = [TPCPreferences preferModernCiphers];\n\n\tself.socket = [[IRCConnection alloc] initWithConfig:socketConfig onClient:self];\n\n\t[self.socket open];\n\n\t/* Pass status to view controller */\n\t[self postEventToViewController:@\"serverConnecting\"];\n}\n\n- (void)autoConnectWithDelay:(NSUInteger)delay afterWakeUp:(BOOL)afterWakeUp\n{\n\tself.connectDelay = delay;\n\n\tif (afterWakeUp) {\n\t\t[self autoConnectAfterWakeUp];\n\t} else {\n\t\t[self autoConnect];\n\t}\n}\n\n- (void)autoConnect\n{\n\tNSUInteger connectDelay = self.connectDelay;\n\n\tif (connectDelay == 0) {\n\t\t[self autoConnectPerformConnect];\n\n\t\treturn;\n\t}\n\n\t[self performSelectorInCommonModes:@selector(autoConnectPerformConnect) withObject:nil afterDelay:connectDelay];\n}\n\n- (void)autoConnectPerformConnect\n{\n\tif (self.isConnecting || self.isConnected) {\n\t\treturn;\n\t}\n\n\t[self connect];\n}\n\n- (void)autoConnectAfterWakeUp\n{\n\tNSUInteger connectDelay = self.connectDelay;\n\n\tif (connectDelay == 0) {\n\t\t[self autoConnectAfterWakeUpPerformConnect];\n\n\t\treturn;\n\t}\n\n\t[self printDebugInformationToConsole:TXTLS(@\"IRC[3s6-e6]\", connectDelay)];\n\n\t[self performSelectorInCommonModes:@selector(autoConnectAfterWakeUpPerformConnect) withObject:nil afterDelay:connectDelay];\n}\n\n- (void)autoConnectAfterWakeUpPerformConnect\n{\n\tif (self.isConnecting || self.isConnected) {\n\t\treturn;\n\t}\n\n\tself.reconnectEnabledBecauseOfSleepMode = YES;\n\n\t[self connect:IRCClientConnectModeReconnect];\n}\n\n- (void)disconnect\n{\n\t[self cancelPerformRequestsWithSelector:@selector(disconnect) object:nil];\n\n\tif (self.isConnecting == NO && self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tif (self.socket == nil) {\n\t\treturn;\n\t}\n\n\tself.isDisconnecting = YES;\n\n\t[RZNotificationCenter() postNotificationName:IRCClientWillDisconnectNotification object:self];\n\n\t[self.socket close];\n}\n\n- (void)quit\n{\n\tNSString *comment = nil;\n\n\tif (self.disconnectType == IRCClientDisconnectModeComputerSleep) {\n\t\tcomment = self.config.sleepModeLeavingComment;\n\t} else {\n\t\tcomment = self.config.normalLeavingComment;\n\t}\n\n\t[self quitWithComment:comment];\n}\n\n- (void)quitWithComment:(NSString *)comment\n{\n\tNSParameterAssert(comment != nil);\n\n\tif ((self.isConnecting == NO && self.isConnected == NO) || self.isQuitting || self.isDisconnecting) {\n\t\treturn;\n\t}\n\n\tself.isQuitting\t= YES;\n\n\t[self cancelReconnect];\n\n\tif (self.isTerminating == NO) {\n\t\t[self postEventToViewController:@\"serverDisconnecting\"];\n\t}\n\n\t[RZNotificationCenter() postNotificationName:IRCClientWillSendQuitNotification object:self];\n\n\t[self.socket clearSendQueue];\n\n\t/* If -isLoggedIn is NO, then the connection does not need \n\t to be closed gracefully because the user hasn't even joined\n\t a channel yet, so who are we doing it for? */\n\tif (self.isLoggedIn == NO) {\n\t\t[self disconnect];\n\n\t\treturn;\n\t}\n\n\t[self send:@\"QUIT\", comment, nil];\n\n\t/* We give it two seconds before forcefully breaking so that the graceful\n\t quit with the quit message above can be performed. */\n\t[self performSelectorInCommonModes:@selector(disconnect) withObject:nil afterDelay:2.0];\n}\n\n- (void)cancelReconnect\n{\n\tself.reconnectEnabled = NO;\n\tself.reconnectEnabledBecauseOfSleepMode = NO;\n\n\t[self stopReconnectTimer];\n\n\t[mainWindow() updateTitleFor:self];\n}\n\n- (void)changeNickname:(NSString *)newNickname\n{\n\tNSParameterAssert(newNickname != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tif (newNickname.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"NICK\", newNickname, nil];\n}\n\n- (void)joinKickedChannel:(IRCChannel *)channel\n{\n\t[self joinChannel:channel];\n}\n\n- (void)joinChannel:(IRCChannel *)channel\n{\n\t[self joinChannel:channel password:nil];\n}\n\n- (void)joinUnlistedChannel:(NSString *)channel\n{\n\t[self joinUnlistedChannel:channel password:nil];\n}\n\n- (void)joinChannel:(IRCChannel *)channel password:(nullable NSString *)password\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO || channel.isActive) {\n\t\treturn;\n\t}\n\n\tchannel.status = IRCChannelStatusJoining;\n\n\tif (password == nil) {\n\t\tpassword = channel.secretKey;\n\t}\n\n\t[self forceJoinChannel:channel.name password:password];\n}\n\n- (void)joinUnlistedChannel:(NSString *)channel password:(nullable NSString *)password\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ([self stringIsChannelName:channel] == NO) {\n\t\t// Many IRCd (I don't know of any that don't) use \"JOIN 0\" as a\n\t\t// secret way to have the user part all channels they are in.\n\t\tif ([channel isEqualToString:@\"0\"]) {\n\t\t\t[self forceJoinChannel:channel password:password];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tIRCChannel *channelPointer = [self findChannel:channel];\n\n\tif (channelPointer) {\n\t\t[self joinChannel:channelPointer password:password];\n\n\t\treturn;\n\t}\n\n\t[self forceJoinChannel:channel password:password];\n}\n\n- (void)forceJoinChannel:(NSString *)channel password:(nullable NSString *)password\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"JOIN\", channel, password, nil];\n}\n\n- (void)joinUnlistedChannelsWithStringAndSelectBestMatch:(NSString *)channels\n{\n\t[self joinUnlistedChannelsWithStringAndSelectBestMatch:channels passwords:nil];\n}\n\n- (void)joinUnlistedChannelsWithStringAndSelectBestMatch:(NSString *)channels passwords:(nullable NSString *)passwords\n{\n\tNSParameterAssert(channels != nil);\n\n\tif (channels.length == 0) {\n\t\treturn;\n\t}\n\n\tNSArray *targets = [channels componentsSeparatedByString:@\",\"];\n\n\t[self joinUnlistedChannelsAndSelectBestMatch:targets passwords:passwords];\n}\n\n- (void)joinUnlistedChannelsAndSelectBestMatch:(NSArray<NSString *> *)channels\n{\n\t[self joinUnlistedChannelsAndSelectBestMatch:channels passwords:nil];\n}\n\n- (void)joinUnlistedChannelsAndSelectBestMatch:(NSArray<NSString *> *)channels passwords:(nullable NSString *)passwords\n{\n\tNSParameterAssert(channels != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channels.count == 0) {\n\t\treturn;\n\t}\n\n\t__block BOOL performJoin = YES;\n\n\t__block IRCChannel *channelToSelect = nil;\n\n\tfor (NSString *channel in channels) {\n\t\tif (channelToSelect == nil && [self stringIsChannelName:channel]) {\n\t\t\tchannelToSelect = [self findChannelOrCreate:channel];\n\n\t\t\tperformJoin = (channelToSelect.isActive == NO || channels.count > 1);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (performJoin) {\n\t\t[self send:@\"JOIN\", [channels componentsJoinedByString:@\",\"], passwords, nil];\n\t}\n\n\tif (channelToSelect) {\n\t\t[mainWindow() select:channelToSelect];\n\t}\n}\n\n- (void)joinChannels:(NSArray<IRCChannel *> *)channels\n{\n\tNSParameterAssert(channels != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channels.count == 0) {\n\t\treturn;\n\t}\n\n\tNSMutableString *joinStringWithoutKey = nil;\n\tNSMutableString *joinStringWithKey = nil;\n\n\tNSMutableString *keyString = nil;\n\n\tfor (IRCChannel *channel in channels) {\n\t\tif (channel.isChannel == NO || channel.isActive) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tchannel.status = IRCChannelStatusJoining;\n\n\t\tNSString *password = nil;\n\n\t\tif (password == nil) {\n\t\t\tpassword = channel.secretKey;\n\t\t}\n\n\t\tif (password.length == 0) {\n\t\t\tif (joinStringWithoutKey == nil) {\n\t\t\t\tjoinStringWithoutKey = [NSMutableString stringWithString:channel.name];\n\t\t\t} else {\n\t\t\t\t[joinStringWithoutKey appendFormat:@\",%@\", channel.name];\n\t\t\t}\n\t\t} else {\n\t\t\tif (joinStringWithKey == nil) {\n\t\t\t\tjoinStringWithKey = [NSMutableString stringWithString:channel.name];\n\t\t\t} else {\n\t\t\t\t[joinStringWithKey appendFormat:@\",%@\", channel.name];\n\t\t\t}\n\n\t\t\tif (keyString == nil) {\n\t\t\t\tkeyString = [NSMutableString stringWithString:password];\n\t\t\t} else {\n\t\t\t\t[keyString appendFormat:@\",%@\", password];\n\t\t\t}\n\t\t}\n\t}\n\n\tif (joinStringWithoutKey) {\n\t\t[self send:@\"JOIN\", joinStringWithoutKey, nil];\n\t}\n\n\tif (joinStringWithKey && keyString) {\n\t\t[self send:@\"JOIN\", joinStringWithKey, keyString, nil];\n\t}\n}\n\n- (void)partUnlistedChannel:(NSString *)channel\n{\n\t[self partUnlistedChannel:channel withComment:nil];\n}\n\n- (void)partChannel:(IRCChannel *)channel\n{\n\t[self partChannel:channel withComment:nil];\n}\n\n- (void)partUnlistedChannel:(NSString *)channel withComment:(nullable NSString *)comment\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ([self stringIsChannelName:channel] == NO) {\n\t\treturn;\n\t}\n\n\tIRCChannel *channelPointer = [self findChannel:channel];\n\n\tif (channelPointer == nil) {\n\t\treturn;\n\t}\n\n\t[self partChannel:channelPointer withComment:comment];\n}\n\n- (void)partChannel:(IRCChannel *)channel withComment:(nullable NSString *)comment\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.isChannel == NO || channel.isActive == NO) {\n\t\treturn;\n\t}\n\n\tif (comment == nil) {\n\t\tcomment = self.config.normalLeavingComment;\n\t}\n\n\t[self send:@\"PART\", channel.name, comment, nil];\n}\n\n- (void)sendWhoToChannel:(IRCChannel *)channel\n{\n\t[self sendWhoToChannel:channel hideResponse:NO];\n}\n\n- (void)sendWhoToChannel:(IRCChannel *)channel hideResponse:(BOOL)hideResponse\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[self sendWhoToChannelNamed:channel.name hideResponse:hideResponse];\n}\n\n- (void)sendWhoToChannelNamed:(NSString *)channel\n{\n\t[self sendWhoToChannelNamed:channel hideResponse:NO];\n}\n\n- (void)sendWhoToChannelNamed:(NSString *)channel hideResponse:(BOOL)hideResponse\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.length == 0) {\n\t\treturn;\n\t}\n\n\tif (hideResponse == NO) {\n\t\t[self.requestedCommands recordWhoRequestOpenedAsVisible];\n\t} else {\n\t\t[self.requestedCommands recordWhoRequestOpened];\n\t}\n\n\t[self send:@\"WHO\", channel, nil];\n}\n\n- (void)sendWhois:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (nickname.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"WHOIS\", nickname, nickname, nil];\n}\n\n- (void)kick:(NSString *)nickname inChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.isChannel == NO || channel.isActive == NO) {\n\t\treturn;\n\t}\n\n\tif (nickname.length == 0) {\n\t\treturn;\n\t}\n\n\tNSString *reason = [TPCPreferences defaultKickMessage];\n\n\t[self send:@\"KICK\", channel.name, nickname, reason, nil];\n}\n\n- (void)toggleAwayStatusWithComment:(nullable NSString *)comment\n{\n\tif (self.userIsAway) {\n\t\t[self toggleAwayStatus:NO withComment:nil];\n\t} else {\n\t\tif (comment.length == 0) {\n\t\t\tcomment = TXTLS(@\"IRC[xog-in]\");\n\t\t}\n\n\t\t[self toggleAwayStatus:YES withComment:comment];\n\t}\n}\n\n- (void)toggleAwayStatus:(BOOL)setAway\n{\n\tNSString *comment = TXTLS(@\"IRC[xog-in]\");\n\n\t[self toggleAwayStatus:setAway withComment:comment];\n}\n\n- (void)toggleAwayStatus:(BOOL)setAway withComment:(nullable NSString *)comment\n{\n\tNSParameterAssert(setAway == NO || comment != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (setAway) {\n\t\t[self send:@\"AWAY\", comment, nil];\n\t} else {\n\t\t[self send:@\"AWAY\", nil];\n\t}\n\n\tNSString *newNickname = nil;\n\n\tif (setAway) {\n\t\tnewNickname = self.config.awayNickname;\n\n\t\tself.preAwayUserNickname = self.userNickname;\n\t} else {\n\t\tnewNickname = self.preAwayUserNickname;\n\n\t\tself.preAwayUserNickname = nil;\n\n\t\t/* If we have an away nickname configured but no preAwayNickname set,\n\t\t then use the configured nickname instead. User probably was on bouncer\n\t\t and relaunched Textual, losing preAwayNickname.*/\n\t\tif (newNickname == nil && self.config.awayNickname.length > 0) {\n\t\t\tnewNickname = self.config.nickname;\n\t\t}\n\t}\n\n\tif (newNickname) {\n\t\t[self changeNickname:newNickname];\n\t}\n}\n\n- (void)presentCertificateTrustInformation\n{\n\tif (self.isSecured == NO) {\n\t\treturn;\n\t}\n\n\t[self.socket openSecuredConnectionCertificateModal];\n}\n\n- (void)requestModesForChannel:(IRCChannel *)channel\n{\n\t[self sendModes:nil withParameters:nil inChannel:channel];\n}\n\n- (void)requestModesForChannelNamed:(NSString *)channel\n{\n\t[self sendModes:nil withParameters:nil inChannelNamed:channel];\n}\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray<NSString *> *)parameters inChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[self sendModes:modeSymbols withParameters:parameters inChannelNamed:channel.name];\n}\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[self sendModes:modeSymbols withParametersString:parametersString inChannelNamed:channel.name];\n}\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParameters:(nullable NSArray<NSString *> *)parameters inChannelNamed:(NSString *)channel\n{\n\tNSString *parametersString = [parameters componentsJoinedByString:@\" \"];\n\n\t[self sendModes:modeSymbols withParametersString:parametersString inChannelNamed:channel];\n}\n\n- (void)sendModes:(nullable NSString *)modeSymbols withParametersString:(nullable NSString *)parametersString inChannelNamed:(NSString *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"MODE\", channel, modeSymbols, parametersString, nil];\n}\n\n- (void)sendPing:(NSString *)tokenString\n{\n\tNSParameterAssert(tokenString != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\t[self send:@\"PING\", tokenString, nil];\n}\n\n- (void)sendPong:(NSString *)tokenString\n{\n\tNSParameterAssert(tokenString != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\t[self send:@\"PONG\", tokenString, nil];\n}\n\n- (void)sendInviteTo:(NSString *)nickname toJoinChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t[self sendInviteTo:nickname toJoinChannelNamed:channel.name];\n}\n\n- (void)sendInviteTo:(NSString *)nickname toJoinChannelNamed:(NSString *)channel\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(channel != nil);\n\n\tif (nickname.length == 0 || channel.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"INVITE\", nickname, channel, nil];\n}\n\n- (void)requestTopicForChannel:(IRCChannel *)channel\n{\n\t[self sendTopicTo:nil inChannel:channel];\n}\n\n- (void)requestTopicForChannelNamed:(NSString *)channel\n{\n\t[self sendTopicTo:nil inChannelNamed:channel];\n}\n\n- (void)sendTopicTo:(nullable NSString *)topic inChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO || channel.isActive == NO) {\n\t\treturn;\n\t}\n\n\t[self sendTopicTo:topic inChannelNamed:channel.name];\n}\n\n- (void)sendTopicTo:(nullable NSString *)topic inChannelNamed:(NSString *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (channel.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"TOPIC\", channel, topic, nil];\n}\n\n- (void)sendCapability:(NSString *)subcommand data:(nullable NSString *)data\n{\n\tNSParameterAssert(subcommand != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\t[self send:@\"CAP\", subcommand, data, nil];\n}\n\n- (void)sendCapabilityAuthenticate:(NSString *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tif (data.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"AUTHENTICATE\", data, nil];\n}\n\n- (void)sendIsonForNicknames:(NSArray<NSString *> *)nicknames\n{\n\t[self sendIsonForNicknames:nicknames hideResponse:NO];\n}\n\n- (void)sendIsonForNicknames:(NSArray<NSString *> *)nicknames hideResponse:(BOOL)hideResponse\n{\n\tNSParameterAssert(nicknames != nil);\n\n\t/* Split nicknames into fixed number per-command in case there are a lot or are long. */\n\t/* June 11, 2018: Disabled this because Textual expects nicknames to appear in ISON\n\t response or they are considered offline. If we chunk out results, then user may\n\t disappear in one ISON response and then appear in another. The long term solution\n\t is to stop relying on ISON but no idea when that will come. */\n//\t[nicknames enumerateSubarraysOfSize:8 usingBlock:^(NSArray *objects, BOOL *stop) {\n\t\t[self _sendIsonForNicknames:nicknames hideResponse:hideResponse];\n//\t}];\n}\n\n- (void)_sendIsonForNicknames:(NSArray<NSString *> *)nicknames hideResponse:(BOOL)hideResponse\n{\n\tNSParameterAssert(nicknames != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\tif (hideResponse == NO) {\n\t\t[self.requestedCommands recordIsonRequestOpenedAsVisible];\n\t} else {\n\t\t[self.requestedCommands recordIsonRequestOpened];\n\t}\n\n\tNSString *nicknamesString = [nicknames componentsJoinedByString:@\" \"];\n\n\t[self send:@\"ISON\", nicknamesString, nil];\n}\n\n- (void)requestChannelList\n{\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\t[self send:@\"LIST\", nil];\n}\n\n- (void)sendPassword:(NSString *)password\n{\n\tNSParameterAssert(password != nil);\n\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\tif (password.length == 0) {\n\t\treturn;\n\t}\n\n\t[self send:@\"PASS\", password, nil];\n}\n\n- (void)modifyWatchListBy:(BOOL)adding nicknames:(NSArray<NSString *> *)nicknames\n{\n\tNSParameterAssert(nicknames != nil);\n\n\t/* Split nicknames into fixed number per-command in case there are a lot or are long. */\n\t[nicknames enumerateSubarraysOfSize:8 usingBlock:^(NSArray *objects, BOOL *stop) {\n\t\t[self _modifyWatchListBy:adding nicknames:objects];\n\t}];\n}\n\n- (void)_modifyWatchListBy:(BOOL)adding nicknames:(NSArray<NSString *> *)nicknames\n{\n\tNSParameterAssert(nicknames != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tif (nicknames.count == 0) {\n\t\treturn;\n\t}\n\n\tNSString *modifier = nil;\n\n\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityMonitorCommand])\n\t{\n\t\tif (adding) {\n\t\t\tmodifier = @\"+\";\n\t\t} else {\n\t\t\tmodifier = @\"-\";\n\t\t}\n\n\t\tNSString *nicknamesString = [nicknames componentsJoinedByString:@\",\"];\n\n\t\t[self send:@\"MONITOR\", modifier, nicknamesString, nil];\n\t}\n\telse if ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityWatchCommand])\n\t{\n\t\tif (adding) {\n\t\t\tmodifier = @\" +\";\n\t\t} else {\n\t\t\tmodifier = @\" -\";\n\t\t}\n\n\t\tNSString *nicknamesString = [nicknames componentsJoinedByString:modifier];\n\n\t\t[self send:@\"WATCH\", [modifier stringByAppendingString:nicknamesString], nil];\n\t}\n}\n\n#pragma mark -\n#pragma mark File Transfers\n\n- (void)notifyFileTransfer:(TXNotificationType)type nickname:(NSString *)nickname filename:(NSString *)filename filesize:(uint64_t)totalFilesize requestIdentifier:(NSString *)identifier\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(filename != nil);\n\tNSParameterAssert(identifier != nil);\n\n\tNSString *description = nil;\n\n\tswitch (type) {\n\t\tcase TXNotificationTypeFileTransferSendSuccessful:\n\t\t{\n\t\t\tdescription = TXTLS(@\"Notifications[fhn-dd]\", filename, totalFilesize);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveSuccessful:\n\t\t{\n\t\t\tdescription = TXTLS(@\"Notifications[oqh-pn]\", filename, totalFilesize);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferSendFailed:\n\t\t{\n\t\t\tdescription = TXTLS(@\"Notifications[9r4-cq]\", filename);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveFailed:\n\t\t{\n\t\t\tdescription = TXTLS(@\"Notifications[cqq-ci]\", filename);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveRequested:\n\t\t{\n\t\t\tdescription = TXTLS(@\"Notifications[wik-wq]\", filename, totalFilesize);\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tNSDictionary *info = @{\n\t   @\"isFileTransferNotification\" : @(YES),\n\t   @\"fileTransferUniqueIdentifier\" : identifier,\n\t   @\"fileTransferNotificationType\" : @(type)\n\t};\n\n\t[self notifyEvent:type lineType:TVCLogLineTypeUndefined target:nil nickname:nickname text:description userInfo:info];\n}\n\n- (void)receivedDCCQuery:(IRCMessage *)m text:(NSString *)text ignoreInfo:(nullable IRCAddressBookEntry *)ignoreInfo\n{\n\tNSParameterAssert(m != nil);\n\tNSParameterAssert(text != nil);\n\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\t/* Do not continue if the user has configured an ignore for file transfers */\n\tif (ignoreInfo.ignoreFileTransferRequests) {\n\t\treturn;\n\t}\n\n\t/* Do not continue if we are not the target */\n\tif ([self nicknameIsMyself:[m paramAt:0]] == NO) {\n\t\treturn;\n\t}\n\n\t/* Record information */\n\tNSString *sender = m.senderNickname;\n\n\tNSMutableString *textMutable = [text mutableCopy];\n\n\tNSString *subcommand = textMutable.uppercaseGetToken;\n\n\tBOOL isSendRequest = ([subcommand isEqualToString:@\"SEND\"]);\n\tBOOL isResumeRequest = ([subcommand isEqualToString:@\"RESUME\"]);\n\tBOOL isAcceptRequest = ([subcommand isEqualToString:@\"ACCEPT\"]);\n\n\tif (isSendRequest == NO && isResumeRequest == NO && isAcceptRequest == NO) {\n\t\treturn;\n\t}\n\n\tNSString *section1 = nil;\n\n\tif ([textMutable hasPrefix:@\"\\\"\"]) {\n\t\tsection1 = textMutable.tokenInsideQuotes;\n\t} else {\n\t\tsection1 = textMutable.token;\n\t}\n\n\tNSString *section2 = textMutable.token;\n\tNSString *section3 = textMutable.token;\n\tNSString *section4 = textMutable.token;\n\tNSString *section5 = textMutable.token;\n\n\t/* Trim whitespaces in case someone tries to send blank \n\t spaces in a quoted string for filename. */\n\tsection1 = section1.trim;\n\n\t/* Remove T from in front of token if it is there. */\n\tif (isSendRequest) {\n\t\tif ([section5 hasPrefix:@\"T\"]) {\n\t\t\tsection5 = [section5 substringFromIndex:1];\n\t\t}\n\t} else if (isAcceptRequest || isResumeRequest) {\n\t   if ([section4 hasPrefix:@\"T\"]) {\n\t\t\tsection4 = [section4 substringFromIndex:1];\n\t   }\n\t}\n\n\t/* Valid values? */\n\tif ( section1.length == 0 ||\n\t\t section2.length == 0 ||\n\t\t(section4.length == 0 && isSendRequest))\n\t{\n\t\treturn;\n\t}\n\n\t/* Start data association. */\n\tNSString *hostAddress = nil;\n\tNSString *hostPort = nil;\n\tNSString *filename = nil;\n\tNSString *filesize = nil;\n\tNSString *transferToken = nil;\n\n\t/* Match data variables. */\n\tif (isSendRequest)\n\t{\n\t\t/* Get normal information */\n\t\tfilename = section1.safeFilename;\n\n\t\tfilesize = section4;\n\n\t\thostPort = section3;\n\n\t\ttransferToken = section5;\n\n\t\t/* Translate host address */\n\t\tif (section2.numericOnly) {\n\t\t\tlong long a = section2.longLongValue;\n\n\t\t\tNSInteger w = (a & 0xff); a >>= 8;\n\t\t\tNSInteger x = (a & 0xff); a >>= 8;\n\t\t\tNSInteger y = (a & 0xff); a >>= 8;\n\t\t\tNSInteger z = (a & 0xff);\n\n\t\t\thostAddress = [NSString stringWithFormat:@\"%ld.%ld.%ld.%ld\", (long)z, (long)y, (long)x, (long)w];\n\t\t} else {\n\t\t\thostAddress = section2;\n\t\t}\n\t}\n\telse if (isResumeRequest || isAcceptRequest)\n\t{\n\t\tfilename = section1.safeFilename;\n\n\t\tfilesize = section3;\n\n\t\thostPort = section2;\n\n\t\ttransferToken = section4;\n\n\t\thostAddress = nil;\n\t}\n\n\tif (transferToken && transferToken.length == 0) {\n\t\ttransferToken = nil;\n\t}\n\n\t/* Important checks */\n\tif (transferToken.length > 0 && transferToken.numericOnly == NO) {\n\t\tLogToConsoleError(\"Fatal error: Received transfer token that is not a number\");\n\n\t\tgoto present_error;\n\t}\n\n\tNSInteger hostPortInt = hostPort.integerValue;\n\n\tif (hostPortInt == 0 && transferToken == nil) {\n\t\tLogToConsoleError(\"Fatal error: Port cannot be zero without a transfer token\");\n\n\t\tgoto present_error;\n\t} else if (hostPortInt < 0 || hostPortInt > TXMaximumTCPPort) {\n\t\tLogToConsoleError(\"Fatal error: Port cannot be less than zero or greater than 65535\");\n\n\t\tgoto present_error;\n\t}\n\n\tlong long filesizeInt = filesize.longLongValue;\n\n\tif (filesizeInt <= 0 || filesizeInt > powl(1000, 4)) { // 1 TB\n\t\tLogToConsoleError(\"Fatal error: Filesize is silly\");\n\n\t\tgoto present_error;\n\t}\n\n\t/* Process individual commands */\n\tif (isSendRequest) {\n\t\t/* DCC SEND <filename> <peer-ip> <port> <filesize> [token] */\n\n\t\tif (transferToken) {\n\t\t\tTDCFileTransferDialogTransferController *e = [[self fileTransferController] fileTransferSenderMatchingToken:transferToken];\n\n\t\t\t/* 0 port indicates a new request in reverse DCC */\n\t\t\tif (hostPortInt == 0)\n\t\t\t{\n\t\t\t\tif (e != nil) {\n\t\t\t\t\tLogToConsoleError(\"Fatal error: Received reverse DCC request with token '%{public}@' but the token already exists\", transferToken);\n\n\t\t\t\t\tgoto present_error;\n\t\t\t\t}\n\n\t\t\t\t[self receivedDCCSend:sender\n\t\t\t\t\t\t\t filename:filename\n\t\t\t\t\t\t\t  address:hostAddress\n\t\t\t\t\t\t\t\t port:hostPortInt\n\t\t\t\t\t\t\t filesize:filesizeInt\n\t\t\t\t\t\t\t\ttoken:transferToken];\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse if (e)\n\t\t\t{\n\t\t\t\tif (e.transferStatus != TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept) {\n\t\t\t\t\tLogToConsoleError(\"Fatal error: Unexpected request to begin transfer\");\n\n\t\t\t\t\tgoto present_error;\n\t\t\t\t}\n\n\t\t\t\t[e didReceiveSendRequest:hostAddress hostPort:hostPortInt];\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse // transferToken\n\t\t{\n\t\t\t/* Treat as normal DCC request */\n\t\t\t[self receivedDCCSend:sender\n\t\t\t\t\t\t filename:filename\n\t\t\t\t\t\t  address:hostAddress\n\t\t\t\t\t\t\t port:hostPort.integerValue\n\t\t\t\t\t\t filesize:filesize.longLongValue\n\t\t\t\t\t\t\ttoken:nil];\n\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (isResumeRequest || isAcceptRequest)\n\t{\n\t\tTDCFileTransferDialogTransferController *e = nil;\n\n\t\tif (transferToken && hostPortInt == 0) {\n\t\t\te = [[self fileTransferController] fileTransferSenderMatchingToken:transferToken];\n\t\t} else if (transferToken == nil && hostPortInt > 0) {\n\t\t\te = [[self fileTransferController] fileTransferMatchingPort:hostPortInt];\n\t\t}\n\n\t\tif (e == nil) {\n\t\t\tLogToConsoleError(\"Fatal error: Could not locate file transfer that matches resume request\");\n\n\t\t\tgoto present_error;\n\t\t}\n\n\t\tif ((isResumeRequest && (e.transferStatus != TDCFileTransferDialogTransferStatusWaitingForReceiverToAccept &&\n\t\t\t\t\t\t\t\t e.transferStatus != TDCFileTransferDialogTransferStatusIsListeningAsSender)) ||\n\t\t\t(isAcceptRequest && e.transferStatus != TDCFileTransferDialogTransferStatusWaitingForResumeAccept))\n\t\t{\n\t\t\tLogToConsoleError(\"Fatal error: Bad transfer status\");\n\n\t\t\tgoto present_error;\n\t\t}\n\n\t\tif (isResumeRequest) {\n\t\t\t[e didReceiveResumeRequest:filesizeInt];\n\t\t} else {\n\t\t\t[e didReceiveResumeAccept:filesizeInt];\n\t\t}\n\n\t\treturn;\n\t}\n\n\t// Report an error\npresent_error:\n\t[self print:TXTLS(@\"IRC[y3w-la]\", sender) by:nil inChannel:nil asType:TVCLogLineTypeDCCFileTransfer command:TVCLogLineDefaultCommandValue];\n}\n\n- (void)receivedDCCSend:(NSString *)nickname filename:(NSString *)filename address:(NSString *)address port:(uint16_t)port filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(filename != nil);\n\tNSParameterAssert(address != nil);\n\n\tNSString *message = TXTLS(@\"IRC[snf-45]\", nickname, filename, totalFilesize);\n\n\t[self print:message by:nil inChannel:nil asType:TVCLogLineTypeDCCFileTransfer command:TVCLogLineDefaultCommandValue];\n\n\tif ([TPCPreferences fileTransferRequestReplyAction] == TXFileTransferRequestReplyIgnore) {\n\t\treturn;\n\t}\n\n\tNSString *addedRequest = [[self fileTransferController] addReceiverForClient:self nickname:nickname address:address port:port filename:filename filesize:totalFilesize token:transferToken];\n\n\tif (addedRequest == nil) {\n\t\treturn;\n\t}\n\n\t[self notifyFileTransfer:TXNotificationTypeFileTransferReceiveRequested nickname:nickname filename:filename filesize:totalFilesize requestIdentifier:addedRequest];\n}\n\n- (void)sendFileResume:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(filename != nil);\n\n\tNSString *escapedFilename = [self DCCSendEscapeFilename:filename];\n\n\tNSString *stringToSend = nil;\n\n\tif (transferToken) {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %hu %lli %@\", escapedFilename, port, totalFilesize, transferToken];\n\t} else {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %hu %lli\", escapedFilename, port, totalFilesize];\n\t}\n\n\t[self sendCTCPQuery:nickname command:@\"DCC RESUME\" text:stringToSend];\n}\n\n- (void)sendFileResumeAccept:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(filename != nil);\n\n\tNSString *escapedFilename = [self DCCSendEscapeFilename:filename];\n\n\tNSString *stringToSend = nil;\n\n\tif (transferToken) {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %hu %lli %@\", escapedFilename, port, totalFilesize, transferToken];\n\t} else {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %hu %lli\", escapedFilename, port, totalFilesize];\n\t}\n\n\t[self sendCTCPQuery:nickname command:@\"DCC ACCEPT\" text:stringToSend];\n}\n\n- (void)sendFile:(NSString *)nickname port:(uint16_t)port filename:(NSString *)filename filesize:(uint64_t)totalFilesize token:(nullable NSString *)transferToken\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(filename != nil);\n\n\tNSString *address = [self DCCTransferAddress];\n\n\tif (address == nil) {\n\t\treturn;\n\t}\n\n\tNSString *escapedFilename = [self DCCSendEscapeFilename:filename];\n\n\tNSString *stringToSend = nil;\n\n\tif (transferToken.length > 0) {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %@ %hu %lli %@\", escapedFilename, address, port, totalFilesize, transferToken];\n\t} else {\n\t\tstringToSend = [NSString stringWithFormat:@\"%@ %@ %hu %lli\", escapedFilename, address, port, totalFilesize];\n\t}\n\n\t[self sendCTCPQuery:nickname command:@\"DCC SEND\" text:stringToSend];\n\n\tNSString *message = TXTLS(@\"IRC[ags-s8]\", nickname, filename, totalFilesize);\n\n\t[self print:message by:nil inChannel:nil asType:TVCLogLineTypeDCCFileTransfer command:TVCLogLineDefaultCommandValue];\n}\n\n- (NSString *)DCCSendEscapeFilename:(NSString *)filename\n{\n\tNSParameterAssert(filename != nil);\n\n\tNSString *filenameEscaped = filename.safeFilename;\n\n\tif ([filenameEscaped contains:@\" \"] == NO) {\n\t\treturn filenameEscaped;\n\t}\n\t\n\t/* Escape double quotes because the filename will be wrapped.\n\t February 20, 2017: Maybe we should replace the double quote\n\t with another character or remove completely? Untested how other\n\t clients will handle an escaped double quote. */\n\tfilenameEscaped = [filenameEscaped stringByReplacingOccurrencesOfString:@\"\\\"\" withString:@\"\\\\\\\"\"];\n\n\treturn [NSString stringWithFormat:@\"\\\"%@\\\"\", filenameEscaped];\n}\n\n- (nullable NSString *)DCCTransferAddress\n{\n\tNSString *address = [self fileTransferController].IPAddress;\n\n\tif (address == nil) {\n\t\treturn nil;\n\t}\n\n\tif (address.IPv6Address) {\n\t\treturn address;\n\t}\n\n\tNSArray *addressOctets = [address componentsSeparatedByString:@\".\"];\n\n\tif (addressOctets.count != 4) {\n\t\tLogToConsoleError(\"User configured a silly IP address\");\n\n\t\treturn nil;\n\t}\n\n\tNSInteger w = [addressOctets[0] integerValue];\n\tNSInteger x = [addressOctets[1] integerValue];\n\tNSInteger y = [addressOctets[2] integerValue];\n\tNSInteger z = [addressOctets[3] integerValue];\n\n\tunsigned long long a = 0;\n\n\ta |= w; a <<= 8;\n\ta |= x; a <<= 8;\n\ta |= y; a <<= 8;\n\ta |= z;\n\n\treturn [NSString stringWithFormat:@\"%llu\", a];\n}\n\n#pragma mark -\n#pragma mark Command Queue\n\n- (NSString *)descriptionForTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\tNSString *timerInterval = TXHumanReadableTimeInterval(timedCommand.timerInterval, NO, 0);\n\n\tNSString *timeRemaining = TXHumanReadableTimeInterval(timedCommand.timeRemaining, NO, 0);\n\n\tNSString *timerStatus = nil;\n\n\tif (timedCommand.timerIsActive == NO) {\n\t\ttimerStatus = TXTLS(@\"IRC[ww4-sn]\");\n\t} else {\n\t\ttimerStatus = TXTLS(@\"IRC[bhz-9e]\");\n\t}\n\n\tif (timedCommand.repeatTimer == NO) {\n\t\treturn TXTLS(@\"IRC[4n6-2x]\",\n\t\t\t\t\t timedCommand.identifier,\n\t\t\t\t\t timerStatus,\n\t\t\t\t\t timerInterval,\n\t\t\t\t\t timeRemaining,\n\t\t\t\t\t timedCommand.command);\n\t} else {\n\t\tNSUInteger repeatLimit = timedCommand.iterations;\n\n\t\tNSString *repeatLimitDescriptor = nil;\n\n\t\tif (repeatLimit == 0) {\n\t\t\trepeatLimitDescriptor = TXTLS(@\"IRC[o26-ae]\");\n\t\t} else {\n\t\t\trepeatLimitDescriptor = [NSString stringWithUnsignedInteger:repeatLimit];\n\t\t}\n\n\t\treturn TXTLS(@\"IRC[uw0-v2]\",\n\t\t\t\t\t timedCommand.identifier,\n\t\t\t\t\t timerStatus,\n\t\t\t\t\t timerInterval,\n\t\t\t\t\t timeRemaining,\n\t\t\t\t\t repeatLimitDescriptor,\n\t\t\t\t\t timedCommand.currentIteration,\n\t\t\t\t\t timedCommand.command);\n\t}\n}\n\n- (nullable IRCTimedCommand *)timedCommandWithIdentifier:(NSString *)identifier\n{\n\tNSParameterAssert(identifier != nil);\n\n\t@synchronized (self.timedCommands) {\n\t\treturn self.timedCommands[identifier];\n\t}\n}\n\n- (NSArray<IRCTimedCommand *> *)listOfTimedCommands\n{\n\t@synchronized (self.timedCommands) {\n\t\treturn self.timedCommands.allValues;\n\t}\n}\n\n- (void)addTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t@synchronized (self.timedCommands) {\n\t\tself.timedCommands[timedCommand.identifier] = timedCommand;\n\t}\n}\n\n- (void)removeTimedCommands\n{\n\t@synchronized (self.timedCommands) {\n\t\t[self.timedCommands removeAllObjects];\n\t}\n}\n\n- (void)removeTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t@synchronized (self.timedCommands) {\n\t\t[self.timedCommands removeObjectForKey:timedCommand.identifier];\n\t}\n}\n\n- (void)stopTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t[timedCommand stop];\n}\n\n- (void)startTimedCommand:(IRCTimedCommand *)timedCommand interval:(NSUInteger)timerInterval\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t[self startTimedCommand:timedCommand interval:timerInterval onRepeat:NO iterations:0];\n}\n\n- (void)startTimedCommand:(IRCTimedCommand *)timedCommand interval:(NSUInteger)timerInterval onRepeat:(BOOL)repeatTimer\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t[self startTimedCommand:timedCommand interval:timerInterval onRepeat:repeatTimer iterations:0];\n}\n\n- (void)startTimedCommand:(IRCTimedCommand *)timedCommand interval:(NSUInteger)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t[timedCommand start:timerInterval onRepeat:repeatTimer iterations:iterations];\n}\n\n- (BOOL)restartTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\treturn [timedCommand restart];\n}\n\n- (void)onTimedCommand:(IRCTimedCommand *)timedCommand\n{\n\tNSParameterAssert(timedCommand != nil);\n\n\t/* Remove timer */\n\tif (timedCommand.timerIsActive == NO) {\n\t\t[self removeTimedCommand:timedCommand];\n\t}\n\n\t/* The -channelId is only a suggestion. It's okay if this returns nil.\n\t The channel is what was selected at the time that the timer was created.\n\t -sendCommand:completeTarget:target: may very well ignore the channel we\n\t give it, even if it's non-nil, depending on format of command. */\n\tIRCChannel *channel = (IRCChannel *)[worldController() findItemWithId:timedCommand.channelId];\n\n\t[self sendCommand:timedCommand.command completeTarget:YES target:channel.name];\n}\n\n#pragma mark -\n#pragma mark User Tracking\n\n- (void)clearTrackedUsers\n{\n\t[self.trackedUsers clearTrackedUsers];\n}\n\n- (void)statusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus\n{\n\t[self statusOfTrackedNickname:nickname changedTo:newStatus notify:NO];\n}\n\n- (void)statusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus notify:(BOOL)notify\n{\n\tNSParameterAssert(nickname != nil);\n\n\t[self.trackedUsers statusOfTrackedNickname:nickname changedTo:newStatus];\n\n\tif (notify) {\n\t\t[self notifyStatusOfTrackedNickname:nickname changedTo:newStatus];\n\t}\n}\n\n- (void)notifyStatusOfTrackedNickname:(NSString *)nickname changedTo:(IRCAddressBookUserTrackingStatus)newStatus\n{\n\tNSParameterAssert(nickname != nil);\n\n\tNSString *message = nil;\n\n\tif (newStatus == IRCAddressBookUserTrackingStatusSignedOn) {\n\t\tmessage = TXTLS(@\"Notifications[xk2-1l]\", nickname);\n\t} else if (newStatus == IRCAddressBookUserTrackingStatusSignedOff) {\n\t\tmessage = TXTLS(@\"Notifications[rif-9r]\", nickname);\n\t} else if (newStatus == IRCAddressBookUserTrackingStatusAvailable) {\n\t\tmessage = TXTLS(@\"Notifications[97r-0l]\", nickname);\n\t}\n\n\tif (message == nil) {\n\t\treturn;\n\t}\n\n\t[self notifyEvent:TXNotificationTypeAddressBookMatch lineType:TVCLogLineTypeNotice target:nil nickname:nickname text:message];\n}\n\n- (void)populateISONTrackedUsersList\n{\n\tif (self.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\t/* Additions & Removals for WATCH command. ISON does not access these. */\n\tNSMutableArray<NSString *> *watchAdditions = [NSMutableArray array];\n\tNSMutableArray<NSString *> *watchRemovals = [NSMutableArray array];\n\n\t/* Compare configuration to the list of tracked nicknames.\n\t * Nicknames that are new are added to watchAdditions */\n\tNSDictionary *trackedUsersOld = self.trackedUsers.trackedUsers;\n\n\tNSMutableArray<NSString *> *trackedUsersNew = [NSMutableArray array];\n\n\tfor (IRCAddressBookEntry *g in self.config.ignoreList) {\n\t\tif (g.trackUserActivity == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *trackingNickname = g.trackingNickname;\n\n\t\tIRCAddressBookUserTrackingStatus trackingStatus = [self.trackedUsers statusOfUser:trackingNickname];\n\n\t\tif (trackingStatus != IRCAddressBookUserTrackingStatusUnknown) {\n\t\t\t[trackedUsersNew addObject:trackingNickname];\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t[watchAdditions addObject:trackingNickname];\n\n\t\t[self.trackedUsers _addTrackedUser:trackingNickname];\n\t}\n\n\t/* Compare old list of tracked nicknames to new list to find\n\t those that no longer appear. Mark those for removal. */\n\tfor (NSString *trackedUser in trackedUsersOld) {\n\t\tif ([trackedUsersNew containsObjectIgnoringCase:trackedUser]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[watchRemovals addObject:trackedUser];\n\n\t\t[self.trackedUsers _removeTrackedUser:trackedUser];\n\t}\n\n\t/* Set new entries */\n\t[self modifyWatchListBy:YES nicknames:watchAdditions];\n\n\t[self modifyWatchListBy:NO nicknames:watchRemovals];\n\n\t[self startISONTimer];\n}\n\n- (void)startISONTimer\n{\n\tif (self.isonTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.isonTimer start:_isonCheckInterval onRepeat:YES];\n\n\t[self startWhoTimer];\n}\n\n- (void)stopISONTimer\n{\n\tif (self.isonTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.isonTimer stop];\n\n\t[self stopWhoTimer];\n}\n\n- (void)onISONTimer\n{\n\tif (self.isLoggedIn == NO || self.isBrokenIRCd_aka_Twitch) {\n\t\treturn;\n\t}\n\n\tNSMutableArray<NSString *> *nicknames = [NSMutableArray array];\n\n\t// Request ISON status for tracked users\n\tif (self.supportsAdvancedTracking == NO) {\n\t\tfor (NSString *trackedUser in self.trackedUsers.trackedUsers) {\n\t\t\t[nicknames addObject:trackedUser];\n\t\t}\n\t}\n\n\t// Request ISON status for private messages\n\tfor (IRCChannel *channel in self.channelList) {\n\t\tif (channel.privateMessage) {\n\t\t\t[nicknames addObject:channel.name];\n\t\t}\n\t}\n\n\t[self sendIsonForNicknames:nicknames hideResponse:YES];\n}\n\n- (void)startWhoTimer\n{\n\tif (self.whoTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[self.whoTimer start:_whoCheckInterval onRepeat:YES];\n}\n\n- (void)stopWhoTimer\n{\n\tif (self.whoTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[self.whoTimer stop];\n}\n\n- (void)onWhoTimer\n{\n\tif (self.isLoggedIn == NO || self.isBrokenIRCd_aka_Twitch) {\n\t\treturn;\n\t}\n\n\tNSArray *channelList = self.channelList;\n\n\t[self sendTimedWhoRequestsToChannels:channelList];\n}\n\n- (void)sendTimedWhoRequestsToChannels:(NSArray<IRCChannel *> *)channelList\n{\n\tNSParameterAssert(channelList != nil);\n\n\tif (self.isLoggedIn == NO || self.isBrokenIRCd_aka_Twitch) {\n\t\treturn;\n\t}\n\n#define _maximumChannelCountPerWhoBatchRequest\t\t\t4\n#define _maximumSingleChannelSizePerWhoBatchRequest\t\t5000\n#define _maximumTotalChannelSizePerWhoBatchRequest\t\t2000\n\n\tNSUInteger channelCount = channelList.count;\n\n\tif (channelCount == 0) {\n\t\treturn;\n\t}\n\n\tNSUInteger startingPosition = self.lastWhoRequestChannelListIndex;\n\n\tNSUInteger endingPosition = (startingPosition + _maximumChannelCountPerWhoBatchRequest);\n\n\tif (startingPosition >= channelCount) {\n\t\tstartingPosition = 0;\n\t}\n\n\tif (endingPosition >= channelCount) {\n\t\tendingPosition = (channelCount - 1);\n\t}\n\n\tNSUInteger totalMemberCount = 0;\n\n\tNSMutableArray<IRCChannel *> *channelsToQuery = nil;\n\n\tfor (NSUInteger channelIndex = startingPosition; channelIndex <= endingPosition; channelIndex++) {\n\t\tIRCChannel *channel = channelList[channelIndex];\n\n\t\tif (channel.isActive == NO || channel.isChannel == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Update internal state of flag */\n\t\tBOOL sentInitialWhoRequest = channel.sentInitialWhoRequest;\n\n\t\tif (sentInitialWhoRequest == NO) {\n\t\t\tchannel.sentInitialWhoRequest = YES;\n\t\t}\n\n\t\t/* continue to next channel and do not break so that the\n\t\t -sentInitialWhoRequest flag of all channels can be updated. */\n\t\tif (self.config.sendWhoCommandRequestsToChannels == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Perform comparisons to know whether channel is acceptable */\n\t\tNSUInteger numberOfMembers = channel.numberOfMembers;\n\n\t\tif (sentInitialWhoRequest == NO) {\n\t\t\tif (numberOfMembers > _maximumSingleChannelSizePerWhoBatchRequest) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t} else {\n\t\t\tif ([self isCapabilityEnabled:ClientIRCv3SupportedCapabilityAwayNotify]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (numberOfMembers > [TPCPreferences trackUserAwayStatusMaximumChannelSize]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t/* Add channel to list */\n\t\tif (channelsToQuery == nil) {\n\t\t\tchannelsToQuery = [NSMutableArray new];\n\t\t}\n\n\t\t[channelsToQuery addObject:channel];\n\n\t\t/* Update total number of members and maybe break loop */\n\t\ttotalMemberCount += numberOfMembers;\n\n\t\tif (totalMemberCount > _maximumTotalChannelSizePerWhoBatchRequest) {\n\t\t\tendingPosition = channelIndex;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tself.lastWhoRequestChannelListIndex = (endingPosition + 1);\n\n\t/* Send WHO requests */\n\tif (channelsToQuery == nil) {\n\t\treturn;\n\t}\n\n\tfor (IRCChannel *channel in channelsToQuery) {\n\t\t[self sendWhoToChannel:channel hideResponse:YES];\n\t}\n\n#undef _maximumChannelCountPerWhoBatchRequest\n#undef _maximumSingleChannelSizePerWhoBatchRequest\n#undef _maximumTotalChannelSizePerWhoBatchRequest\n}\n\n- (void)updateUserTrackingStatusForEntry:(IRCAddressBookEntry *)addressBookEntry withMessage:(IRCMessage *)message\n{\n\tNSParameterAssert(addressBookEntry != nil);\n\tNSParameterAssert(message != nil);\n\n\tif (self.supportsAdvancedTracking) {\n\t\treturn;\n\t}\n\n\tIRCAddressBookUserTrackingStatus trackingStatus = [self.trackedUsers statusOfEntry:addressBookEntry];\n\n\tif (trackingStatus == IRCAddressBookUserTrackingStatusUnknown) {\n\t\treturn;\n\t}\n\n\tBOOL ison = (trackingStatus == IRCAddressBookUserTrackingStatusAvailable);\n\n\t/* Notification Type: JOIN Command */\n\tif ([message.command isEqualToStringIgnoringCase:@\"JOIN\"]) {\n\t\tif (ison == NO) {\n\t\t\t[self statusOfTrackedNickname:message.senderNickname changedTo:IRCAddressBookUserTrackingStatusSignedOn notify:YES];\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Notification Type: QUIT Command */\n\tif ([message.command isEqualToStringIgnoringCase:@\"QUIT\"]) {\n\t\tif (ison) {\n\t\t\t[self statusOfTrackedNickname:message.senderNickname changedTo:IRCAddressBookUserTrackingStatusSignedOff notify:YES];\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* Notification Type: NICK Command */\n\tif ([message.command isEqualToStringIgnoringCase:@\"NICK\"]) {\n\t\tif (ison) {\n\t\t\t[self statusOfTrackedNickname:message.senderNickname changedTo:IRCAddressBookUserTrackingStatusSignedOff notify:YES];\n\t\t} else {\n\t\t\t[self statusOfTrackedNickname:message.senderNickname changedTo:IRCAddressBookUserTrackingStatusSignedOn notify:YES];\n\t\t}\n\n\t\treturn;\n\t}\n}\n\n#pragma mark -\n#pragma mark Channel Ban List Dialog\n\n- (void)createChannelInviteExceptionListSheet\n{\n\t[self createChannelBanListSheet:TDCChannelBanListSheetEntryTypeInviteException];\n}\n\n- (void)createChannelBanExceptionListSheet\n{\n\t[self createChannelBanListSheet:TDCChannelBanListSheetEntryTypeBanException];\n}\n\n- (void)createChannelBanListSheet\n{\n\t[self createChannelBanListSheet:TDCChannelBanListSheetEntryTypeBan];\n}\n\n- (void)createChannelQuietListSheet\n{\n\t[self createChannelBanListSheet:TDCChannelBanListSheetEntryTypeQuiet];\n}\n\n- (void)createChannelBanListSheet:(TDCChannelBanListSheetEntryType)entryType\n{\n\t[windowController() popMainWindowSheetIfExists];\n\n\tIRCChannel *c = mainWindow().selectedChannel;\n\n\tif (c == nil) {\n\t\treturn;\n\t}\n\n\tTDCChannelBanListSheet *listSheet = [[TDCChannelBanListSheet alloc] initWithEntryType:entryType inChannel:c];\n\n\tif (listSheet == nil) {\n\t\treturn;\n\t}\n\n\tlistSheet.delegate = (id)self;\n\n\tlistSheet.window = mainWindow();\n\n\t[listSheet start];\n\n\t[windowController() addWindowToWindowList:listSheet];\n}\n\n- (void)channelBanListSheetOnUpdate:(TDCChannelBanListSheet *)sender\n{\n\tIRCChannel *channel = sender.channel;\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\tNSString *modeSend = [NSString stringWithFormat:@\"+%@\", sender.modeSymbol];\n\n\t[self sendModes:modeSend withParametersString:nil inChannel:channel];\n}\n\n- (void)channelBanListSheetWillClose:(TDCChannelBanListSheet *)sender\n{\n\tIRCChannel *channel = sender.channel;\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\tNSArray *listOfChanges = sender.listOfChanges;\n\n\tfor (NSString *change in listOfChanges) {\n\t\t[self sendModes:change withParametersString:nil inChannel:channel];\n\t}\n\n\t[windowController() removeWindowFromWindowList:sender];\n}\n\n#pragma mark -\n#pragma mark Network Channel List Dialog\n\n- (NSString *)channelListDialogWindowKey\n{\n\treturn [NSString stringWithFormat:@\"TDCServerChannelListDialog -> %@\", self.uniqueIdentifier];\n}\n\n- (nullable TDCServerChannelListDialog *)channelListDialog\n{\n\treturn [windowController() windowFromWindowList:[self channelListDialogWindowKey]];\n}\n\n- (void)createChannelListDialog\n{\n\tif ([windowController() maybeBringWindowForward:[self channelListDialogWindowKey]]) {\n\t\treturn; // The window was brought forward already.\n\t}\n\n\tTDCServerChannelListDialog *channelListDialog = [[TDCServerChannelListDialog alloc] initWithClient:self];\n\n\tchannelListDialog.delegate = (id)self;\n\n\t[channelListDialog show];\n\n\t[windowController() addWindowToWindowList:channelListDialog withDescription:[self channelListDialogWindowKey]];\n}\n\n- (void)serverChannelListDialogOnUpdate:(TDCServerChannelListDialog *)sender\n{\n\t[self requestChannelList];\n}\n\n- (void)serverChannelListDialog:(TDCServerChannelListDialog *)sender joinChannels:(NSArray<NSString *> *)channels\n{\n\t[self joinUnlistedChannelsAndSelectBestMatch:channels];\n}\n\n- (void)serverChannelDialogWillClose:(TDCServerChannelListDialog *)sender\n{\n\t[windowController() removeWindowFromWindowList:[self channelListDialogWindowKey]];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCClientConfig.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"IRC.h\"\n#import \"IRCAddressBook.h\"\n#import \"IRCChannelConfig.h\"\n#import \"IRCHighlightMatchCondition.h\"\n#import \"IRCNetworkList.h\"\n#import \"IRCServerPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOLocalization.h\"\n#import \"IRCClientConfigInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define IRCClientConfigDictionaryVersionLatest\t\t710\n\n#define IRCClientConfigFloodControlDefaultDelayIntervalLimited\t\t2\n#define IRCClientConfigFloodControlDefaultMessageCountLimited\t\t2 // freenode gets a special case 'cause they are strict about flood control\n\n@interface IRCClientConfig ()\n@property (readonly) BOOL prefersSecuredConnection_;\n@property (readonly) uint16_t serverPort_;\n@property (readonly, copy, nullable) NSString *serverAddress_;\n@property (readonly) BOOL connectionPrefersModernCiphers_;\n@end\n\n@implementation IRCClientConfig\n\n#pragma mark -\n#pragma mark Defaults\n\n- (void)populateDefaultsPreflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\t/* Even if a value is NO, include it as a default. */\n\t/* This allows NO values to be stripped from output dictionary. */\n\tNSMutableDictionary<NSString *, id> *defaults = [NSMutableDictionary dictionary];\n\n\tdefaults[@\"addressType\"] = @(IRCConnectionAddressTypeDefault);\n\tdefaults[@\"autoConnect\"] = @(NO);\n\tdefaults[@\"autoReconnect\"] = @(NO);\n\tdefaults[@\"autoSleepModeDisconnect\"] = @(YES);\n\tdefaults[@\"autojoinWaitsForNickServ\"] = @(NO);\n\tdefaults[@\"cachedLastServerTimeCapabilityReceivedAtTimestamp\"] = @(0);\n\tdefaults[@\"cipherSuites\"] = @(RCMCipherSuiteCollectionDefault);\n\tdefaults[@\"connectionName\"] = TXTLS(@\"BasicLanguage[vfu-c0]\");\n\tdefaults[@\"fallbackEncoding\"] = @(TXDefaultFallbackStringEncoding);\n\tdefaults[@\"floodControlDelayTimerInterval\"] = @(IRCConnectionConfigFloodControlDefaultDelayInterval);\n\tdefaults[@\"floodControlMaximumMessages\"] = @(IRCConnectionConfigFloodControlDefaultMessageCount);\n\tdefaults[@\"hideAutojoinDelayedWarnings\"] = @(NO);\n\tdefaults[@\"hideNetworkUnavailabilityNotices\"] = @(NO);\n\tdefaults[@\"normalLeavingComment\"] = TXTLS(@\"BasicLanguage[1dd-0f]\");\n\tdefaults[@\"performDisconnectOnPongTimer\"] = @(NO);\n\tdefaults[@\"performDisconnectOnReachabilityChange\"] = @(YES);\n\tdefaults[@\"performPongTimer\"] = @(YES);\n\tdefaults[@\"prefersSecuredConnection\"] = @(NO);\n\tdefaults[@\"primaryEncoding\"] = @(TXDefaultPrimaryStringEncoding);\n\tdefaults[@\"proxyPort\"] = @(IRCConnectionDefaultProxyPort);\n\tdefaults[@\"proxyType\"] = @(IRCConnectionProxyTypeAutomatic);\n\tdefaults[@\"saslAuthenticationDisableExternalMechanism\"] = @(NO);\n\tdefaults[@\"sendAuthenticationRequestsToUserServ\"] = @(NO);\n\tdefaults[@\"sendWhoCommandRequestsToChannels\"] = @(YES);\n\tdefaults[@\"serverPort\"] = @(IRCConnectionDefaultServerPort);\n\tdefaults[@\"setInvisibleModeOnConnect\"] = @(NO);\n\tdefaults[@\"sidebarItemExpanded\"] = @(YES);\n\tdefaults[@\"sleepModeLeavingComment\"] = TXTLS(@\"BasicLanguage[qi7-5y]\");\n\tdefaults[@\"validateServerCertificateChain\"] = @(YES);\n\tdefaults[@\"zncIgnoreConfiguredAutojoin\"] = @(NO);\n\tdefaults[@\"zncIgnorePlaybackNotifications\"] = @(YES);\n\tdefaults[@\"zncIgnoreUserNotifications\"] = @(NO);\n\tdefaults[@\"zncOnlyPlaybackLatest\"] = @(YES);\n\n\tself->_defaults = [defaults copy];\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n\n\tSetVariableIfNil(self->_nickname, [TPCPreferences defaultNickname])\n\tSetVariableIfNil(self->_awayNickname, [TPCPreferences defaultAwayNickname])\n\tSetVariableIfNil(self->_username, [TPCPreferences defaultUsername])\n\tSetVariableIfNil(self->_realName, [TPCPreferences defaultRealName])\n\n\tSetVariableIfNil(self->_ignoreList, @[])\n\tSetVariableIfNil(self->_channelList, @[])\n\tSetVariableIfNil(self->_highlightList, @[])\n\tSetVariableIfNil(self->_serverList, @[])\n\n\tSetVariableIfNil(self->_alternateNicknames, @[])\n\n\tSetVariableIfNil(self->_loginCommands, @[])\n\n\t[self modifyFloodControlDefaults];\n}\n\n- (void)populateDefaultsByAppendingDictionary:(NSDictionary<NSString *, id> *)defaultsToAppend\n{\n\tNSParameterAssert(defaultsToAppend != nil);\n\n\tself->_defaults = [self->_defaults dictionaryByAddingEntries:defaultsToAppend];\n}\n\n- (void)modifyFloodControlDefaults\n{\n\tif (self.floodControlDelayTimerInterval != IRCConnectionConfigFloodControlDefaultDelayInterval ||\n\t\tself.floodControlMaximumMessages != IRCConnectionConfigFloodControlDefaultMessageCount)\n\t{\n\t\treturn;\n\t}\n\n\tBOOL haveLimitedServer = NO;\n\n\tfor (IRCServer *server in self.serverList) {\n\t\tif ([server.serverAddress hasSuffix:@\".freenode.net\"] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\thaveLimitedServer = YES;\n\n\t\tbreak;\n\t}\n\n\tif (haveLimitedServer == NO) {\n\t\treturn;\n\t}\n\n\tNSUInteger floodControlDelayTimerInterval = IRCClientConfigFloodControlDefaultDelayIntervalLimited;\n\tNSUInteger floodControlMaximumMessages = IRCClientConfigFloodControlDefaultMessageCountLimited;\n\n\t[self populateDefaultsByAppendingDictionary:@{\n\t\t@\"floodControlDelayTimerInterval\" : @(floodControlDelayTimerInterval),\n\t\t@\"floodControlMaximumMessages\" : @(floodControlMaximumMessages)\n\t}];\n\n\tself->_floodControlDelayTimerInterval = floodControlDelayTimerInterval;\n\tself->_floodControlMaximumMessages = floodControlMaximumMessages;\n}\n\n#pragma mark -\n#pragma mark Server Configuration\n\n- (instancetype)init\n{\n\treturn [self initWithDictionary:@{}];\n}\n\n- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\treturn [self initWithDictionary:dic ignorePrivateMessages:NO];\n}\n\n- (instancetype)initWithDictionary:(NSDictionary<NSString *, id> *)dic ignorePrivateMessages:(BOOL)ignorePrivateMessages\n{\n\tif ((self = [super init])) {\n\t\t[self populateDefaultsPreflight];\n\n\t\t[self populateDictionaryValue:dic\n\t\t\t\tignorePrivateMessages:ignorePrivateMessages\n\t\t\t\t\t\tapplyDefaults:YES\n\t\t\t\t\tbypassIsCopyCheck:NO];\n\n\t\t[self populateDefaultsPostflight];\n\n\t\t[self initializedClassHealthCheck];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tif (self->_proxyPort == 0) {\n\t\tself->_proxyPort = IRCConnectionDefaultProxyPort;\n\t}\n\n\tif ([self isMutable]) {\n\t\treturn;\n\t}\n\n\tNSParameterAssert(self->_connectionName.length > 0);\n}\n\n+ (instancetype)newConfigByMerging:(IRCClientConfig *)config1 with:(IRCClientConfig *)config2\n{\n\tNSParameterAssert(config1 != nil);\n\tNSParameterAssert(config2 != nil);\n\n\tIRCClientConfigMutable *config1Mutable = [config1 mutableCopy];\n\n\t[config1Mutable populateDictionaryValue:config2.dictionaryValue\n\t\t\t\t\t  ignorePrivateMessages:NO\n\t\t\t\t\t\t\t  applyDefaults:NO\n\t\t\t\t\t\t  bypassIsCopyCheck:YES];\n\n\tif ([self isMutable]) {\n\t\treturn config1Mutable;\n\t}\n\n\treturn [config1Mutable copy];\n}\n\n+ (instancetype)newConfigWithNetwork:(IRCNetwork *)network\n{\n\tNSParameterAssert(network != nil);\n\n\tIRCClientConfigMutable *configMutable = [IRCClientConfigMutable new];\n\n\tconfigMutable.connectionName = network.networkName;\n\n\tIRCServerMutable *server = [IRCServerMutable new];\n\n\tserver.serverAddress = network.serverAddress;\n\tserver.serverPort = network.serverPort;\n\n\tserver.prefersSecuredConnection = network.prefersSecuredConnection;\n\n\tconfigMutable.serverList = @[[server copy]];\n\n\tif ([self isMutable]) {\n\t\treturn configMutable;\n\t}\n\n\treturn [configMutable copy];\n}\n\n- (void)populateDictionaryValue:(NSDictionary<NSString *, id> *)dic ignorePrivateMessages:(BOOL)ignorePrivateMessages applyDefaults:(BOOL)applyDefaults bypassIsCopyCheck:(BOOL)bypassIsCopyCheck\n{\n\tNSParameterAssert(dic != nil);\n\n\tNSMutableDictionary<NSString *, id> *defaultsMutable = nil;\n\n\tif (applyDefaults) {\n\t\tdefaultsMutable = [self->_defaults mutableCopy];\n\n\t\t[defaultsMutable addEntriesFromDictionary:dic];\n\t} else {\n\t\tdefaultsMutable = [dic mutableCopy];\n\t}\n\n\t/* Load the newest set of keys. */\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_dictionaryVersion forKey:@\"dictionaryVersion\"];\n\n\t[defaultsMutable assignArrayTo:&self->_alternateNicknames forKey:@\"alternateNicknames\"];\n\t[defaultsMutable assignArrayTo:&self->_loginCommands forKey:@\"onConnectCommands\"];\n\n\t[defaultsMutable assignBoolTo:&self->_autoConnect forKey:@\"autoConnect\"];\n\t[defaultsMutable assignBoolTo:&self->_autoReconnect forKey:@\"autoReconnect\"];\n\t[defaultsMutable assignBoolTo:&self->_autoSleepModeDisconnect forKey:@\"autoSleepModeDisconnect\"];\n\t[defaultsMutable assignBoolTo:&self->_autojoinWaitsForNickServ forKey:@\"autojoinWaitsForNickServ\"];\n\t[defaultsMutable assignBoolTo:&self->_hideAutojoinDelayedWarnings forKey:@\"hideAutojoinDelayedWarnings\"];\n\t[defaultsMutable assignBoolTo:&self->_hideNetworkUnavailabilityNotices forKey:@\"hideNetworkUnavailabilityNotices\"];\n\t[defaultsMutable assignBoolTo:&self->_performDisconnectOnPongTimer forKey:@\"performDisconnectOnPongTimer\"];\n\t[defaultsMutable assignBoolTo:&self->_performDisconnectOnReachabilityChange forKey:@\"performDisconnectOnReachabilityChange\"];\n\t[defaultsMutable assignBoolTo:&self->_performPongTimer forKey:@\"performPongTimer\"];\n\t[defaultsMutable assignBoolTo:&self->_prefersSecuredConnection forKey:@\"prefersSecuredConnection\"];\n\t[defaultsMutable assignBoolTo:&self->_saslAuthenticationDisableExternalMechanism forKey:@\"saslAuthenticationDisableExternalMechanism\"];\n\t[defaultsMutable assignBoolTo:&self->_sendAuthenticationRequestsToUserServ forKey:@\"sendAuthenticationRequestsToUserServ\"];\n\t[defaultsMutable assignBoolTo:&self->_sendWhoCommandRequestsToChannels forKey:@\"sendWhoCommandRequestsToChannels\"];\n\t[defaultsMutable assignBoolTo:&self->_setInvisibleModeOnConnect forKey:@\"setInvisibleModeOnConnect\"];\n\t[defaultsMutable assignBoolTo:&self->_sidebarItemExpanded forKey:@\"sidebarItemExpanded\"];\n\t[defaultsMutable assignBoolTo:&self->_validateServerCertificateChain forKey:@\"validateServerCertificateChain\"];\n\t[defaultsMutable assignBoolTo:&self->_zncIgnoreConfiguredAutojoin forKey:@\"zncIgnoreConfiguredAutojoin\"];\n\t[defaultsMutable assignBoolTo:&self->_zncIgnorePlaybackNotifications forKey:@\"zncIgnorePlaybackNotifications\"];\n\t[defaultsMutable assignBoolTo:&self->_zncIgnoreUserNotifications forKey:@\"zncIgnoreUserNotifications\"];\n\t[defaultsMutable assignBoolTo:&self->_zncOnlyPlaybackLatest forKey:@\"zncOnlyPlaybackLatest\"];\n\n\t[defaultsMutable assignDoubleTo:&self->_lastMessageServerTime forKey:@\"cachedLastServerTimeCapabilityReceivedAtTimestamp\"];\n\t[defaultsMutable assignObjectTo:&self->_identityClientSideCertificate forKey:@\"identityClientSideCertificate\"];\n\t[defaultsMutable assignStringTo:&self->_awayNickname forKey:@\"awayNickname\"];\n\t[defaultsMutable assignStringTo:&self->_connectionName forKey:@\"connectionName\"];\n\t[defaultsMutable assignStringTo:&self->_nickname forKey:@\"nickname\"];\n\t[defaultsMutable assignStringTo:&self->_normalLeavingComment forKey:@\"normalLeavingComment\"];\n\t[defaultsMutable assignStringTo:&self->_proxyAddress forKey:@\"proxyAddress\"];\n\t[defaultsMutable assignStringTo:&self->_proxyUsername forKey:@\"proxyUsername\"];\n\t[defaultsMutable assignStringTo:&self->_realName forKey:@\"realName\"];\n\t[defaultsMutable assignStringTo:&self->_serverAddress forKey:@\"serverAddress\"];\n\t[defaultsMutable assignStringTo:&self->_sleepModeLeavingComment forKey:@\"sleepModeLeavingComment\"];\n\t[defaultsMutable assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\t[defaultsMutable assignStringTo:&self->_username forKey:@\"username\"];\n\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_addressType forKey:@\"addressType\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_cipherSuites forKey:@\"cipherSuites\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_fallbackEncoding forKey:@\"fallbackEncoding\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_floodControlDelayTimerInterval forKey:@\"floodControlDelayTimerInterval\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_floodControlMaximumMessages forKey:@\"floodControlMaximumMessages\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_primaryEncoding forKey:@\"primaryEncoding\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_proxyType forKey:@\"proxyType\"];\n\n\t[defaultsMutable assignUnsignedShortTo:&self->_proxyPort forKey:@\"proxyPort\"];\n\t[defaultsMutable assignUnsignedShortTo:&self->_serverPort forKey:@\"serverPort\"];\n\n\t/* -connectionPrefersIPv4 is a special exception to legacy support.\n\t We still load its value, regardless of dictionary version, so that\n\t we can show a user a warning when -connectionPrefersIPv4 == YES\n\t and -addressType == IPv6 (which is automatically migrates to).\n\t We then change value to NO when user modifies -addressType. */\n\t[defaultsMutable assignBoolTo:&self->_connectionPrefersIPv4 forKey:@\"connectionPrefersIPv4\"];\n\n\t/* If this is a copy operation, then we can just stop here. The rest of the data processed below,\n\t such as other configurations and backwards keys are already taken care of. */\n\tif (self.initializedAsCopy && bypassIsCopyCheck == NO) {\n\t\treturn;\n\t}\n\n\t/* Channel list */\n\tNSMutableArray<IRCChannelConfig *> *channelListOut = [NSMutableArray array];\n\n\tNSArray<NSDictionary *> *channelListIn = [defaultsMutable arrayForKey:@\"channelList\"];\n\n\tfor (NSDictionary<NSString *, id> *e in channelListIn) {\n\t\tIRCChannelConfig *c = [[IRCChannelConfig alloc] initWithDictionary:e];\n\n\t\tif (c.type == IRCChannelTypePrivateMessage) {\n\t\t\tif (ignorePrivateMessages == NO) {\n\t\t\t\t[channelListOut addObject:c];\n\t\t\t}\n\t\t} else {\n\t\t\t[channelListOut addObject:c];\n\t\t}\n\t}\n\n\tself->_channelList = [channelListOut copy];\n\n\t/* Ignore list */\n\tNSMutableArray<IRCAddressBookEntry *> *ignoreListOut = [NSMutableArray array];\n\n\tNSArray<NSDictionary *> *ignoreListIn = [defaultsMutable arrayForKey:@\"ignoreList\"];\n\n\tfor (NSDictionary<NSString *, id> *e in ignoreListIn) {\n\t\tIRCAddressBookEntry *c = [[IRCAddressBookEntry alloc] initWithDictionary:e];\n\n\t\t[ignoreListOut addObject:c];\n\t}\n\n\tself->_ignoreList = [ignoreListOut copy];\n\n\t/* Highlight list */\n\tNSMutableArray<IRCHighlightMatchCondition *> *highlightListOut = [NSMutableArray array];\n\n\tNSArray<NSDictionary *> *highlightListIn = [defaultsMutable arrayForKey:@\"highlightList\"];\n\n\tfor (NSDictionary<NSString *, id> *e in highlightListIn) {\n\t\tIRCHighlightMatchCondition *c = [[IRCHighlightMatchCondition alloc] initWithDictionary:e];\n\n\t\t[highlightListOut addObject:c];\n\t}\n\n\tself->_highlightList = [highlightListOut copy];\n\n\t/* Server List */\n\tNSMutableArray<IRCServer *> *serverListOut = [NSMutableArray array];\n\n\tNSArray<NSDictionary *> *serverListIn = [defaultsMutable arrayForKey:@\"serverList\"];\n\n\tfor (NSDictionary<NSString *, id> *e in serverListIn) {\n\t\tIRCServer *c = [[IRCServer alloc] initWithDictionary:e];\n\n\t\t[serverListOut addObject:c];\n\t}\n\n\tself->_serverList = [serverListOut copy];\n\n\t/* Perform migration */\n\t/* If legacy keys were assigned before new keys, then a transition would not occur properly. */\n\t/* Since the new keys will read from -defaults if they are not present in /dic/, then those\n\t would override legacy keys when performing a first pass. */\n\n\t/* Is everything up to date? */\n\tNSUInteger dictionaryVersion = self->_dictionaryVersion;\n\n\tif (dictionaryVersion == IRCClientConfigDictionaryVersionLatest) {\n\t\treturn;\n\t}\n\n\t/* 710 is latest version which means we migrate it at all times */\n\t[self _migrate710Dictionary:dic withDefaults:defaultsMutable];\n\n\t/* 704 is no longer the latest version but there was no version before\n\t it which means we only have to migrate it when the version is unknown. */\n\tif (dictionaryVersion == 0) {\n\t\t[self _migrate704Dictionary:dic withDefaults:defaultsMutable];\n\t}\n\n\t/* Update version */\n\tself->_dictionaryVersion = IRCClientConfigDictionaryVersionLatest;\n}\n\n- (void)_migrate710Dictionary:(NSDictionary *)dic withDefaults:(NSMutableDictionary *)defaultsMutable\n{\n\tNSParameterAssert(dic != nil);\n\tNSParameterAssert(defaultsMutable != nil);\n\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\tif (self.connectionPrefersIPv4) {\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\t\tself->_addressType = IRCConnectionAddressTypeIPv4;\n\t}\n}\n\n- (void)_migrate704Dictionary:(NSDictionary *)dic withDefaults:(NSMutableDictionary *)defaultsMutable\n{\n\tNSParameterAssert(dic != nil);\n\tNSParameterAssert(defaultsMutable != nil);\n\n\t[defaultsMutable assignArrayTo:&self->_alternateNicknames forKey:@\"identityAlternateNicknames\"];\n\n\t[defaultsMutable assignBoolTo:&self->_autoConnect forKey:@\"connectOnLaunch\"];\n\t[defaultsMutable assignBoolTo:&self->_autoReconnect forKey:@\"connectOnDisconnect\"];\n\t[defaultsMutable assignBoolTo:&self->_autoSleepModeDisconnect forKey:@\"disconnectOnSleepMode\"];\n\t[defaultsMutable assignBoolTo:&self->_autojoinWaitsForNickServ forKey:@\"autojoinWaitsForNickServIdentification\"];\n\t[defaultsMutable assignBoolTo:&self->_prefersSecuredConnection forKey:@\"connectUsingSSL\"];\n\t[defaultsMutable assignBoolTo:&self->_setInvisibleModeOnConnect forKey:@\"setInvisibleOnConnect\"];\n\t[defaultsMutable assignBoolTo:&self->_sidebarItemExpanded forKey:@\"serverListItemIsExpanded\"];\n\t[defaultsMutable assignBoolTo:&self->_validateServerCertificateChain forKey:@\"validateServerSideSSLCertificate\"];\n\n\t[defaultsMutable assignObjectTo:&self->_identityClientSideCertificate forKey:@\"IdentitySSLCertificate\"];\n\n\t[defaultsMutable assignStringTo:&self->_awayNickname forKey:@\"identityAwayNickname\"];\n\t[defaultsMutable assignStringTo:&self->_nickname forKey:@\"identityNickname\"];\n\t[defaultsMutable assignStringTo:&self->_normalLeavingComment forKey:@\"connectionDisconnectDefaultMessage\"];\n\t[defaultsMutable assignStringTo:&self->_proxyAddress forKey:@\"proxyServerAddress\"];\n\t[defaultsMutable assignStringTo:&self->_proxyUsername forKey:@\"proxyServerUsername\"];\n\t[defaultsMutable assignStringTo:&self->_realName forKey:@\"identityRealname\"];\n\t[defaultsMutable assignStringTo:&self->_sleepModeLeavingComment forKey:@\"connectionDisconnectSleepModeMessage\"];\n\t[defaultsMutable assignStringTo:&self->_username forKey:@\"identityUsername\"];\n\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_primaryEncoding forKey:@\"characterEncodingDefault\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_fallbackEncoding forKey:@\"characterEncodingFallback\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_proxyType forKey:@\"proxyServerType\"];\n\n\t[defaultsMutable assignUnsignedShortTo:&self->_proxyPort forKey:@\"proxyServerPort\"];\n\n\t[defaultsMutable assignDoubleTo:&self->_lastMessageServerTime forKey:@\"cachedLastServerTimeCapacityReceivedAtTimestamp\"];\n\n\t/* Flood control */\n\t/* This is here to migrate to the new properties. Saving these values\n\t in this dictionary key is no longer preferred. */\n\tBOOL floodControlSetToDisabled = NO;\n\n\tNSDictionary *floodControlDic = [defaultsMutable dictionaryForKey:@\"floodControl\"];\n\n\tif (floodControlDic) {\n\t\tNSNumber *serviceEnabled = floodControlDic[@\"serviceEnabled\"];\n\n\t\tif (serviceEnabled && serviceEnabled.boolValue == NO) {\n\t\t\tfloodControlSetToDisabled = YES;\n\t\t}\n\n\t\t[floodControlDic assignUnsignedIntegerTo:&self->_floodControlDelayTimerInterval forKey:@\"delayTimerInterval\"];\n\t\t[floodControlDic assignUnsignedIntegerTo:&self->_floodControlMaximumMessages forKey:@\"maximumMessageCount\"];\n\t}\n\n\tif (floodControlSetToDisabled == NO) {\n\t\tNSNumber *floodControlEnabled = defaultsMutable[@\"isOutgoingFloodControlEnabled\"];\n\n\t\tif (floodControlEnabled && floodControlEnabled.boolValue == NO) {\n\t\t\tfloodControlSetToDisabled = YES;\n\t\t}\n\t}\n\n\t/* An option to disable flood control no longer exists.\n\t If the user had flood control disabled when the option did exist,\n\t then set the the current values to appear disabled. */\n\tif (floodControlSetToDisabled) {\n\t\tself->_floodControlDelayTimerInterval = IRCConnectionConfigFloodControlMinimumDelayInterval;\n\t\tself->_floodControlMaximumMessages = IRCConnectionConfigFloodControlMaximumMessageCount;\n\t}\n\n\t/* Migrate to keychain. */\n\tNSString *proxyPassword = [defaultsMutable stringForKey:@\"proxyServerPassword\"];\n\n\tif (proxyPassword) {\n\t\tself->_proxyPassword = [proxyPassword copy];\n\n\t\t[self writeProxyPasswordToKeychain];\n\t}\n\n\t/* Cipher suites */\n\t/* The dictionary excludes defaults which means we need to be cautious\n\t about reading the value of dic when performing migration. */\n\tif (dic[@\"cipherSuites\"] == nil) {\n\t\tNSNumber *connectionPrefersModernCiphers = dic[@\"connectionPrefersModernCiphers\"];\n\n\t\tif (connectionPrefersModernCiphers && connectionPrefersModernCiphers.boolValue == NO) {\n\t\t\tself->_cipherSuites = RCMCipherSuiteCollectionNone;\n\t\t}\n\t}\n\n\t/* Migrate servers */\n\t[self _migrateDictionaryToServerListV1Layout:defaultsMutable];\n}\n\n- (void)_migrateDictionaryToServerListV1Layout:(NSDictionary *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\t/* This key is no longer assigned. We still check it so that\n\t clients that did not set dictionaryVersion but did set this\n\t key wont trigger migration again. */\n\tid migratedToServerListV1Layout = dic[@\"migratedToServerListV1Layout\"];\n\n\tif (migratedToServerListV1Layout && [migratedToServerListV1Layout boolValue]) {\n\t\treturn;\n\t}\n\n\t/* Do not perform migration if already one server exists. */\n\t/* IRCClientConfig inserts these values back into the exported dictionary \n\t for backwards compatibility which means once we imported them and have\n\t at least one server, then importing again will not help. */\n\tif (self.serverList.count > 0) {\n\t\treturn;\n\t}\n\n\t/* Perform migration */\n\tNSString *serverAddress = [dic stringForKey:@\"serverAddress\"];\n\n\tif (serverAddress.isValidInternetAddress == NO) {\n\t\tLogToConsoleDebug(\"Migration cancelled because of bad server address\");\n\n\t\treturn;\n\t}\n\n\tuint16_t serverPort = [dic unsignedShortForKey:@\"serverPort\"];\n\n\tif (serverPort == 0 || serverPort > TXMaximumTCPPort) {\n\t\tLogToConsoleDebug(\"Migration cancelled because of bad server port\");\n\n\t\treturn;\n\t}\n\n\tBOOL prefersSecuredConnection = [dic boolForKey:@\"prefersSecuredConnection\"];\n\n\tNSString *serverPasswordServiceName = [NSString stringWithFormat:@\"textual.server.%@\", self.uniqueIdentifier];\n\n\tNSString *serverPassword = [XRKeychain getPasswordFromKeychainItem:@\"Textual (Server Password)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   serviceName:serverPasswordServiceName];\n\n\tIRCServerMutable *server = [IRCServerMutable new];\n\n\tserver.serverAddress = serverAddress;\n\tserver.serverPort = serverPort;\n\n\tserver.serverPassword = serverPassword;\n\n\tserver.prefersSecuredConnection = prefersSecuredConnection;\n\n\t[server writeServerPasswordToKeychain];\n\n\tself->_serverList = @[[server copy]];\n\n\tself->_migratedServerPasswordPendingDestroy = YES;\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCClientConfig class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCClientConfig *objectCast = (IRCClientConfig *)object;\n\n\tNSDictionary *s1 = self.dictionaryValue;\n\n\tNSDictionary *s2 = objectCast.dictionaryValue;\n\n\treturn ([s1 isEqualToDictionary:s2] &&\n\t\t\t\n\t\t\t((self->_nicknamePassword == nil && objectCast->_nicknamePassword == nil) ||\n\t\t\t [self->_nicknamePassword isEqualToString:objectCast->_nicknamePassword]) &&\n\n\t\t\t((self->_proxyPassword == nil && objectCast->_proxyPassword == nil) ||\n\t\t\t [self->_proxyPassword isEqualToString:objectCast->_proxyPassword]));\n}\n\n- (NSUInteger)hash\n{\n\treturn self.uniqueIdentifier.hash;\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCClientConfig *config = [self allocForCopyAsMutable:mutableCopy];\n\n\tconfig->_nicknamePassword = self->_nicknamePassword;\n\tconfig->_proxyPassword = self->_proxyPassword;\n\n\tconfig->_defaults = self->_defaults;\n\n\tconfig->_migratedServerPasswordPendingDestroy = self->_migratedServerPasswordPendingDestroy;\n\n\tif (uniquing) {\n\t\tNSMutableArray *channelList = [self.channelList mutableCopy];\n\t\tNSMutableArray *highlightList = [self.highlightList mutableCopy];\n\t\tNSMutableArray *ignoreList = [self.ignoreList mutableCopy];\n\t\tNSMutableArray *serverList = [self.serverList mutableCopy];\n\n\t\t[channelList performSelectorOnObjectValueAndReplace:@selector(uniqueCopy)];\n\t\t[highlightList performSelectorOnObjectValueAndReplace:@selector(uniqueCopy)];\n\t\t[ignoreList performSelectorOnObjectValueAndReplace:@selector(uniqueCopy)];\n\t\t[serverList performSelectorOnObjectValueAndReplace:@selector(uniqueCopy)];\n\n\t\tconfig->_channelList = [channelList copy];\n\t\tconfig->_highlightList = [highlightList copy];\n\t\tconfig->_ignoreList = [ignoreList copy];\n\t\tconfig->_serverList = [serverList copy];\n\n\t\tconfig->_uniqueIdentifier = [NSString stringWithUUID];\n\t} \n\telse // uniquing\n\t{\n\t\tconfig->_channelList = self->_channelList;\n\t\tconfig->_highlightList = self->_highlightList;\n\t\tconfig->_ignoreList = self->_ignoreList;\n\t\tconfig->_serverList = self->_serverList;\n\t}\n\n\treturn [config initWithDictionary:self.dictionaryValueForCopy ignorePrivateMessages:NO];\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [IRCClientConfigMutable self];\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t[dic setUnsignedInteger:self->_dictionaryVersion forKey:@\"dictionaryVersion\"];\n\n\t[dic maybeSetObject:self.alternateNicknames forKey:@\"alternateNicknames\"];\n\t[dic maybeSetObject:self.awayNickname forKey:@\"awayNickname\"];\n\t[dic maybeSetObject:self.connectionName forKey:@\"connectionName\"];\n\t[dic maybeSetObject:self.loginCommands forKey:@\"onConnectCommands\"];\n\t[dic maybeSetObject:self.nickname forKey:@\"nickname\"];\n\t[dic maybeSetObject:self.normalLeavingComment forKey:@\"normalLeavingComment\"];\n\t[dic maybeSetObject:self.proxyAddress forKey:@\"proxyAddress\"];\n\t[dic maybeSetObject:self.proxyUsername forKey:@\"proxyUsername\"];\n\t[dic maybeSetObject:self.realName forKey:@\"realName\"];\n\t[dic maybeSetObject:self.sleepModeLeavingComment forKey:@\"sleepModeLeavingComment\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\t[dic maybeSetObject:self.username forKey:@\"username\"];\n\n\t[dic setBool:self.autoConnect forKey:@\"autoConnect\"];\n\t[dic setBool:self.autoReconnect forKey:@\"autoReconnect\"];\n\t[dic setBool:self.autoSleepModeDisconnect forKey:@\"autoSleepModeDisconnect\"];\n\t[dic setBool:self.autojoinWaitsForNickServ forKey:@\"autojoinWaitsForNickServ\"];\n\t[dic setBool:self.hideAutojoinDelayedWarnings forKey:@\"hideAutojoinDelayedWarnings\"];\n\t[dic setBool:self.hideNetworkUnavailabilityNotices forKey:@\"hideNetworkUnavailabilityNotices\"];\n\t[dic setBool:self.performDisconnectOnPongTimer forKey:@\"performDisconnectOnPongTimer\"];\n\t[dic setBool:self.performDisconnectOnReachabilityChange forKey:@\"performDisconnectOnReachabilityChange\"];\n\t[dic setBool:self.performPongTimer forKey:@\"performPongTimer\"];\n\t[dic setBool:self.saslAuthenticationDisableExternalMechanism forKey:@\"saslAuthenticationDisableExternalMechanism\"];\n\t[dic setBool:self.sendAuthenticationRequestsToUserServ forKey:@\"sendAuthenticationRequestsToUserServ\"];\n\t[dic setBool:self.sendWhoCommandRequestsToChannels forKey:@\"sendWhoCommandRequestsToChannels\"];\n\t[dic setBool:self.setInvisibleModeOnConnect forKey:@\"setInvisibleModeOnConnect\"];\n\t[dic setBool:self.validateServerCertificateChain forKey:@\"validateServerCertificateChain\"];\n\t[dic setBool:self.zncIgnoreConfiguredAutojoin forKey:@\"zncIgnoreConfiguredAutojoin\"];\n\t[dic setBool:self.zncIgnorePlaybackNotifications forKey:@\"zncIgnorePlaybackNotifications\"];\n\t[dic setBool:self.zncIgnoreUserNotifications forKey:@\"zncIgnoreUserNotifications\"];\n\t[dic setBool:self.zncOnlyPlaybackLatest forKey:@\"zncOnlyPlaybackLatest\"];\n\n\t[dic setUnsignedInteger:self.addressType forKey:@\"addressType\"];\n\t[dic setUnsignedInteger:self.cipherSuites forKey:@\"cipherSuites\"];\n\t[dic setUnsignedInteger:self.fallbackEncoding forKey:@\"fallbackEncoding\"];\n\t[dic setUnsignedInteger:self.floodControlDelayTimerInterval forKey:@\"floodControlDelayTimerInterval\"];\n\t[dic setUnsignedInteger:self.floodControlMaximumMessages forKey:@\"floodControlMaximumMessages\"];\n\t[dic setUnsignedInteger:self.primaryEncoding forKey:@\"primaryEncoding\"];\n\t[dic setUnsignedInteger:self.proxyType forKey:@\"proxyType\"];\n\n\t[dic setUnsignedShort:self.proxyPort forKey:@\"proxyPort\"];\n\n\t/* These are items that cannot be synced over iCloud because they access data specific to \n\t this device or only contain state information which is not useful to other devices. */\n\t[dic maybeSetObject:self.identityClientSideCertificate forKey:@\"identityClientSideCertificate\"];\n\n\t[dic setBool:self.sidebarItemExpanded forKey:@\"sidebarItemExpanded\"];\n\n\t[dic setDouble:self.lastMessageServerTime forKey:@\"cachedLastServerTimeCapabilityReceivedAtTimestamp\"];\n\n\t/* Deprecated */\n\t/* These values are inserted here for backwards compatibility \n\t with earlier versions of Textual */\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t[dic setBool:self.connectionPrefersIPv4 forKey:@\"connectionPrefersIPv4\"];\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\t[dic setBool:self.legacyConnectionPrefersModernCiphers forKey:@\"connectionPrefersModernCiphers\"];\n\n\t[dic maybeSetObject:self.legacyServerAddress forKey:@\"serverAddress\"];\n\n\t[dic setBool:self.legacyPrefersSecuredConnection forKey:@\"prefersSecuredConnection\"];\n\n\t[dic setUnsignedShort:self.legacyServerPort forKey:@\"serverPort\"];\n\n\t/* During a copy operation, it is faster to copy these arrays as a whole.\n\t It also preserves -secretKey value in IRCChannelConfig since that will\n\t be lost when reconstructing from dictionary value. */\n\tif (target == XRPortablePropertyDictTargetCopy ||\n\t\ttarget == XRPortablePropertyDictTargetMutableCopy)\n\t{\n\t\treturn [dic copy];\n\t}\n\n\t/* Channel List */\n\tNSMutableArray<NSDictionary *> *channelListOut = [NSMutableArray array];\n\n\tfor (IRCChannelConfig *e in self.channelList) {\n\t\tNSDictionary *d = e.dictionaryValue;\n\n\t\t[channelListOut addObject:d];\n\t}\n\n\tif (channelListOut.count > 0) {\n\t\tdic[@\"channelList\"] = [channelListOut copy];\n\t}\n\n\t/* Highlight list */\n\tNSMutableArray<NSDictionary *> *highlightListOut = [NSMutableArray array];\n\n\tfor (IRCHighlightMatchCondition *e in self.highlightList) {\n\t\tNSDictionary *d = e.dictionaryValue;\n\n\t\t[highlightListOut addObject:d];\n\t}\n\n\tif (highlightListOut.count > 0) {\n\t\tdic[@\"highlightList\"] = [highlightListOut copy];\n\t}\n\n\t/* Ignore list */\n\tNSMutableArray<NSDictionary *> *ignoreListOut = [NSMutableArray array];\n\n\tfor (IRCAddressBookEntry *e in self.ignoreList) {\n\t\tNSDictionary *d = e.dictionaryValue;\n\n\t\t[ignoreListOut addObject:d];\n\t}\n\n\tif (ignoreListOut.count > 0) {\n\t\tdic[@\"ignoreList\"] = [ignoreListOut copy];\n\t}\n\n\t/* Servers */\n\tNSMutableArray<NSDictionary *> *serverListOut = [NSMutableArray array];\n\n\tfor (IRCServer *e in self.serverList) {\n\t\tNSDictionary *d = e.dictionaryValue;\n\n\t\t[serverListOut addObject:d];\n\t}\n\n\tif (serverListOut.count > 0) {\n\t\tdic[@\"serverList\"] = [serverListOut copy];\n\t}\n\n\treturn [dic dictionaryByRemovingDefaults:self->_defaults allowEmptyValues:YES];\n}\n\n#pragma mark -\n#pragma mark Keychain Management\n\n- (nullable NSString *)nicknamePassword\n{\n\tif (self->_nicknamePassword) {\n\t\treturn self->_nicknamePassword;\n\t}\n\n\treturn self.nicknamePasswordFromKeychain;\n}\n\n- (nullable NSString *)nicknamePasswordFromKeychain\n{\n\tNSString *nicknamePasswordServiceName = [NSString stringWithFormat:@\"textual.nickserv.%@\", self.uniqueIdentifier];\n\n\tNSString *kcPassword = [XRKeychain getPasswordFromKeychainItem:@\"Textual (NickServ)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   serviceName:nicknamePasswordServiceName];\n\n\treturn kcPassword;\n}\n\n- (nullable NSString *)proxyPassword\n{\n\tif (self->_proxyPassword) {\n\t\treturn self->_proxyPassword;\n\t}\n\n\treturn self.proxyPasswordFromKeychain;\n}\n\n- (nullable NSString *)proxyPasswordFromKeychain\n{\n\tNSString *proxyPasswordServiceName = [NSString stringWithFormat:@\"textual.proxy-server.%@\", self.uniqueIdentifier];\n\n\tNSString *kcPassword = [XRKeychain getPasswordFromKeychainItem:@\"Textual (Proxy Server Password)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   serviceName:proxyPasswordServiceName];\n\n\treturn kcPassword;\n}\n\n- (void)writeNicknamePasswordToKeychain\n{\n\tif (self->_nicknamePassword == nil) {\n\t\treturn;\n\t}\n\n\tNSString *nicknamePasswordServiceName = [NSString stringWithFormat:@\"textual.nickserv.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain modifyOrAddKeychainItem:@\"Textual (NickServ)\"\n\t\t\t\t\t\t   withItemKind:@\"application password\"\n\t\t\t\t\t\t\tforUsername:nil\n\t\t\t\t\t\twithNewPassword:self->_nicknamePassword\n\t\t\t\t\t\t\tserviceName:nicknamePasswordServiceName];\n\n\tself->_nicknamePassword = nil;\n}\n\n- (void)writeProxyPasswordToKeychain\n{\n\tif (self->_proxyPassword == nil) {\n\t\treturn;\n\t}\n\n\tNSString *proxyPasswordServiceName = [NSString stringWithFormat:@\"textual.proxy-server.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain modifyOrAddKeychainItem:@\"Textual (Proxy Server Password)\"\n\t\t\t\t\t\t   withItemKind:@\"application password\"\n\t\t\t\t\t\t\tforUsername:nil\n\t\t\t\t\t\twithNewPassword:self->_proxyPassword\n\t\t\t\t\t\t\tserviceName:proxyPasswordServiceName];\n\n\tself->_proxyPassword = nil;\n}\n\n- (void)destroyNicknamePasswordKeychainItem\n{\n\tNSString *nicknamePasswordServiceName = [NSString stringWithFormat:@\"textual.nickserv.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain deleteKeychainItem:@\"Textual (NickServ)\"\n\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t   serviceName:nicknamePasswordServiceName];\n\n\tself->_nicknamePassword = nil;\n}\n\n- (void)destroyProxyPasswordKeychainItem\n{\n\tNSString *proxyPasswordServiceName = [NSString stringWithFormat:@\"textual.proxy-server.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain deleteKeychainItem:@\"Textual (Proxy Server Password)\"\n\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t   serviceName:proxyPasswordServiceName];\n\n\tself->_proxyPassword = nil;\n}\n\n- (void)destroyServerPasswordKeychainItemAfterMigration\n{\n\tif (self->_migratedServerPasswordPendingDestroy == NO) {\n\t\treturn;\n\t}\n\n\tself->_migratedServerPasswordPendingDestroy = NO;\n\n\tNSString *serverPasswordServiceName = [NSString stringWithFormat:@\"textual.server.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain deleteKeychainItem:@\"Textual (Server Password)\"\n\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t   serviceName:serverPasswordServiceName];\n}\n\n#pragma mark -\n#pragma mark Deprecated Properties\n\n- (nullable NSString *)legacyServerAddress\n{\n\tIRCServer *server = self.serverList.firstObject;\n\n\tif (server == nil) {\n\t\treturn self->_serverAddress;\n\t}\n\n\treturn server.serverAddress;\n}\n\n- (uint16_t)legacyServerPort\n{\n\tIRCServer *server = self.serverList.firstObject;\n\n\tif (server == nil) {\n\t\treturn self->_serverPort;\n\t}\n\n\treturn server.serverPort;\n}\n\n- (BOOL)legacyPrefersSecuredConnection\n{\n\tIRCServer *server = self.serverList.firstObject;\n\n\tif (server == nil) {\n\t\treturn self->_prefersSecuredConnection;\n\t}\n\n\treturn server.prefersSecuredConnection;\n}\n\n- (BOOL)legacyConnectionPrefersModernCiphers\n{\n\treturn (self.cipherSuites != RCMCipherSuiteCollectionNone);\n}\n\n- (BOOL)showConnectionPrefersIPv4Warning\n{\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\treturn (self.addressType == IRCConnectionAddressTypeIPv4 && self.connectionPrefersIPv4);\nTEXTUAL_IGNORE_DEPRECATION_END\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCClientConfigMutable\n\n@dynamic addressType;\n@dynamic alternateNicknames;\n@dynamic autoConnect;\n@dynamic autoReconnect;\n@dynamic autoSleepModeDisconnect;\n@dynamic autojoinWaitsForNickServ;\n@dynamic awayNickname;\n@dynamic channelList;\n@dynamic cipherSuites;\n@dynamic connectionName;\n@dynamic connectionPrefersIPv4;\n@dynamic fallbackEncoding;\n@dynamic floodControlDelayTimerInterval;\n@dynamic floodControlMaximumMessages;\n@dynamic hideAutojoinDelayedWarnings;\n@dynamic hideNetworkUnavailabilityNotices;\n@dynamic highlightList;\n@dynamic identityClientSideCertificate;\n@dynamic ignoreList;\n@dynamic lastMessageServerTime;\n@dynamic loginCommands;\n@dynamic nickname;\n@dynamic nicknamePassword;\n@dynamic normalLeavingComment;\n@dynamic performDisconnectOnPongTimer;\n@dynamic performDisconnectOnReachabilityChange;\n@dynamic performPongTimer;\n@dynamic primaryEncoding;\n@dynamic proxyAddress;\n@dynamic proxyPassword;\n@dynamic proxyPort;\n@dynamic proxyType;\n@dynamic proxyUsername;\n@dynamic realName;\n@dynamic saslAuthenticationDisableExternalMechanism;\n@dynamic sendAuthenticationRequestsToUserServ;\n@dynamic sendWhoCommandRequestsToChannels;\n@dynamic serverList;\n@dynamic setInvisibleModeOnConnect;\n@dynamic sidebarItemExpanded;\n@dynamic sleepModeLeavingComment;\n@dynamic username;\n@dynamic validateServerCertificateChain;\n@dynamic zncIgnoreConfiguredAutojoin;\n@dynamic zncIgnorePlaybackNotifications;\n@dynamic zncIgnoreUserNotifications;\n@dynamic zncOnlyPlaybackLatest;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [IRCClientConfig self];\n}\n\n- (void)setAutoConnect:(BOOL)autoConnect\n{\n\tif (self->_autoConnect != autoConnect) {\n\t\tself->_autoConnect = autoConnect;\n\t}\n}\n\n- (void)setAutoReconnect:(BOOL)autoReconnect\n{\n\tif (self->_autoReconnect != autoReconnect) {\n\t\tself->_autoReconnect = autoReconnect;\n\t}\n}\n\n- (void)setAutoSleepModeDisconnect:(BOOL)autoSleepModeDisconnect\n{\n\tif (self->_autoSleepModeDisconnect != autoSleepModeDisconnect) {\n\t\tself->_autoSleepModeDisconnect = autoSleepModeDisconnect;\n\t}\n}\n\n- (void)setAutojoinWaitsForNickServ:(BOOL)autojoinWaitsForNickServ\n{\n\tif (self->_autojoinWaitsForNickServ != autojoinWaitsForNickServ) {\n\t\tself->_autojoinWaitsForNickServ = autojoinWaitsForNickServ;\n\t}\n}\n\n- (void)setConnectionPrefersIPv4:(BOOL)connectionPrefersIPv4\n{\n\tTEXTUAL_DEPRECATED_WARNING\n\n\tif (self->_connectionPrefersIPv4 != connectionPrefersIPv4) {\n\t\tself->_connectionPrefersIPv4 = connectionPrefersIPv4;\n\t}\n}\n\n- (void)setHideAutojoinDelayedWarnings:(BOOL)hideAutojoinDelayedWarnings\n{\n\tif (self->_hideAutojoinDelayedWarnings != hideAutojoinDelayedWarnings) {\n\t\tself->_hideAutojoinDelayedWarnings = hideAutojoinDelayedWarnings;\n\t}\n}\n\n- (void)setHideNetworkUnavailabilityNotices:(BOOL)hideNetworkUnavailabilityNotices\n{\n\tif (self->_hideNetworkUnavailabilityNotices != hideNetworkUnavailabilityNotices) {\n\t\tself->_hideNetworkUnavailabilityNotices = hideNetworkUnavailabilityNotices;\n\t}\n}\n\n- (void)setPerformDisconnectOnPongTimer:(BOOL)performDisconnectOnPongTimer\n{\n\tif (self->_performDisconnectOnPongTimer != performDisconnectOnPongTimer) {\n\t\tself->_performDisconnectOnPongTimer = performDisconnectOnPongTimer;\n\t}\n}\n\n- (void)setPerformDisconnectOnReachabilityChange:(BOOL)performDisconnectOnReachabilityChange\n{\n\tif (self->_performDisconnectOnReachabilityChange != performDisconnectOnReachabilityChange) {\n\t\tself->_performDisconnectOnReachabilityChange = performDisconnectOnReachabilityChange;\n\t}\n}\n\n- (void)setPerformPongTimer:(BOOL)performPongTimer\n{\n\tif (self->_performPongTimer != performPongTimer) {\n\t\tself->_performPongTimer = performPongTimer;\n\t}\n}\n\n- (void)setSaslAuthenticationDisableExternalMechanism:(BOOL)saslAuthenticationDisableExternalMechanism\n{\n\tif (self->_saslAuthenticationDisableExternalMechanism != saslAuthenticationDisableExternalMechanism) {\n\t\tself->_saslAuthenticationDisableExternalMechanism = saslAuthenticationDisableExternalMechanism;\n\t}\n}\n\n- (void)setSendAuthenticationRequestsToUserServ:(BOOL)sendAuthenticationRequestsToUserServ\n{\n\tif (self->_sendAuthenticationRequestsToUserServ != sendAuthenticationRequestsToUserServ) {\n\t\tself->_sendAuthenticationRequestsToUserServ = sendAuthenticationRequestsToUserServ;\n\t}\n}\n\n- (void)setSendWhoCommandRequestsToChannels:(BOOL)sendWhoCommandRequestsToChannels\n{\n\tif (self->_sendWhoCommandRequestsToChannels != sendWhoCommandRequestsToChannels) {\n\t\tself->_sendWhoCommandRequestsToChannels = sendWhoCommandRequestsToChannels;\n\t}\n}\n\n- (void)setSetInvisibleModeOnConnect:(BOOL)setInvisibleModeOnConnect\n{\n\tif (self->_setInvisibleModeOnConnect != setInvisibleModeOnConnect) {\n\t\tself->_setInvisibleModeOnConnect = setInvisibleModeOnConnect;\n\t}\n}\n\n- (void)setSidebarItemExpanded:(BOOL)sidebarItemExpanded\n{\n\tif (self->_sidebarItemExpanded != sidebarItemExpanded) {\n\t\tself->_sidebarItemExpanded = sidebarItemExpanded;\n\t}\n}\n\n- (void)setValidateServerCertificateChain:(BOOL)validateServerCertificateChain\n{\n\tif (self->_validateServerCertificateChain != validateServerCertificateChain) {\n\t\tself->_validateServerCertificateChain = validateServerCertificateChain;\n\t}\n}\n\n- (void)setZncIgnoreConfiguredAutojoin:(BOOL)zncIgnoreConfiguredAutojoin\n{\n\tif (self->_zncIgnoreConfiguredAutojoin != zncIgnoreConfiguredAutojoin) {\n\t\tself->_zncIgnoreConfiguredAutojoin = zncIgnoreConfiguredAutojoin;\n\t}\n}\n\n- (void)setZncIgnorePlaybackNotifications:(BOOL)zncIgnorePlaybackNotifications\n{\n\tif (self->_zncIgnorePlaybackNotifications != zncIgnorePlaybackNotifications) {\n\t\tself->_zncIgnorePlaybackNotifications = zncIgnorePlaybackNotifications;\n\t}\n}\n\n- (void)setZncIgnoreUserNotifications:(BOOL)zncIgnoreUserNotifications\n{\n\tif (self->_zncIgnoreUserNotifications != zncIgnoreUserNotifications) {\n\t\tself->_zncIgnoreUserNotifications = zncIgnoreUserNotifications;\n\t}\n}\n\n- (void)setZncOnlyPlaybackLatest:(BOOL)zncOnlyPlaybackLatest\n{\n\tif (self->_zncOnlyPlaybackLatest != zncOnlyPlaybackLatest) {\n\t\tself->_zncOnlyPlaybackLatest = zncOnlyPlaybackLatest;\n\t}\n}\n\n- (void)setAddressType:(IRCConnectionAddressType)addressType\n{\n\tif (self->_addressType != addressType) {\n\t\tself->_addressType = addressType;\n\t}\n}\n\n- (void)setProxyType:(IRCConnectionProxyType)proxyType\n{\n\tif (self->_proxyType != proxyType) {\n\t\tself->_proxyType = proxyType;\n\t}\n}\n\n- (void)setIgnoreList:(NSArray<IRCAddressBookEntry *> *)ignoreList\n{\n\tNSParameterAssert(ignoreList != nil);\n\n\tif (self->_ignoreList != ignoreList) {\n\t\tself->_ignoreList = [ignoreList copy];\n\t}\n}\n\n- (void)setChannelList:(NSArray<IRCChannelConfig *> *)channelList\n{\n\tNSParameterAssert(channelList != nil);\n\n\tif (self->_channelList != channelList) {\n\t\tself->_channelList = [channelList copy];\n\t}\n}\n\n- (void)setHighlightList:(NSArray<IRCHighlightMatchCondition *> *)highlightList\n{\n\tNSParameterAssert(highlightList != nil);\n\n\tif (self->_highlightList != highlightList) {\n\t\tself->_highlightList = [highlightList copy];\n\t}\n}\n\n- (void)setAlternateNicknames:(NSArray<NSString *> *)alternateNicknames\n{\n\tNSParameterAssert(alternateNicknames != nil);\n\n\tif (self->_alternateNicknames != alternateNicknames) {\n\t\tself->_alternateNicknames = [alternateNicknames copy];\n\t}\n}\n\n- (void)setLoginCommands:(NSArray<NSString *> *)loginCommands\n{\n\tNSParameterAssert(loginCommands != nil);\n\n\tif (self->_loginCommands != loginCommands) {\n\t\tself->_loginCommands = [loginCommands copy];\n\t}\n}\n\n- (void)setServerList:(NSArray<IRCServer *> *)serverList\n{\n\tNSParameterAssert(serverList != nil);\n\n\tif (self->_serverList != serverList) {\n\t\tself->_serverList = [serverList copy];\n\t}\n}\n\n- (void)setIdentityClientSideCertificate:(nullable NSData *)identityClientSideCertificate\n{\n\tif (self->_identityClientSideCertificate != identityClientSideCertificate) {\n\t\tself->_identityClientSideCertificate = [identityClientSideCertificate copy];\n\t}\n}\n\n- (void)setAwayNickname:(nullable NSString *)awayNickname\n{\n\tif (self->_awayNickname != awayNickname) {\n\t\tself->_awayNickname = [awayNickname copy];\n\t}\n}\n\n- (void)setConnectionName:(NSString *)connectionName\n{\n\tNSParameterAssert(connectionName != nil);\n\n\tif (self->_connectionName != connectionName) {\n\t\tself->_connectionName = [connectionName copy];\n\t}\n}\n\n- (void)setNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self->_nickname != nickname) {\n\t\tself->_nickname = [nickname copy];\n\t}\n}\n\n- (void)setNicknamePassword:(nullable NSString *)nicknamePassword\n{\n\tif (self->_nicknamePassword != nicknamePassword) {\n\t\tself->_nicknamePassword = [nicknamePassword copy];\n\t}\n}\n\n- (void)setNormalLeavingComment:(NSString *)normalLeavingComment\n{\n\tNSParameterAssert(normalLeavingComment != nil);\n\n\tif (self->_normalLeavingComment != normalLeavingComment) {\n\t\tself->_normalLeavingComment = [normalLeavingComment copy];\n\t}\n}\n\n- (void)setProxyAddress:(nullable NSString *)proxyAddress\n{\n\tif (self->_proxyAddress != proxyAddress) {\n\t\tself->_proxyAddress = [proxyAddress copy];\n\t}\n}\n\n- (void)setProxyPassword:(nullable NSString *)proxyPassword\n{\n\tif (self->_proxyPassword != proxyPassword) {\n\t\tself->_proxyPassword = [proxyPassword copy];\n\t}\n}\n\n- (void)setProxyUsername:(nullable NSString *)proxyUsername\n{\n\tif (self->_proxyUsername != proxyUsername) {\n\t\tself->_proxyUsername = [proxyUsername copy];\n\t}\n}\n\n- (void)setRealName:(NSString *)realName\n{\n\tNSParameterAssert(realName != nil);\n\n\tif (self->_realName != realName) {\n\t\tself->_realName = [realName copy];\n\t}\n}\n\n- (void)setSleepModeLeavingComment:(NSString *)sleepModeLeavingComment\n{\n\tNSParameterAssert(sleepModeLeavingComment != nil);\n\n\tif (self->_sleepModeLeavingComment != sleepModeLeavingComment) {\n\t\tself->_sleepModeLeavingComment = [sleepModeLeavingComment copy];\n\t}\n}\n\n- (void)setUsername:(NSString *)username\n{\n\tNSParameterAssert(username != nil);\n\n\tif (self->_username != username) {\n\t\tself->_username = [username copy];\n\t}\n}\n\n- (void)setFallbackEncoding:(NSStringEncoding)fallbackEncoding\n{\n\tif (self->_fallbackEncoding != fallbackEncoding) {\n\t\tself->_fallbackEncoding = fallbackEncoding;\n\t}\n}\n\n- (void)setPrimaryEncoding:(NSStringEncoding)primaryEncoding\n{\n\tif (self->_primaryEncoding != primaryEncoding) {\n\t\tself->_primaryEncoding = primaryEncoding;\n\t}\n}\n\n- (void)setLastMessageServerTime:(NSTimeInterval)lastMessageServerTime\n{\n\tif (self->_lastMessageServerTime != lastMessageServerTime) {\n\t\tself->_lastMessageServerTime = lastMessageServerTime;\n\t}\n}\n\n- (void)setFloodControlDelayTimerInterval:(NSUInteger)floodControlDelayTimerInterval\n{\n\tNSParameterAssert(floodControlDelayTimerInterval >= IRCConnectionConfigFloodControlMinimumDelayInterval &&\n\t\t\t\t\t  floodControlDelayTimerInterval <= IRCConnectionConfigFloodControlMaximumDelayInterval);\n\n\tif (self->_floodControlDelayTimerInterval != floodControlDelayTimerInterval) {\n\t\tself->_floodControlDelayTimerInterval = floodControlDelayTimerInterval;\n\t}\n}\n\n- (void)setFloodControlMaximumMessages:(NSUInteger)floodControlMaximumMessages\n{\n\tNSParameterAssert(floodControlMaximumMessages >= IRCConnectionConfigFloodControlMinimumMessageCount &&\n\t\t\t\t\t  floodControlMaximumMessages <= IRCConnectionConfigFloodControlMaximumMessageCount);\n\n\tif (self->_floodControlMaximumMessages != floodControlMaximumMessages) {\n\t\tself->_floodControlMaximumMessages = floodControlMaximumMessages;\n\t}\n}\n\n- (void)setProxyPort:(uint16_t)proxyPort\n{\n\tif (self->_proxyPort != proxyPort) {\n\t\tself->_proxyPort = proxyPort;\n\t}\n}\n\n- (void)setCipherSuites:(RCMCipherSuiteCollection)cipherSuites\n{\n\tif (self->_cipherSuites != cipherSuites) {\n\t\tself->_cipherSuites = cipherSuites;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCClientRequestedCommands.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientRequestedCommandsPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, IRCClientRequestedCommandVisibility)\n{\n\tIRCClientRequestedCommandVisibilityUnknown = 0,\n\tIRCClientRequestedCommandVisibilityHidden,\n\tIRCClientRequestedCommandVisibilityVisible\n};\n\n@interface IRCClientRequestedCommand : NSObject\n@property (nonatomic, assign) IRCRemoteCommand command;\n@property (nonatomic, assign) BOOL hiddenResponse;\n@property (nonatomic, assign) BOOL enforceCount;\n@property (nonatomic, assign) NSUInteger count;\n@end\n\n@interface IRCClientRequestedCommands ()\n/* We could use a dictionary or cache with command as key\n and an array of objects for the assigned object but that\n is much more complex than just scanning a one level array. */\n@property (nonatomic, strong) NSMutableArray<IRCClientRequestedCommand *> *invokedCommandsInt;\n@end\n\n@implementation IRCClientRequestedCommands\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.invokedCommandsInt = [NSMutableArray array];\n}\n\n- (nullable IRCClientRequestedCommand *)findCommand:(IRCRemoteCommand)command\n{\n\t@synchronized (self.invokedCommandsInt) {\n\t\treturn [self.invokedCommandsInt objectPassingTest:^BOOL(IRCClientRequestedCommand *object, NSUInteger index, BOOL *stop) {\n\t\t\treturn (object.command == command);\n\t\t}];\n\t}\n}\n\n- (void)addCommand:(IRCRemoteCommand)command hiddenResponse:(BOOL)hiddenResponse\n{\n\t[self addCommand:command withCount:0 hiddenResponse:hiddenResponse];\n}\n\n- (void)addCommand:(IRCRemoteCommand)command withCount:(NSUInteger)count hiddenResponse:(BOOL)hiddenResponse\n{\n\tIRCClientRequestedCommand *commandObject = [IRCClientRequestedCommand new];\n\n\tcommandObject.command = command;\n\tcommandObject.hiddenResponse = hiddenResponse;\n\tcommandObject.enforceCount = (count > 0);\n\tcommandObject.count = count;\n\n\t@synchronized (self.invokedCommandsInt) {\n\t\t[self.invokedCommandsInt addObject:commandObject];\n\t}\n}\n\n- (void)removeCommands\n{\n\t@synchronized (self.invokedCommandsInt) {\n\t\t[self.invokedCommandsInt removeAllObjects];\n\t}\n}\n\n- (void)removeCommand:(IRCRemoteCommand)command\n{\n\t/* There can be multiple commands with same context.\n\t When we remove, we remove the first that is matched and let next\n\t pass of responses remove the others. */\n\tIRCClientRequestedCommand *commandObject = [self findCommand:command];\n\n\tif (commandObject == nil) {\n\t\treturn;\n\t}\n\n\t[self removeCommandObject:commandObject];\n}\n\n- (void)removeCommandObject:(IRCClientRequestedCommand *)commandObject\n{\n\tNSParameterAssert(commandObject != nil);\n\n\t@synchronized (self.invokedCommandsInt) {\n\t\t[self.invokedCommandsInt removeObject:commandObject];\n\t}\n}\n\n- (void)decrementCommandCount:(IRCRemoteCommand)command\n{\n\tIRCClientRequestedCommand *commandObject = [self findCommand:command];\n\n\tif (commandObject == nil) {\n\t\treturn;\n\t}\n\n\tif (commandObject.enforceCount == NO) {\n\t\treturn;\n\t}\n\n\tcommandObject.count -= 1;\n\n\tif (commandObject.count == 0) {\n\t\t[self removeCommandObject:commandObject];\n\t}\n}\n\n- (IRCClientRequestedCommandVisibility)commandHiddenState:(IRCRemoteCommand)command\n{\n\tIRCClientRequestedCommand *commandObject = [self findCommand:command];\n\n\tif (commandObject == nil) {\n\t\treturn IRCClientRequestedCommandVisibilityUnknown;\n\t}\n\n\tif (commandObject.hiddenResponse == NO) {\n\t\treturn IRCClientRequestedCommandVisibilityVisible;\n\t} else {\n\t\treturn IRCClientRequestedCommandVisibilityHidden;\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCClientRequestedCommands (Helpers)\n\n- (BOOL)inVisibleIsonRequest\n{\n\treturn ([self commandHiddenState:IRCRemoteCommandIson] == IRCClientRequestedCommandVisibilityVisible);\n}\n\n- (void)recordIsonRequestOpened\n{\n\t[self addCommand:IRCRemoteCommandIson hiddenResponse:YES];\n}\n\n- (void)recordIsonRequestOpenedAsVisible\n{\n\t[self addCommand:IRCRemoteCommandIson hiddenResponse:NO];\n}\n\n- (void)recordIsonRequestClosed\n{\n\t[self removeCommand:IRCRemoteCommandIson];\n}\n\n#if 0\n- (BOOL)inVisibleMonitorRequest\n{\n\treturn ([self commandHiddenState:IRCRemoteCommandMonitor] == IRCClientRequestedCommandVisibilityVisible);\n}\n\n- (void)recordMonitorRequestOpened\n{\n\t[self addCommand:IRCRemoteCommandMonitor hiddenResponse:YES];\n}\n\n- (void)recordMonitorRequestOpenedWithCount:(NSUInteger)count\n{\n\tNSParameterAssert(count > 0);\n\n\t[self addCommand:IRCRemoteCommandMonitor withCount:count hiddenResponse:YES];\n}\n\n- (void)recordMonitorRequestOpenedAsVisibleWithCount:(NSUInteger)count\n{\n\tNSParameterAssert(count > 0);\n\n\t[self addCommand:IRCRemoteCommandMonitor withCount:count hiddenResponse:NO];\n}\n\n- (void)recordMonitorRequestOpenedAsVisible\n{\n\t[self addCommand:IRCRemoteCommandMonitor hiddenResponse:NO];\n}\n\n- (void)recordMonitorRequestClosedOne\n{\n\t[self decrementCommandCount:IRCRemoteCommandMonitor];\n}\n\n- (void)recordMonitorRequestClosed\n{\n\t[self removeCommand:IRCRemoteCommandMonitor];\n}\n\n- (BOOL)inVisibleNamesRequest\n{\n\treturn ([self commandHiddenState:IRCRemoteCommandNames] == IRCClientRequestedCommandVisibilityVisible);\n}\n\n- (void)recordNamesRequestOpened\n{\n\t[self addCommand:IRCRemoteCommandNames hiddenResponse:YES];\n}\n\n- (void)recordNamesRequestOpenedAsVisible\n{\n\t[self addCommand:IRCRemoteCommandNames hiddenResponse:NO];\n}\n\n- (void)recordNamesRequestClosed\n{\n\t[self removeCommand:IRCRemoteCommandNames];\n}\n\n- (BOOL)inVisibleWatchRequest\n{\n\treturn ([self commandHiddenState:IRCRemoteCommandWatch] == IRCClientRequestedCommandVisibilityVisible);\n}\n\n- (void)recordWatchRequestOpened\n{\n\t[self addCommand:IRCRemoteCommandWatch hiddenResponse:YES];\n}\n\n- (void)recordWatchRequestOpenedWithCount:(NSUInteger)count\n{\n\tNSParameterAssert(count > 0);\n\n\t[self addCommand:IRCRemoteCommandWatch withCount:count hiddenResponse:YES];\n}\n\n- (void)recordWatchRequestOpenedAsVisibleWithCount:(NSUInteger)count\n{\n\tNSParameterAssert(count > 0);\n\n\t[self addCommand:IRCRemoteCommandWatch withCount:count hiddenResponse:NO];\n}\n\n- (void)recordWatchRequestOpenedAsVisible\n{\n\t[self addCommand:IRCRemoteCommandWatch hiddenResponse:NO];\n}\n\n- (void)recordWatchRequestClosedOne\n{\n\t[self decrementCommandCount:IRCRemoteCommandWatch];\n}\n\n- (void)recordWatchRequestClosed\n{\n\t[self removeCommand:IRCRemoteCommandWatch];\n}\n#endif\n\n- (BOOL)inVisibleWhoRequest\n{\n\treturn ([self commandHiddenState:IRCRemoteCommandWho] == IRCClientRequestedCommandVisibilityVisible);\n}\n\n- (void)recordWhoRequestOpened\n{\n\t[self addCommand:IRCRemoteCommandWho hiddenResponse:YES];\n}\n\n- (void)recordWhoRequestOpenedAsVisible\n{\n\t[self addCommand:IRCRemoteCommandWho hiddenResponse:NO];\n}\n\n- (void)recordWhoRequestClosed\n{\n\t[self removeCommand:IRCRemoteCommandWho];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCClientRequestedCommand\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCCommandIndex.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCResourceManager.h\"\n#import \"IRCCommandIndexPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _reservedSlotDictionaryKey\t\t\t@\"Reserved Information\"\n\n@implementation IRCCommandIndex\n\nstatic NSArray * _Nullable _cachedLocalCommandList = nil;\n\nstatic NSDictionary *IRCCommandIndexLocalData = nil;\nstatic NSDictionary *IRCCommandIndexRemoteData = nil;\n\n+ (void)populateCommandIndex\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t[self _populateCommandIndex];\n\t});\n}\n\n+ (void)_populateCommandIndex\n{\n\t/* Populate public data */\n\tNSDictionary *publicValues = [TPCResourceManager dictionaryFromResources:@\"IRCCommandIndexLocalData\" cacheValue:NO];\n\n\tif (publicValues) {\n\t\tNSMutableDictionary *publicValuesMutable = [publicValues mutableCopy];\n\n\t\t[publicValuesMutable removeObjectForKey:_reservedSlotDictionaryKey];\n\n\t\tIRCCommandIndexLocalData = [publicValuesMutable copy];\n\t}\n\n\t/* Populate private data */\n\tNSDictionary *privateValues = [TPCResourceManager dictionaryFromResources:@\"IRCCommandIndexRemoteData\" cacheValue:NO];\n\n\tif (privateValues) {\n\t\tNSMutableDictionary *privateValuesMutable = [privateValues mutableCopy];\n\n\t\t[privateValuesMutable removeObjectForKey:_reservedSlotDictionaryKey];\n\n\t\tIRCCommandIndexRemoteData = [privateValuesMutable copy];\n\t}\n\n\t/* Only error checking we need. It either fails or succeeds. */\n\tNSParameterAssert(IRCCommandIndexRemoteData != nil);\n\tNSParameterAssert(IRCCommandIndexLocalData != nil);\n}\n\n+ (void)invalidateCaches\n{\n\t_cachedLocalCommandList = nil;\n}\n\n+ (void)rebuildLocalCommandList\n{\n\tNSMutableArray<NSString *> *commandList = [NSMutableArray array];\n\t\n\tBOOL developerModeEnabled = [TPCPreferences developerModeEnabled];\n\t\n\t[IRCCommandIndexLocalData enumerateKeysAndObjectsUsingBlock:^(NSString *indexKey, NSDictionary *indexValue, BOOL *stop) {\n\t\tBOOL developerOnly = [indexValue boolForKey:@\"developerModeOnly\"];\n\t\t\n\t\tif (developerModeEnabled == NO && developerOnly) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t[commandList addObject:indexKey.uppercaseString];\n\t}];\n\t\n\t_cachedLocalCommandList = [commandList copy];\n}\n\n+ (NSArray<NSString *> *)localCommandList\n{\n\tif (_cachedLocalCommandList == nil) {\n\t\t[self rebuildLocalCommandList];\n\t}\n\n\treturn _cachedLocalCommandList;\n}\n\n+ (NSUInteger)indexOfLocalCommand:(NSString *)command\n{\n\treturn [self indexOfCommand:command isLocal:YES];\n}\n\n+ (NSUInteger)indexOfRemoteCommand:(NSString *)command\n{\n\treturn [self indexOfCommand:command isLocal:NO];\n}\n\n+ (NSUInteger)indexOfCommand:(NSString *)command isLocal:(BOOL)isLocalCommand\n{\n\tNSDictionary *index = nil;\n\t\n\tif (isLocalCommand) {\n\t\tindex = IRCCommandIndexLocalData[command.lowercaseString];\n\t} else {\n\t\tindex = IRCCommandIndexRemoteData[command.lowercaseString];\n\t}\n\t\n\tif (index == nil) {\n\t\treturn NSNotFound;\n\t}\n\t\n\tif (isLocalCommand) {\n\t\tif ([index boolForKey:@\"developerModeOnly\"] && [TPCPreferences developerModeEnabled] == NO) {\n\t\t\treturn NSNotFound;\n\t\t}\n\t}\n\t\n\treturn [index unsignedIntegerForKey:@\"indexValue\"];\n}\n\n+ (NSUInteger)colonPositionForRemoteCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tNSDictionary *index = IRCCommandIndexRemoteData[command.lowercaseString];\n\t\n\tif (index == nil) {\n\t\treturn NSNotFound;\n\t}\n\t\n\tNSInteger position = [index integerForKey:@\"outgoingColonIndex\"];\n\t\n\tif (position < 0) {\n\t\treturn NSNotFound;\n\t}\n\t\n\treturn position;\n}\n\n+ (nullable NSString *)syntaxForLocalCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tNSDictionary *index = IRCCommandIndexLocalData[command.lowercaseString];\n\n\tif (index == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *commandFormatted = command.uppercaseString;\n\n\tNSString *argumentFormat = index[@\"arguments\"];\n\t\n\tif (argumentFormat) {\n\t\treturn [NSString stringWithFormat:@\"%@ %@\", commandFormatted, argumentFormat];\n\t}\n\t\n\treturn commandFormatted;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCConnection.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"RCMConnectionManagerProtocol.h\"\n\n#import <objc/message.h>\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"GCDAsyncSocketExtensions.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCConnectionErrors.h\"\n#import \"IRCConnectionPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCConnection ()\n@property (nonatomic, weak, readwrite) IRCClient *client;\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@property (nonatomic, strong, nullable) SFCertificateTrustPanel *trustPanel;\n@property (nonatomic, assign) BOOL trustPanelDoNotInvokeCompletionBlock;\n@property (nonatomic, assign) BOOL connectionInvalidatedVoluntarily;\n@property (nonatomic, copy, readwrite) NSString *uniqueIdentifier;\n@end\n\n@implementation IRCConnection\n\n#pragma mark -\n#pragma mark Initialization \n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithConfig:(IRCConnectionConfig *)config onClient:(IRCClient *)client\n{\n\tNSParameterAssert(config != nil);\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\n\t\tself.config = config;\n\t\t\n\t\tself.uniqueIdentifier = [NSString stringWithUUID];\n\t}\n\n\treturn self;\n}\n\n- (void)resetState\n{\n\tself.isConnecting = NO;\n\tself.isConnected = NO;\n\tself.isConnectedWithClientSideCertificate = NO;\n\tself.isDisconnecting = NO;\n\tself.EOFReceived = NO;\n\tself.isSecured = NO;\n\tself.isSending = NO;\n\n\tself.connectedAddress = nil;\n\n\tself.connectionInvalidatedVoluntarily = NO;\n}\n\n#pragma mark -\n#pragma mark Process Management\n\n- (void)invalidateProcess\n{\n\tif (self.serviceConnection == nil) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Invalidating process...\");\n\n\t[self.serviceConnection invalidate];\n}\n\n- (void)warmProcessIfNeeded\n{\n\tif (self.serviceConnection != nil) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Warming process...\");\n\n\t[self warmProcess];\n}\n\n- (void)warmProcess\n{\n\tNSXPCConnection *serviceConnection = [[NSXPCConnection alloc] initWithServiceName:@\"com.codeux.app-utilities.Textual-IRCConnectionHost\"];\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(RCMConnectionManagerServerProtocol)];\n\n\tserviceConnection.remoteObjectInterface = remoteObjectInterface;\n\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(RCMConnectionManagerClientProtocol)];\n\n\tserviceConnection.exportedInterface = exportedInterface;\n\n\tserviceConnection.exportedObject = self;\n\n\tserviceConnection.interruptionHandler = ^{\n\t\t[self interruptionHandler];\n\n\t\tLogToConsole(\"Interruption handler called\");\n\t};\n\n\tserviceConnection.invalidationHandler = ^{\n\t\t[self invalidationHandler];\n\n\t\tLogToConsole(\"Invalidation handler called\");\n\t};\n\n\t[serviceConnection resume];\n\n\tself.serviceConnection = serviceConnection;\n}\n\n- (void)interruptionHandler\n{\n\t[self invalidateProcess];\n}\n\n- (void)invalidationHandler\n{\n\tself.serviceConnection = nil;\n\n\t/* -ircConnectionDidDisconnectWithError: instructs the process to\n\t voluntarily invalidate, so if we reach here, then its pretty certain\n\t something big happened and we need to let the client know. */\n\tif ((self.isConnecting || self.isConnected) &&\n\t\tself.connectionInvalidatedVoluntarily == NO)\n\t{\n\t\tNSString *errorMessage = TXTLS(@\"IRC[vdy-jk]\");\n\n\t\tNSError *error = [NSError errorWithDomain:IRCConnectionErrorDomain\n\t\t\t\t\t\t\t\t\t\t\t code:IRCConnectionErrorCodeOther\n\t\t\t\t\t\t\t\t\t\t userInfo:@{ NSLocalizedDescriptionKey : errorMessage }];\n\n\t\t[self _ircConnectionDidDisconnectWithError:error];\n\t}\n\n\t[self resetState];\n}\n\n- (id <RCMConnectionManagerServerProtocol>)remoteObjectProxy\n{\n\treturn [self remoteObjectProxyWithErrorHandler:nil];\n}\n\n- (id <RCMConnectionManagerServerProtocol>)remoteObjectProxyWithErrorHandler:(void (^ _Nullable)(NSError *error))handler\n{\n\treturn [self.serviceConnection remoteObjectProxyWithErrorHandler:^(NSError *error) {\n\t\tLogToConsoleError(\"Error occurred while communicating with service: %{public}@\",\n\t\t\t  error.localizedDescription);\n\n\t\tif (handler) {\n\t\t\thandler(error);\n\t\t}\n\t}];\n}\n\n#pragma mark -\n#pragma mark Open/Close Connection\n\n- (void)open\n{\n\tif (self.isConnecting || self.isConnected || self.isDisconnecting) {\n\t\treturn;\n\t}\n\n\t[self warmProcessIfNeeded];\n\n\tself.isConnecting = YES;\n\n\t[[self remoteObjectProxy] openWithConfig:self.config];\n\n\tif ([TPCPreferences appNapEnabled] == NO) {\n\t\t[[self remoteObjectProxy] disableAppNap];\n\t}\n\n\t[[self remoteObjectProxy] disableSuddenTermination];\n}\n\n- (void)close\n{\n\tif (self.isDisconnecting) {\n\t\treturn;\n\t}\n\n\tif (self.isConnecting || self.isConnected) {\n\t\t/* Disconnect caused by calling -close on the service will\n\t\t cause -ircConnectionDidDisconnectWithError: to invoke\n\t\t -invalidateProcess for us, so don't call it on this condition. */\n\t\tself.isDisconnecting = YES;\n\n\t\t[[self remoteObjectProxy] close];\n\t} else {\n\t\t[self invalidateProcess];\n\t}\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)enforceFloodControl\n{\n\tif (self.isConnected == NO) {\n\t\treturn;\n\t}\n\n\t[[self remoteObjectProxy] enforceFloodControl];\n}\n\n- (void)openSecuredConnectionCertificateModal\n{\n\t[[self remoteObjectProxy] exportSecureConnectionInformation:^(NSString * _Nullable policyName, tls_protocol_version_t protocolType, tls_ciphersuite_t cipherSuites, NSArray<NSData *> *certificateChain) {\n\t\tif (policyName == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tSecTrustRef trustRef = [RCMSecureTransport trustFromCertificateChain:certificateChain withPolicyName:policyName];\n\n\t\tif (trustRef == NULL) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *protocolDescription = [RCMSecureTransport descriptionForProtocolType:protocolType];\n\n\t\tNSString *cipherDescription = [RCMSecureTransport descriptionForCipherSuite:cipherSuites];\n\n\t\tif (protocolDescription == nil || cipherDescription == nil) {\n\t\t\tCFRelease(trustRef);\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *protocolSummary = nil;\n\n\t\tif ([RCMSecureTransport isCipherSuiteDeprecated:cipherSuites] == NO) {\n\t\t\tprotocolSummary = TXTLS(@\"Prompts[2jq-t5]\", protocolDescription, cipherDescription);\n\t\t} else {\n\t\t\tprotocolSummary = TXTLS(@\"Prompts[8ou-pu]\", protocolDescription, cipherDescription);\n\t\t}\n\n\t\tNSString *defaultButtonTitle = TXTLS(@\"Prompts[aqw-q1]\");\n\t\tNSString *alternateButtonTitle = nil;\n\n\t\tNSString *promptTitleText = TXTLS(@\"Prompts[sfx-xx]\", policyName);\n\t\tNSString *promptInformativeText = nil;\n\n\t\tif (protocolSummary == nil) {\n\t\t\tpromptInformativeText = TXTLS(@\"Prompts[ihy-mz]\", policyName);\n\t\t} else {\n\t\t\tpromptInformativeText = TXTLS(@\"Prompts[iun-45]\", policyName, protocolSummary);\n\t\t}\n\n\t\t__block NSWindow *window = nil;\n\n\t\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t\twindow = [NSApp keyWindow];\n\t\t});\n\n\t\t(void)\n\t\t[RCMTrustPanel presentTrustPanelInWindow:window\n\t\t\t\t\t\t\t\t\t\t\tbody:promptInformativeText\n\t\t\t\t\t\t\t\t\t\t   title:promptTitleText\n\t\t\t\t\t\t\t\t   defaultButton:defaultButtonTitle\n\t\t\t\t\t\t\t\t alternateButton:alternateButtonTitle\n\t\t\t\t\t\t\t\t\t\ttrustRef:trustRef\n\t\t\t\t\t\t\t\t completionBlock:^(SecTrustRef trustRef, BOOL trusted, id contextInfo) {\n\t\t\t\t\t\t\t\t\t CFRelease(trustRef);\n\t\t\t\t\t\t\t\t }];\n\t}];\n}\n\n- (void)openInsecureCertificateTrustPanel:(RCMTrustResponse)trustBlock\n{\n\tif (self.trustPanel != nil) {\n\t\treturn;\n\t}\n\n\t[[self remoteObjectProxy] exportSecureConnectionInformation:^(NSString * _Nullable policyName, tls_protocol_version_t protocolType, tls_ciphersuite_t cipherSuites, NSArray<NSData *> *certificateChain) {\n\t\tif (policyName == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tSecTrustRef trustRef = [RCMSecureTransport trustFromCertificateChain:certificateChain withPolicyName:policyName];\n\n\t\tif (trustRef == NULL) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *defaultButtonTitle = TXTLS(@\"Prompts[zjw-bd]\");\n\t\tNSString *alternateButtonTitle = TXTLS(@\"Prompts[qso-2g]\");\n\n\t\tNSString *promptTitleText = TXTLS(@\"Prompts[m8b-58]\", policyName);\n\t\tNSString *promptInformativeText = TXTLS(@\"Prompts[85z-qw]\", policyName);\n\n\t\t__weak typeof(self) weakSelf = self;\n\n\t\tself.trustPanel =\n\t\t[RCMTrustPanel presentTrustPanelInWindow:nil\n\t\t\t\t\t\t\t\t\t\t\tbody:promptInformativeText\n\t\t\t\t\t\t\t\t\t\t   title:promptTitleText\n\t\t\t\t\t\t\t\t   defaultButton:defaultButtonTitle\n\t\t\t\t\t\t\t\t alternateButton:alternateButtonTitle\n\t\t\t\t\t\t\t\t\t\ttrustRef:trustRef\n\t\t\t\t\t\t\t\t completionBlock:^(SecTrustRef trustRef, BOOL trusted, id contextInfo) {\n\t\t\t\t\t\t\t\t\t CFRelease(trustRef);\n\n\t\t\t\t\t\t\t\t\t weakSelf.trustPanel = nil;\n\n\t\t\t\t\t\t\t\t\t if (weakSelf.trustPanelDoNotInvokeCompletionBlock) {\n\t\t\t\t\t\t\t\t\t\t weakSelf.trustPanelDoNotInvokeCompletionBlock = NO;\n\n\t\t\t\t\t\t\t\t\t\t return;\n\t\t\t\t\t\t\t\t\t }\n\n\t\t\t\t\t\t\t\t\t ((RCMTrustResponse)contextInfo)(trusted);\n\t\t\t\t\t\t\t\t }\n\t\t\t\t\t\t\t\t\t contextInfo:trustBlock];\n\t}];\n}\n\n- (void)closeInsecureCertificateTrustPanel\n{\n\tif (self.trustPanel == nil) {\n\t\treturn;\n\t}\n\n\tSEL dismissSelector = NSSelectorFromString(@\"_dismissWithCode:\");\n\n\tif ([self.trustPanel respondsToSelector:dismissSelector]) {\n\t\tself.trustPanelDoNotInvokeCompletionBlock = YES;\n\n\t\tNSMethodSignature *signature = [self.trustPanel methodSignatureForSelector:dismissSelector];\n\n\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t[invocation setTarget:self.trustPanel];\n\t\t[invocation setSelector:dismissSelector];\n\n\t\tNSModalResponse cancel = NSModalResponseCancel;\n\t\t[invocation setArgument:&cancel atIndex:2];\n\n\t\t[invocation invoke];\n\t}\n}\n\n#pragma mark -\n#pragma mark Encode Data\n\n- (nullable NSString *)convertFromCommonEncoding:(NSData *)data\n{\n\treturn [self.client convertFromCommonEncoding:data];\n}\n\n- (nullable NSData *)convertToCommonEncoding:(NSString *)data\n{\n\treturn [self.client convertToCommonEncoding:data];\n}\n\n#pragma mark -\n#pragma mark Send Data\n\n- (void)sendLine:(NSString *)line\n{\n\tNSParameterAssert(line != nil);\n\n\tline = [line stringByAppendingString:@\"\\x0d\\x0a\"];\n\n\tNSData *dataToSend = [self convertToCommonEncoding:line];\n\n\tif (dataToSend == nil) {\n\t\treturn;\n\t}\n\n\tself.isSending = YES;\n\n\t/* PONG replies are extremely important. There is no reason they should be\n\t placed in the flood control queue. This writes them directly to the socket\n\t instead of actually waiting for the queue. We only need this check if\n\t we actually have flood control enabled. */\n\tif ([line hasPrefix:@\"PONG\"]) {\n\t\t[[self remoteObjectProxy] sendData:dataToSend bypassQueue:YES];\n\n\t\treturn;\n\t}\n\n\t[[self remoteObjectProxy] sendData:dataToSend];\n}\n\n- (void)clearSendQueue\n{\n\t[[self remoteObjectProxy] clearSendQueue];\n}\n\n#pragma mark -\n#pragma mark Socket Delegate\n\n- (void)ircConnectionWillConnectToProxy:(NSString *)proxyHost port:(uint16_t)proxyPort\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self.client ircConnection:self willConnectToProxy:proxyHost port:proxyPort];\n\t});\n}\n\n- (void)ircConnectionDidConnectToHost:(nullable NSString *)host\n{\n\tself.connectedAddress = host;\n\n\tself.isConnecting = NO;\n\tself.isConnected = YES;\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self.client ircConnectionDidConnect:self];\n\t});\n}\n\n- (void)ircConnectionDidSecureConnectionWithProtocolType:(tls_protocol_version_t)protocolType cipherSuite:(tls_ciphersuite_t)cipherSuite\n{\n\tself.isSecured = YES;\n\n\tif (self.config.identityClientSideCertificate != nil) {\n\t\tself.isConnectedWithClientSideCertificate = YES;\n\t}\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self.client ircConnectionDidSecureConnection:self withProtocolType:protocolType cipherSuite:cipherSuite];\n\t});\n}\n\n- (void)ircConnectionDidCloseReadStream\n{\n\tself.EOFReceived = YES;\n\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self.client ircConnectionDidCloseReadStream:self];\n\t});\n}\n\n- (void)ircConnectionDidDisconnectWithError:(nullable NSError *)disconnectError\n{\n\tself.connectionInvalidatedVoluntarily = YES;\n\n\t[self invalidateProcess];\n\n\t[self _ircConnectionDidDisconnectWithError:disconnectError];\n}\n\n- (void)_ircConnectionDidDisconnectWithError:(nullable NSError *)disconnectError\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self closeInsecureCertificateTrustPanel];\n\n\t\t[self.client ircConnection:self didDisconnectWithError:disconnectError];\n\t});\n}\n\n- (void)ircConnectionDidReceiveData:(NSData *)data\n{\n\t/* IRCClient performs call to main thread later in stack. */\n\tNSString *dataString = [self convertFromCommonEncoding:data];\n\n\tif (dataString == nil) {\n\t\treturn;\n\t}\n\n\t[self.client ircConnection:self didReceiveData:dataString];\n}\n\n- (void)ircConnectionRequestInsecureCertificateTrust:(RCMTrustResponse)trustBlock\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[self openInsecureCertificateTrustPanel:trustBlock];\n\t});\n}\n\n- (void)ircConnectionWillSendData:(NSData *)data\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\tNSString *dataString = [self convertFromCommonEncoding:data];\n\n\t\tif (dataString == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.client ircConnection:self willSendData:dataString];\n\t});\n}\n\n- (void)ircConnectionDidSendData\n{\n\tself.isSending = NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCExtras.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TDCAlert.h\"\n#import \"TPCPathInfo.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TVCMainWindow.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelConfig.h\"\n#import \"IRCChannel.h\"\n#import \"IRCServer.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"IRCExtrasPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCExtras\n\n+ (void)performSpecialActionForTextualScheme:(NSString *)action source:(NSString *)sourceLocation\n{\n/*\n\tSyntax: textual://<token>\n\n\tReserved tokens:\n\n\tacknowledgements\t\t\t\t\t— Open acknowledgements file\n\tactivate-license\t\t\t\t\t— Activate a license key\n\tapplication-support-folder\t\t\t— Open the Application Support folder\n\tcontributors\t\t\t\t\t\t— Open contributors file\n\tcustom-scripts-folder\t\t\t\t– Open the custom scripts storage location folder\n\tcustom-style-folder\t\t\t\t\t— Open the custom style storage location folder\n\tcustom-styles-folder\t\t\t\t— Open the custom style storage location folder\n\tdiagnostic-reports-folder\t\t\t— System diagnostic reports folder\n\tgoto \t\t\t\t\t\t\t\t— Navigate to an item\n\tknowledge-base\t\t\t\t\t\t— Open the homepage of our knowledge base\n\tnewsletter\t\t\t\t\t\t\t— Open the subscription page for the newsletter\n\tsupport-channel\t\t\t\t\t\t— Connect to the #textual channel\n\ttesting-channel\t\t\t\t\t\t— Connect to the #textual-testing channel\n\tunsupervised-script-folder\t\t\t— Open the custom scripts storage location folder\n\tunsupervised-scripts-folder\t\t\t— Open the custom scripts storage location folder\n*/\n\n\tif ([action isEqualToString:@\"acknowledgements\"])\n\t{\n\t\t[menuController() openAcknowledgements:nil];\n\t}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\telse if ([action isEqualToString:@\"activate-license\"])\n\t{\n\t\tNSURL *licenseKeyURL = [NSURL URLWithString:sourceLocation];\n\n\t\t[menuController() manageLicense:nil activateLicenseKeyWithURL:licenseKeyURL];\n\t}\n#endif\n\n\telse if ([action isEqualToString:@\"application-support-folder\"])\n\t{\n\t\t[RZWorkspace() openURL:[TPCPathInfo groupContainerApplicationSupportURL]];\n\t}\n\telse if ([action isEqualToString:@\"contributors\"])\n\t{\n\t\t[menuController() openAcknowledgements:nil];\n\t}\n\telse if ([action isEqualToString:@\"custom-scripts-folder\"] ||\n\t\t\t [action isEqualToString:@\"unsupervised-script-folder\"] ||\n\t\t\t [action isEqualToString:@\"unsupervised-scripts-folder\"])\n\t{\n\t\t[RZWorkspace() openURL:[TPCPathInfo customScriptsURL]];\n\t}\n\telse if ([action isEqualToString:@\"custom-style-folder\"] ||\n\t\t\t [action isEqualToString:@\"custom-styles-folder\"])\n\t{\n\t\t[RZWorkspace() openURL:[TPCPathInfo customThemesURL]];\n\t}\n\telse if ([action isEqualToString:@\"diagnostic-reports-folder\"])\n\t{\n\t\t[RZWorkspace() openURL:[TPCPathInfo userDiagnosticReportsURL]];\n\t\t[RZWorkspace() openURL:[TPCPathInfo systemDiagnosticReportsURL]];\n\t}\n\telse if ([action isEqualToString:@\"goto\"])\n\t{\n\t\tNSURL *url = [NSURL URLWithString:sourceLocation];\n\n\t\t[menuController() navigateToTreeItemAtURL:url];\n\t}\n\telse if ([action isEqualToString:@\"knowledge-base\"])\n\t{\n\t\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/\" inBackground:NO];\n\t}\n\telse if ([action isEqualToString:@\"newsletter\"])\n\t{\n\t\t[TLOpenLink openWithString:@\"https://www.codeux.com/textual/newsletter/\" inBackground:NO];\n\t}\n\telse if ([action isEqualToString:@\"support-channel\"])\n\t{\n\t\t[menuController() connectToTextualHelpChannel:nil];\n\t}\n\telse if ([action isEqualToString:@\"testing-channel\"])\n\t{\n\t\t[menuController() connectToTextualTestingChannel:nil];\n\t}\n}\n\n+ (void)parseIRCProtocolURI:(NSString *)location\n{\n\t[self parseIRCProtocolURI:location withDescriptor:nil];\n}\n\n+ (void)parseIRCProtocolURI:(NSString *)location withDescriptor:(nullable NSAppleEventDescriptor *)event\n{\n\tNSParameterAssert(location != nil);\n\n\t/* Basic input clean up. */\n\tNSString *locationValue = location;\n\n\tlocationValue = locationValue.percentDecodedString;\n\tlocationValue = locationValue.trim;\n\n\t/* This method extracts the path component of the URL from the input\n\t string before turning the remaining pieces into an NSURL. */\n\t/* The URL may contain multiple sections proceeded by the pound sign (#),\n\t which this method treats as channel, but NSURL aren't too friendly about. */\n\tNSUInteger totalSlashCount = [locationValue occurrencesOfCharacter:'/'];\n\n\tif (totalSlashCount < 2 || totalSlashCount > 3) {\n\t\treturn;\n\t}\n\n\tNSString *serverInfo = locationValue;\n\n\tNSString *channelInfo = nil;\n\n\tif (totalSlashCount == 3) { // Only cut if we do have an extra slash.\n\t\tNSRange backwardRange = [locationValue rangeOfString:@\"/\" options:NSBackwardsSearch];\n\n\t\tif (backwardRange.location != NSNotFound) {\n\t\t\tserverInfo = [locationValue substringToIndex:backwardRange.location];\n\n\t\t\tchannelInfo = [locationValue substringAfterIndex:backwardRange.location];\n\t\t}\n\t}\n\n\t/* Now that channel information is no longer present in the URL, \n\t we can pass it to NSURL to extract all other information. */\n\tNSURL *baseURL = [NSURL URLWithString:serverInfo];\n\n\tNSString *addressScheme = baseURL.scheme;\n\n\tNSString *serverAddress = baseURL.host;\n\n\tif (addressScheme == nil || serverAddress == nil) {\n\t\treturn;\n\t}\n\n\tif ([addressScheme isEqualToString:@\"textual\"]) {\n\t\t[self performSpecialActionForTextualScheme:serverAddress source:locationValue];\n\n\t\treturn;\n\t}\n\n\t/* Continue normal parsing... */\n\tNSNumber *serverPort = baseURL.port;\n\n\tif (serverPort == nil) {\n\t\tserverPort = @(IRCConnectionDefaultServerPort);\n\t}\n\n\t__block BOOL connectSecurely = NO;\n\n\tif ([addressScheme isEqualToString:@\"ircs\"]) {\n\t\tconnectSecurely = YES;\n\t}\n\n\t/* If we have made it to this point without this method returning,\n\t then everything is going smooth so far. We have established our\n\t server address, the URL scheme, and associated channel information. */\n\t/* We will now parse the actual channel information. */\n\t/* This method does not actually create the connection. It only formats \n\t the input so that another can. Therefore, we do not have to take much \n\t care with the channel information. Just a basic parse to establish if \n\t the \"needssl\" token is present as well as the channel name having a \n\t pound (#) sign in front of it. */\n\tNSMutableString *channelList = [NSMutableString string];\n\n\tif (channelInfo) {\n\t\tNSArray *dataSections = [channelInfo split:@\",\"];\n\n\t\tNSUInteger dataSectionsCount = dataSections.count;\n\n\t\t[dataSections enumerateObjectsUsingBlock:^(NSString *section, NSUInteger index, BOOL *stop) {\n\t\t\tif (section.length == 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (index > 4) {\n\t\t\t\t*stop = YES;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tBOOL isLastObject = ((index + 1) == dataSectionsCount);\n\n\t\t\tif (isLastObject && [section isEqualToStringIgnoringCase:@\"needssl\"]) {\n\t\t\t\tconnectSecurely = YES;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSString *sectionCopy = section;\n\n\t\t\tif ([sectionCopy hasPrefix:@\"#\"] == NO) {\n\t\t\t\tsectionCopy = [@\"#\" stringByAppendingString:sectionCopy];\n\t\t\t}\n\n\t\t\t[channelList appendString:sectionCopy];\n\t\t\t[channelList appendString:@\",\"];\n\t\t}];\n\n\t\t/* Erase end commas */\n\t\tif (channelList.length > 1) {\n\t\t\t[channelList deleteCharactersInRange:NSMakeRange((channelList.length - 1), 1)];\n\t\t}\n\t}\n\n\t/* We have parsed every part of our URL. Build the final result and\n\t pass it along. We are done here. */\n\tNSString *resultValue = nil;\n\n\tif (connectSecurely) {\n\t\tresultValue = [NSString stringWithFormat:@\"-SSL %@:%hu\", serverAddress, serverPort.unsignedShortValue];\n\t} else {\n\t\tresultValue = [NSString stringWithFormat:@\"%@:%hu\", serverAddress, serverPort.unsignedShortValue];\n\t}\n\n\t/* A URL is consider untrusted and will not auto connect */\n\t[self createConnectionToServer:resultValue channelList:channelList connectWhenCreated:NO mergeConnectionIfPossible:YES selectFirstChannelAdded:NO];\n}\n\n+ (void)createConnectionToServer:(NSString *)serverInfo channelList:(nullable NSString *)channelList connectWhenCreated:(BOOL)connectWhenCreated\n{\n\t[self createConnectionToServer:serverInfo channelList:channelList connectWhenCreated:connectWhenCreated mergeConnectionIfPossible:NO selectFirstChannelAdded:NO];\n}\n\n+ (void)createConnectionToServer:(NSString *)serverInfo\n\t\t\t\t\t channelList:(nullable NSString *)channelList\n\t\t\t  connectWhenCreated:(BOOL)connectWhenCreated\n\t   mergeConnectionIfPossible:(BOOL)mergeConnectionIfPossible\n\t\t selectFirstChannelAdded:(BOOL)selectFirstChannelAdded\n{\n\tNSParameterAssert(serverInfo != nil);\n\n\t/* Establish our variables */\n\tNSString *serverAddress = nil;\n\n\tuint16_t serverPort = IRCConnectionDefaultServerPort;\n\n\tNSString *serverPassword = nil;\n\n\tBOOL connectSecurely = NO;\n\n\t/* Begin parsing */\n\tNSMutableString *serverInfoMutable = [serverInfo mutableCopy];\n\n\t/* Get our first token. A token is everything before the first \n\t occurrence of a space character. getToken will get everything \n\t before a space in a string, then erase the remaining content \n\t of that string so that each call to getToken gives us the next \n\t section of our string. */\n\tNSString *tempStore = serverInfoMutable.token;\n\n\t/* Secure Socket Layer? */\n\tif ([tempStore isEqualToStringIgnoringCase:@\"-SSL\"] ||\n\t\t[tempStore isEqualToStringIgnoringCase:@\"-TLS\"])\n\t{\n\t\tconnectSecurely = YES;\n\n\t\t/* If the SSL define was our first token, we\n\t\t go to our next token. */\n\t\ttempStore = serverInfoMutable.token;\n\t}\n\n\t/* Server Address */\n\tNSInteger openingBracketPosition = ([tempStore stringPosition:@\"[\"] + 1);\n\tNSInteger closingBracketPosition =  [tempStore stringPosition:@\"]\"];\n\n\tBOOL hasOpeningBracket = (openingBracketPosition == 1 && openingBracketPosition < closingBracketPosition);\n\tBOOL hasClosingBracket = (closingBracketPosition > 0 && openingBracketPosition < closingBracketPosition);\n\n\tif (hasOpeningBracket && hasClosingBracket) {\n\t\tNSRange serverAddressRange = NSMakeRange(openingBracketPosition, (closingBracketPosition - openingBracketPosition));\n\n\t\tNSString *tempServerAddress = [tempStore substringWithRange:serverAddressRange];\n\n\t\tif (tempServerAddress.IPv6Address == NO) {\n\t\t\tLogToConsoleError(\"Server address was surrounded by square brackets but the enclosed value was not an IPv6 address\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tserverAddress = tempServerAddress;\n\n\t\ttempStore = [tempStore substringAfterIndex:closingBracketPosition];\n\t} else if (hasOpeningBracket == NO && hasClosingBracket == NO) {\n\t\t/* Our server address did not contain brackets. Does it\n\t\t contain a colon (:) which means a port is included? */\n\t\tNSInteger colonPosition = [tempStore stringPosition:@\":\"];\n\n\t\tif (colonPosition > (-1)) {\n\t\t\tserverAddress = [tempStore substringToIndex:colonPosition];\n\n\t\t\t/* We cut the server address out of our temporary store,\n\t\t\t but left the colon and everything after it, in it. */\n\t\t\ttempStore = [tempStore substringFromIndex:colonPosition];\n\t\t} else {\n\t\t\tserverAddress = tempStore;\n\t\t}\n\t} else {\n\t\t/* If we have a opening bracket but no closing or any\n\t\t combination of the two, then return this method as our\n\t\t server address is already invalid. If there were not\n\t\t brackets either, then we are not treating the server\n\t\t as an IPv4 address so any colon will be considered\n\t\t for port use only. */\n\n\t\treturn;\n\t}\n\n\tif (serverAddress.validInternetAddress == NO) {\n\t\tLogToConsoleError(\"Invalid internet address\");\n\n\t\treturn;\n\t}\n\n\tserverAddress = serverAddress.lowercaseString;\n\n\t/* Server Port */\n\tNSString *tempServerPort = nil;\n\n\tif ([tempStore hasPrefix:@\":\"]) {\n\t\ttempServerPort = [tempStore substringFromIndex:1];\n\t} else if (serverInfoMutable.length > 0) {\n\t\ttempServerPort = serverInfoMutable.token;\n\t}\n\n\tif (tempServerPort) {\n\t\tif ([tempServerPort hasPrefix:@\"+\"]) {\n\t\t\ttempServerPort = [tempServerPort substringFromIndex:1];\n\n\t\t\tconnectSecurely = YES;\n\t\t}\n\n\t\tif (tempServerPort.validInternetPort == NO) {\n\t\t\tLogToConsoleError(\"Invalid internet port\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tserverPort = tempServerPort.integerValue;\n\t}\n\n\t/* Server Password */\n\t/* If our base is still not empty after taking out the token for the\n\t server address and port, then we are going to treat that as the server\n\t password. Anything after this token will be ignored completely. */\n\tif (serverInfoMutable.length > 0) {\n\t\ttempStore = serverInfoMutable.token;\n\n\t\tserverPassword = tempStore;\n\t}\n\n\t/* Convert channel list string into array of configurations */\n\tNSMutableArray<NSString *> *channelListArray = nil;\n\n\tif (channelList.length > 0) {\n\t\tchannelListArray = [NSMutableArray array];\n\n\t\tNSArray *dataSections = [channelList split:@\",\"];\n\n\t\tfor (NSString *section in dataSections) {\n\t\t\tNSString *channelName = section.trim;\n\n\t\t\tif (channelName.isChannelName == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([channelListArray containsObjectIgnoringCase:channelName]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[channelListArray addObject:channelName];\n\t\t}\n\t}\n\n\t/* Create connection */\n\t[self createConnectionToServer:serverAddress\n\t\t\t\t\t\tserverPort:serverPort\n\t\t\t\t\tserverPassword:serverPassword\n\t\t\t\t   connectSecurely:connectSecurely\n\t\t\t\t\t   channelList:[channelListArray copy]\n\t\t\t\tconnectWhenCreated:connectWhenCreated\n\t\t mergeConnectionIfPossible:mergeConnectionIfPossible\n\t\t   selectFirstChannelAdded:selectFirstChannelAdded];\n}\n\n+ (void)createConnectionToServer:(NSString *)serverAddress\n\t\t\t\t\t  serverPort:(uint16_t)serverPort\n\t\t\t\t  serverPassword:(nullable NSString *)serverPassword\n\t\t\t\t connectSecurely:(BOOL)connectSecurely\n\t\t\t\t\t channelList:(nullable NSArray<NSString *> *)channelList\n\t\t\t  connectWhenCreated:(BOOL)connectWhenCreated\n\t   mergeConnectionIfPossible:(BOOL)mergeConnectionIfPossible\n\t\t selectFirstChannelAdded:(BOOL)selectFirstChannelAdded\n{\n\tNSParameterAssert(serverAddress != nil);\n\tNSParameterAssert(serverPort > 0);\n\n\tNSUInteger channelListCount = channelList.count;\n\n\t/* If merging is enabled, try to find first possible client\n\t by comparing server address values. */\n\t/* Merging is only performed if a channel is being joined. */\n\tIRCClient *existingClient = nil;\n\n\tif (mergeConnectionIfPossible && channelListCount > 0) {\n\t\texistingClient = [worldController() findClientWithServerAddress:serverAddress];\n\t}\n\n\tif (existingClient != nil) {\n\t\tBOOL mergeConnection = NO;\n\n\t\tif (channelListCount > 1) {\n\t\t\tNSString *channelListFormatted = [channelList componentsJoinedByString:@\", \"];\n\n\t\t\tmergeConnection = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[a9z-9f]\", existingClient.name)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[pnc-ew]\", serverAddress, channelListFormatted)\n\t\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[0hh-sl]\")\n\t\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[sv9-8s]\")];\n\t\t} else {\n\t\t\tmergeConnection = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[mx1-qz]\", existingClient.name)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[3l6-3z]\", serverAddress, channelList.firstObject)\n\t\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[sl5-rf]\")\n\t\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[xca-5h]\")];\n\t\t}\n\n\t\t// YES = default button (create new connection)\n\t\tif (mergeConnection == NO) {\n\t\t\texistingClient = nil;\n\t\t}\n\t}\n\n\t/* Create new connection or merge into existing */\n\tif (existingClient)\n\t{\n\t\tIRCChannel *firstChannelAdded = nil;\n\n\t\tfor (NSString *channelName in channelList) {\n\t\t\tIRCChannel *channel = [existingClient findChannelOrCreate:channelName isPrivateMessage:NO];\n\n\t\t\tif (firstChannelAdded == nil) {\n\t\t\t\tfirstChannelAdded = channel;\n\t\t\t}\n\n\t\t\tif (connectWhenCreated) {\n\t\t\t\t[existingClient joinChannel:channel];\n\t\t\t}\n\t\t}\n\n\t\t[worldController() save];\n\n\t\tif (selectFirstChannelAdded && firstChannelAdded) {\n\t\t\t[mainWindow() select:firstChannelAdded];\n\t\t}\n\t}\n\telse // existingClient\n\t{\n\t\tIRCClientConfigMutable *baseConfig = [IRCClientConfigMutable new];\n\n\t\tbaseConfig.connectionName = serverAddress;\n\n\t\tIRCServerMutable *server = [IRCServerMutable new];\n\n\t\tserver.serverAddress = serverAddress;\n\t\tserver.serverPort = serverPort;\n\n\t\tserver.prefersSecuredConnection = connectSecurely;\n\n\t\tif (serverPassword != nil) {\n\t\t\tserver.serverPassword = serverPassword;\n\t\t}\n\n\t\tbaseConfig.serverList = @[[server copy]];\n\n\t\tNSMutableArray<IRCChannelConfig *> *channelListConfigs = [NSMutableArray arrayWithCapacity:channelListCount];\n\n\t\tfor (NSString *channelName in channelList) {\n\t\t\tIRCChannelConfig *channelConfig = [IRCChannelConfig seedWithName:channelName];\n\n\t\t\t[channelListConfigs addObject:channelConfig];\n\t\t}\n\n\t\tbaseConfig.channelList = channelListConfigs;\n\n\t\tIRCClient *client = [worldController() createClientWithConfig:baseConfig reload:YES];\n\n\t\t[worldController() save];\n\n\t\tif (connectWhenCreated) {\n\t\t\t[client connect];\n\t\t}\n\n\t\tif (selectFirstChannelAdded) {\n\t\t\t[client selectFirstChannelInChannelList];\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCHighlightLogEntry.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSColorHelper.h\"\n#import \"NSStringHelper.h\"\n#import \"NSTableViewHelperPrivate.h\"\n#import \"TXGlobalModels.h\"\n#import \"TXMasterController.h\"\n#import \"IRCChannel.h\"\n#import \"IRCWorld.h\"\n#import \"TLOLocalization.h\"\n#import \"TLONotificationControllerPrivate.h\"\n#import \"TVCLogLinePrivate.h\"\n#import \"IRCHighlightLogEntryInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCHighlightLogEntry\n\n- (NSString *)description\n{\n\tIRCChannel *channel = self.channel;\n\n\tif (channel == nil) {\n\t\treturn [super description];\n\t}\n\n\tTVCLogLine *logLine = self.lineLogged;\n\n\treturn [logLine renderedBodyForTranscriptLogInChannel:channel];\n}\n\n- (NSString *)timeLoggedFormatted\n{\n\tTVCLogLine *logLine = self.lineLogged;\n\n\tNSTimeInterval timeInterval = logLine.receivedAt.timeIntervalSinceNow;\n\n\tNSString *formattedTimeInterval = TXHumanReadableTimeInterval(timeInterval, YES, 0);\n\n\treturn TXTLS(@\"BasicLanguage[4um-w4]\", formattedTimeInterval);\n}\n\n- (nullable IRCChannel *)channel\n{\n\tIRCChannel *channel = [worldController() findChannelWithId:self.channelId onClientWithId:self.clientId];\n\n\treturn channel;\n}\n\n- (NSString *)channelName\n{\n\tIRCChannel *channel = self.channel;\n\n\tif (channel) {\n\t\treturn channel.name;\n\t}\n\n\treturn TXTLS(@\"BasicLanguage[vbl-xi]\");\n}\n\n- (NSAttributedString *)renderedMessage\n{\n\tIRCChannel *channel = self.channel;\n\n\tTVCLogLine *logLine = self.lineLogged;\n\n\tNSString *nicknameBody = nil;\n\n\tNSString *messageBody = nil;\n\n\tif (logLine.lineType == TVCLogLineTypeAction) {\n\t\t/* Actions are presented in the format \"• <nickname>: <message\" in the Highlight List. */\n\t\tnicknameBody = logLine.nickname;\n\n\t\tmessageBody = TXNotificationHighlightLogStandardActionFormat;\n\t} else {\n\t\tnicknameBody = [logLine formattedNicknameInChannel:channel];\n\n\t\tmessageBody = TXNotificationHighlightLogStandardMessageFormat;\n\t}\n\n\tmessageBody = [NSString stringWithFormat:messageBody, nicknameBody, logLine.messageBody];\n\n\treturn [messageBody attributedStringWithIRCFormatting:[NSTableView preferredGlobalTableViewFont]\n\t\t\t\t\t\t\t\t\t   preferredFontColor:[NSColor controlTextColor]];\n}\n\n- (NSString *)lineNumber\n{\n\tTVCLogLine *logLine = self.lineLogged;\n\n\treturn logLine.uniqueIdentifier;\n}\n\n- (NSDate *)timeLogged\n{\n\tTVCLogLine *logLine = self.lineLogged;\n\n\treturn logLine.receivedAt;\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.mutable || self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tNSParameterAssert(self->_lineLogged != nil);\n\tNSParameterAssert(self->_clientId.length > 0);\n\tNSParameterAssert(self->_channelId.length > 0);\n}\n\n- (void)populateDuringCopy:(__kindof XRPortablePropertyObject *)newObject mutableCopy:(BOOL)mutableCopy\n{\n\tIRCHighlightLogEntry *object = (IRCHighlightLogEntry *)newObject;\n\n\tobject->_lineLogged = self->_lineLogged;\n\tobject->_clientId = self->_clientId;\n\tobject->_channelId = self->_channelId;\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCHighlightLogEntryMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCHighlightLogEntryMutable\n\n@dynamic lineLogged;\n@dynamic clientId;\n@dynamic channelId;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCHighlightLogEntry self];\n}\n\n- (void)setLineLogged:(TVCLogLine *)lineLogged\n{\n\tNSParameterAssert(lineLogged != nil);\n\n\tif (self->_lineLogged != lineLogged) {\n\t\tself->_lineLogged = [lineLogged copy];\n\t}\n}\n\n- (void)setClientId:(NSString *)clientId\n{\n\tNSParameterAssert(clientId != nil);\n\n\tif (self->_clientId != clientId) {\n\t\tself->_clientId = [clientId copy];\n\t}\n}\n\n- (void)setChannelId:(NSString *)channelId\n{\n\tNSParameterAssert(channelId != nil);\n\n\tif (self->_channelId != channelId) {\n\t\tself->_channelId = [channelId copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCHighlightMatchCondition.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCHighlightMatchConditionInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCHighlightMatchCondition\n\n- (instancetype)init\n{\n\treturn [super initWithDictionary:@{}];\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.mutable || self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tNSParameterAssert(self->_matchKeyword.length > 0);\n}\n\n- (void)populateDictionaryValues:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\t[dic assignBoolTo:&self->_matchIsExcluded forKey:@\"matchIsExcluded\"];\n\n\t[dic assignStringTo:&self->_matchChannelId forKey:@\"matchChannelID\"];\n\t[dic assignStringTo:&self->_matchKeyword forKey:@\"matchKeyword\"];\n\t[dic assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n}\n\n- (void)populateDefaultsPostflight\n{\n\tSetVariableIfNil(self->_matchKeyword, @\"\")\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t[dic maybeSetObject:self.matchChannelId forKey:@\"matchChannelID\"];\n\t[dic maybeSetObject:self.matchKeyword forKey:@\"matchKeyword\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[dic setBool:self.matchIsExcluded forKey:@\"matchIsExcluded\"];\n\n\treturn [dic copy];\n}\n\n- (id)uniqueCopyAsMutable:(BOOL)mutableCopy\n{\n\tIRCHighlightMatchCondition *object = [super uniqueCopyAsMutable:mutableCopy];\n\n\tobject->_uniqueIdentifier = [NSString stringWithUUID];\n\n\treturn object;\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [IRCHighlightMatchConditionMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCHighlightMatchConditionMutable\n\n@dynamic matchChannelId;\n@dynamic matchIsExcluded;\n@dynamic matchKeyword;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [IRCHighlightMatchCondition self];\n}\n\n- (void)setMatchIsExcluded:(BOOL)matchIsExcluded\n{\n\tif (self->_matchIsExcluded != matchIsExcluded) {\n\t\tself->_matchIsExcluded = matchIsExcluded;\n\t}\n}\n\n- (void)setMatchChannelId:(nullable NSString *)matchChannelId\n{\n\tif (self->_matchChannelId != matchChannelId) {\n\t\tself->_matchChannelId = [matchChannelId copy];\n\t}\n}\n\n- (void)setMatchKeyword:(NSString *)matchKeyword\n{\n\tNSParameterAssert(matchKeyword != nil);\n\n\tif (self->_matchKeyword != matchKeyword) {\n\t\tself->_matchKeyword = [matchKeyword copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCISupportInfo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TLOLocalization.h\"\n#import \"IRC.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCModeInfo.h\"\n#import \"IRCISupportInfoPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _channelUserModeValue\t\t100\n\n@interface IRCISupportInfo ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, copy) NSArray<NSDictionary *> *cachedConfiguration;\n@property (nonatomic, assign, readwrite) NSUInteger maximumAwayLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumChannelNameLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumKeyLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumKickLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumNicknameLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumTopicLength;\n@property (nonatomic, assign, readwrite) NSUInteger maximumModeCount;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *channelNamePrefixes;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *statusMessageModeSymbols;\n@property (nonatomic, copy, readwrite) NSDictionary<NSString *, NSNumber *> *channelModes;\n@property (nonatomic, copy, readwrite) NSDictionary<NSString *, NSArray *> *userModeSymbols;\n@property (nonatomic, copy, readwrite, nullable) NSString *banExceptionModeSymbol;\n@property (nonatomic, copy, readwrite, nullable) NSString *inviteExceptionModeSymbol;\n@property (nonatomic, copy, readwrite, nullable) NSString *networkName;\n@property (nonatomic, copy, readwrite, nullable) NSString *networkNameFormatted;\n@end\n\n@implementation IRCISupportInfo\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[self reset];\n}\n\n- (void)reset\n{\n\tself.cachedConfiguration = @[];\n\n\tself.serverAddress = nil;\n\n\tself.networkName = nil;\n\tself.networkNameFormatted = nil;\n\n\tself.channelNamePrefixes = @[@\"#\"];\n\n\tself.maximumModeCount = TXMaximumNodesPerModeCommand;\n\tself.maximumNicknameLength = IRCProtocolDefaultNicknameMaximumLength;\n\n\tself.userModeSymbols = @{\n\t\t@\"modeSymbols\" : @[@\"o\", @\"v\"],\n\t\t@\"characters\" : @[@\"@\", @\"+\"]\n\t};\n\n\tself.channelModes = @{\n\t\t@\"o\" : @(_channelUserModeValue),\n\t\t@\"v\" : @(_channelUserModeValue)\n\t};\n\n\tself.statusMessageModeSymbols = @[];\n}\n\n- (void)processConfigurationData:(NSString *)configurationData\n{\n\tNSParameterAssert(configurationData != nil);\n\n\tconfigurationData = configurationData.trim;\n\n\tif (configurationData.length == 0) {\n\t\treturn;\n\t}\n\n\tIRCClient *client = self.client;\n\n\tNSMutableDictionary *configuration = [NSMutableDictionary dictionary];\n\n\tNSArray *segments = [configurationData componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\tfor (NSString *segment in segments) {\n\t\tif (segment.length == 0) { // Blank\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *segmentKey = segment;\n\t\tNSString *segmentValue = nil;\n\n\t\tNSInteger equalSignPosition = [segment stringPosition:@\"=\"];\n\n\t\tif (equalSignPosition > 0) {\n\t\t\tsegmentKey = [segment substringToIndex:equalSignPosition];\n\t\t\tsegmentValue = [segment substringAfterIndex:equalSignPosition];\n\n\t\t\tif (segmentValue.length == 0) {\n\t\t\t\tsegmentValue = nil;\n\t\t\t}\n\t\t}\n\n\t\tif (segmentValue) {\n\t\t\tconfiguration[segmentKey] = segmentValue;\n\t\t} else {\n\t\t\tconfiguration[segmentKey] = @(YES);\n\t\t}\n\n\t\tif (segmentValue) {\n\t\t\tif ([segmentKey isEqualToStringIgnoringCase:@\"AWAYLEN\"]) {\n\t\t\t\tNSInteger awayLength = segmentValue.integerValue;\n\n\t\t\t\tif (awayLength > 0) {\n\t\t\t\t\tself.maximumAwayLength = awayLength;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"CHANMODES\"]) {\n\t\t\t\t[self parseChannelModes:segmentValue];\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"CHANNELLEN\"]) {\n\t\t\t\tNSInteger channelNameLength = segmentValue.integerValue;\n\n\t\t\t\tif (channelNameLength > 0) {\n\t\t\t\t\tself.maximumChannelNameLength = channelNameLength;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"CHANTYPES\"]) {\n\t\t\t\tNSArray *channelNamePrefixes = segmentValue.characterStringBuffer;\n\n\t\t\t\tif (channelNamePrefixes.count > 0) {\n\t\t\t\t\tself.channelNamePrefixes = channelNamePrefixes;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"KEYLEN\"]) {\n\t\t\t\tNSInteger maximumKeyLength = segmentValue.integerValue;\n\n\t\t\t\tif (maximumKeyLength > 0) {\n\t\t\t\t\tself.maximumKeyLength = maximumKeyLength;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"KICKLEN\"]) {\n\t\t\t\tNSInteger maximumKickLength = segmentValue.integerValue;\n\n\t\t\t\tif (maximumKickLength > 0) {\n\t\t\t\t\tself.maximumKickLength = maximumKickLength;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"MODES\"]) {\n\t\t\t\tNSInteger maximumModesCount = segmentValue.integerValue;\n\n\t\t\t\tif (maximumModesCount > 0) {\n\t\t\t\t\tself.maximumModeCount = maximumModesCount;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"NETWORK\"]) {\n\t\t\t\tself.networkName = segmentValue;\n\t\t\t\tself.networkNameFormatted = TXTLS(@\"IRC[8hg-7k]\", segmentValue);\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"NICKLEN\"]) {\n\t\t\t\tNSInteger maximumNicknameLength = segmentValue.integerValue;\n\n\t\t\t\tif (maximumNicknameLength > 0) {\n\t\t\t\t\tself.maximumNicknameLength = maximumNicknameLength;\n\t\t\t\t}\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"PREFIX\"]) {\n\t\t\t\t[self parseUserModeSymbols:segmentValue];\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"STATUSMSG\"]) {\n\t\t\t\tself.statusMessageModeSymbols = segmentValue.characterStringBuffer;\n\t\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"TOPICLEN\"]) {\n\t\t\t\tNSInteger maximumTopicLength = segmentValue.integerValue;\n\n\t\t\t\tif (maximumTopicLength > 0) {\n\t\t\t\t\tself.maximumTopicLength = maximumTopicLength;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ([segmentKey isEqualToStringIgnoringCase:@\"EXCEPTS\"]) {\n\t\t\tif (segmentValue.isModeSymbol) {\n\t\t\t\tself.banExceptionModeSymbol = segmentValue;\n\t\t\t} else {\n\t\t\t\tself.banExceptionModeSymbol = @\"e\";\n\t\t\t}\n\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"INVEX\"]) {\n\t\t\tif (segmentValue.isModeSymbol) {\n\t\t\t\tself.inviteExceptionModeSymbol = segmentValue;\n\t\t\t} else {\n\t\t\t\tself.inviteExceptionModeSymbol = @\"I\";\n\t\t\t}\n\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"MONITOR\"]) {\n\t\t\t// freenode advertises support for MONITOR but does not respond to command\n\t\t\t/*\n\t\t\t Update as of May 30, 2018:\n\n\t\t\t [17:25:55]  <milky>\tBack in 2016 I hard coded MONITOR support disabled on freenode in\n\t\t\t \t\t\t\t\t\tmy client because back then the network advertised it but didn't\n\t\t\t \t\t\t\t\t\tactually respond to it. Has that since changed?\n\t\t\t [17:26:53]  <@Unit193>\tmilky: Depends on the server unfortunately.\n\t\t\t [17:27:24]  <milky>\tUnit193 so just keep it disabled, you think?\n\t\t\t [17:27:39]  <@Unit193>\tmilky: Yeah, the server I'm on claims support.\n\t\t\t */\n\t\t\tif ([self.serverAddress hasSuffix:@\".freenode.net\"]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[client enableCapability:ClientIRCv3SupportedCapabilityMonitorCommand];\n\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"NAMESX\"]) {\n\t\t\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityMultiPrefix] == NO) {\n\t\t\t\t[client sendLine:@\"PROTOCTL NAMESX\"];\n\n\t\t\t\t[client enableCapability:ClientIRCv3SupportedCapabilityMultiPrefix];\n\t\t\t}\n\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"UHNAMES\"]) {\n\t\t\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityUserhostInNames] == NO) {\n\t\t\t\t[client sendLine:@\"PROTOCTL UHNAMES\"];\n\n\t\t\t\t[client enableCapability:ClientIRCv3SupportedCapabilityUserhostInNames];\n\t\t\t}\n\t\t} else if ([segmentKey isEqualToStringIgnoringCase:@\"WATCH\"]) {\n\t\t\t[client enableCapability:ClientIRCv3SupportedCapabilityWatchCommand];\n\t\t}\n\t} // while()\n\n\tself.cachedConfiguration = [self.cachedConfiguration arrayByAddingObject:configuration];\n}\n\n- (nullable NSString *)stringValueForConfiguration:(NSDictionary<NSString *, id> *)configuration\n{\n\tNSParameterAssert(configuration != nil);\n\n\t/* This takes our cached configuration data and builds it into what it would look like if we\n\t were to receive an actual 005. The only difference is this method formats each token that\n\t is in our configuration cache to make them easier to see. We use bold for the tokens. \n\t This is pretty much only used in developer mode, but it could have other uses? */\n\n\tif (configuration.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSMutableString *stringValue = [NSMutableString string];\n\n\tNSArray *sortedKeys = configuration.sortedDictionaryKeys;\n\n\tfor (NSString *key in sortedKeys) {\n\t\tid value = configuration[key];\n\n\t\tif ([value isKindOfClass:[NSString class]]) {\n\t\t\t[stringValue appendFormat:@\"\\002%@\\002=%@ \", key, value];\n\t\t} else {\n\t\t\t[stringValue appendFormat:@\"\\002%@ \\002\", key];\n\t\t}\n\t}\n\n\treturn [stringValue copy];\n}\n\n- (nullable NSString *)stringValueForLastUpdate\n{\n\tNSDictionary *configuration = self.cachedConfiguration.lastObject;\n\n\tif (configuration == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self stringValueForConfiguration:configuration];\n}\n\n- (NSArray<IRCModeInfo *> *)parseModes:(NSString *)modeString\n{\n\tNSParameterAssert(modeString != nil);\n\n\tNSMutableArray<IRCModeInfo *> *modes = [NSMutableArray array];\n\n\tNSMutableString *modeStringMutable = [modeString mutableCopy];\n\n\tBOOL modeIsSet = NO;\n\n\tdo {\n\t\tNSString *nextToken = modeStringMutable.token;\n\n\t\tif (nextToken.length == 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\tUniChar nextCharacter = [nextToken characterAtIndex:0];\n\n\t\tif (nextCharacter != '+' && nextCharacter != '-') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tmodeIsSet = (nextCharacter == '+');\n\n\t\tnextToken = [nextToken substringFromIndex:1];\n\n\t\tfor (NSUInteger i = 0; i < nextToken.length; i++) {\n\t\t\tnextCharacter = [nextToken characterAtIndex:i];\n\n\t\t\tif (nextCharacter == '-') {\n\t\t\t\tmodeIsSet = NO;\n\t\t\t} else if (nextCharacter == '+') {\n\t\t\t\tmodeIsSet = YES;\n\t\t\t} else {\n\t\t\t\tNSString *modeSymbol = [NSString stringWithUniChar:nextCharacter];\n\n\t\t\t\tIRCModeInfoMutable *mode =\n\t\t\t\t[[IRCModeInfoMutable alloc] initWithModeSymbol:modeSymbol modeIsSet:modeIsSet];\n\n\t\t\t\tif ([self modeHasParameter:modeSymbol whenModeIsSet:modeIsSet]) {\n\t\t\t\t\tmode.modeParameter = modeStringMutable.token;\n\t\t\t\t}\n\n\t\t\t\t[modes addObject:[mode copy]];\n\t\t\t}\n\t\t}\n\t} while (modeStringMutable.length > 0);\n\n\treturn [modes copy];\n}\n\n- (void)parseUserModeSymbols:(NSString *)modeString\n{\n\tNSParameterAssert(modeString != nil);\n\n\t// Format: (qaohv)~&@%+\n\n\t/* Perform validation on placement of parentheses */\n\tNSInteger openingParenthesesPosition = [modeString stringPosition:@\"(\"];\n\tNSInteger closingParenthesesPosition = [modeString stringPosition:@\")\"];\n\n\tif (openingParenthesesPosition != 0 &&\n\t\topeningParenthesesPosition >= closingParenthesesPosition)\n\t{\n\t\treturn;\n\t}\n\n\t/* Extract relevant information and ensure that they are equal length */\n\tNSString *modeSymbols = [modeString substringWithRange:NSMakeRange(1, (closingParenthesesPosition - 1))];\n\n\tNSString *characters = [modeString substringAfterIndex:closingParenthesesPosition];\n\n\tif (modeSymbols.length != characters.length) {\n\t\treturn;\n\t}\n\n\t/* Begin processing modes */\n\t/* The mode symbols and characters are stored in separate arrays because\n\t NSDictionary has no sense of order and the order of the user mode\n\t symbols is very important to establish rank. */\n\tNSArray *modeSymbolsArray = modeSymbols.characterStringBuffer;\n\tNSArray *charactersArray = characters.characterStringBuffer;\n\n\tself.userModeSymbols = @{\n\t\t @\"modeSymbols\" : modeSymbolsArray,\n\t\t @\"characters\" : charactersArray\n\t};\n\n\t/* Update channel modes array so that we know these mode symbols are for user */\n\tNSMutableDictionary *channelModes = [self.channelModes mutableCopy];\n\n\tfor (NSString *modeSymbol in modeSymbolsArray) {\n\t\tchannelModes[modeSymbol] = @(_channelUserModeValue);\n\t}\n\n\tself.channelModes = channelModes;\n}\n\n- (BOOL)modeHasParameter:(NSString *)modeSymbol whenModeIsSet:(BOOL)whenModeIsSet\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\t// Input: CHANMODES=A,B,C,D\n\t//\n\t// A = Always has a parameter.\t\t\tIndex: 1\n\t// B = Always has a parameter.\t\t\tIndex: 2\n\t// C = Only has a parameter when set.\tIndex: 3\n\t// D = Never has a parameter.\t\t\tIndex: 4\n\n\tNSUInteger modeIndex = [self.channelModes unsignedIntegerForKey:modeSymbol];\n\n\tif (modeIndex == 1 || modeIndex == 2 || modeIndex == _channelUserModeValue) {\n\t\treturn YES;\n\t} else if (modeIndex == 3) {\n\t\treturn whenModeIsSet;\n\t}\n\n\treturn NO;\n}\n\n- (void)parseChannelModes:(NSString *)modeString\n{\n\tNSParameterAssert(modeString != nil);\n\n\t// Input: CHANMODES=A,B,C,D\n\t//\n\t// A = Always has a parameter.\t\t\tIndex: 1\n\t// B = Always has a parameter.\t\t\tIndex: 2\n\t// C = Only has a parameter when set.\tIndex: 3\n\t// D = Never has a parameter.\t\t\tIndex: 4\n\n\tNSMutableDictionary *channelModes = [self.channelModes mutableCopy];\n\n\tNSArray *modes = [modeString split:@\",\"];\n\n\tfor (NSUInteger i = 0; i < modes.count; i++) {\n\t\tNSString *modeSet = modes[i];\n\n\t\tfor (NSUInteger j = 0; j < modeSet.length; j++) {\n\t\t\tNSString *modeSymbol = [modeSet stringCharacterAtIndex:j];\n\n\t\t\tchannelModes[modeSymbol] = @(i + 1);\n\t\t}\n\t}\n\n\tself.channelModes = channelModes;\n}\n\n- (nullable NSString *)userPrefixForModeSymbol:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSArray *modeSymbols = self.userModeSymbols[@\"modeSymbols\"];\n\n\tNSUInteger modeSymbolIndex = [modeSymbols indexOfObject:modeSymbol];\n\n\tif (modeSymbolIndex == NSNotFound) {\n\t\treturn 0;\n\t}\n\n\tNSArray *characters = self.userModeSymbols[@\"characters\"];\n\n\treturn characters[modeSymbolIndex];\n}\n\n- (BOOL)modeSymbolIsUserPrefix:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\treturn ([self userPrefixForModeSymbol:modeSymbol] != nil);\n}\n\n- (nullable NSString *)modeSymbolForUserPrefix:(NSString *)character\n{\n\tNSParameterAssert(character != nil);\n\n\tNSArray *characters = self.userModeSymbols[@\"characters\"];\n\n\tNSUInteger characterIndex = [characters indexOfObject:character];\n\n\tif (characterIndex == NSNotFound) {\n\t\treturn nil;\n\t}\n\n\tNSArray *modeSymbols = self.userModeSymbols[@\"modeSymbols\"];\n\n\treturn modeSymbols[characterIndex];\n}\n\n- (BOOL)characterIsUserPrefix:(NSString *)character\n{\n\tNSParameterAssert(character != nil);\n\n\treturn ([self modeSymbolForUserPrefix:character] != nil);\n}\n\n- (NSUInteger)rankForUserPrefixWithMode:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSArray *modeSymbols = self.userModeSymbols[@\"modeSymbols\"];\n\n\tNSUInteger modeSymbolIndex = [modeSymbols indexOfObject:modeSymbol];\n\n\tif (modeSymbolIndex == NSNotFound) {\n\t\treturn 0;\n\t}\n\n\treturn (IRCISupportInfoHighestUserPrefixRank - modeSymbolIndex);\n}\n\n- (NSString *)extractStatusMessagePrefixFromChannelNamed:(NSString *)channel\n{\n\tNSArray *characters = self.statusMessageModeSymbols;\n\n\treturn [self _extractCharacters:characters fromChannelNamed:channel];\n}\n\n- (NSString *)_extractCharacters:(NSArray<NSString *> *)characters fromChannelNamed:(NSString *)channel\n{\n\tNSParameterAssert(characters != nil);\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.length < 2) {\n\t\treturn @\"\";\n\t}\n\n\tNSArray *channelNamePrefixes = self.channelNamePrefixes;\n\n\tfor (NSString *character in characters) {\n\t\tif ([channel hasPrefix:character] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *nextCharacter = [channel stringCharacterAtIndex:1];\n\n\t\tif ([channelNamePrefixes containsObject:nextCharacter]) {\n\t\t\treturn character;\n\t\t}\n\t}\n\n\treturn @\"\";\n}\n\n- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\treturn [[IRCModeInfo alloc] initWithModeSymbol:modeSymbol];\n}\n\n- (IRCModeInfo *)createModeWithSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\treturn [[IRCModeInfo alloc] initWithModeSymbol:modeSymbol modeIsSet:modeIsSet modeParameter:modeParameter];\n}\n\n- (BOOL)configurationReceived\n{\n\treturn (self.cachedConfiguration.count > 0);\n}\n\n- (BOOL)isListSupported:(IRCISupportInfoListType)listType\n{\n\treturn ([self modeSymbolForList:listType] != nil);\n}\n\n- (nullable NSString *)modeSymbolForList:(IRCISupportInfoListType)listType\n{\n\tswitch (listType) {\n\t\tcase IRCISupportInfoListTypeBan:\n\t\t{\n\t\t\treturn @\"b\";\n\t\t}\n\t\tcase IRCISupportInfoListTypeBanException:\n\t\t{\n\t\t\treturn self.banExceptionModeSymbol;\n\t\t}\n\t\tcase IRCISupportInfoListTypeInviteException:\n\t\t{\n\t\t\treturn self.inviteExceptionModeSymbol;\n\t\t}\n\t\tcase IRCISupportInfoListTypeQuiet:\n\t\t{\n\t\t\t/* +q is used by some servers as the user mode for channel owner.\n\t\t\t If this mode is a user mode, then hide the menu item. */\n\t\t\tif ([self modeSymbolIsUserPrefix:@\"q\"]) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\treturn @\"q\";\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn nil;\n\t\t}\n\t} // switch\n}\n\n- (nullable NSString *)statusMessagePrefixForModeSymbol:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSString *character = [self userPrefixForModeSymbol:modeSymbol];\n\n\tif (character == nil) {\n\t\treturn nil;\n\t}\n\n\tif ([self.statusMessageModeSymbols containsObject:character] == NO) {\n\t\treturn nil;\n\t}\n\n\treturn character;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCMessage.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TXGlobalModelsPrivate.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCPrefix.h\"\n#import \"IRCMessageInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCMessage\n\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_END\n\n- (nullable instancetype)initWithLine:(NSString *)line\n{\n\treturn [self initWithLine:line onClient:nil];\n}\n\n- (nullable instancetype)initWithLine:(NSString *)line onClient:(nullable IRCClient *)client\n{\n\tif ((self = [super init])) {\n\t\tBOOL parseResult = [self parseLine:line forClient:client];\n\n\t\tif (parseResult == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)populateDefaultsPostflight\n{\n\tSetVariableIfNil(self->_command, @\"\")\n\tSetVariableIfNil(self->_messageTags, @{})\n\tSetVariableIfNil(self->_params, @[])\n\tSetVariableIfNil(self->_receivedAt, [NSDate date])\n\tSetVariableIfNil(self->_sender, [IRCPrefix new])\n}\n\n- (NSUInteger)paramsCount\n{\n\treturn self.params.count;\n}\n\n- (NSString *)paramAt:(NSUInteger)index\n{\n\tif (index < self.params.count) {\n\t\treturn self.params[index];\n\t}\n\n\treturn @\"\";\n}\n\n- (NSString *)sequence\n{\n\tif (self.params.count < 2) {\n\t\treturn [self sequence:0];\n\t} else {\n\t\treturn [self sequence:1];\n\t}\n}\n\n- (NSString *)sequence:(NSUInteger)index\n{\n\tNSMutableString *sequence = [NSMutableString string];\n\n\tNSArray *params = self.params;\n\n\tNSUInteger paramsCount = params.count;\n\n\tfor (NSUInteger i = index; i < paramsCount; i++) {\n\t\tNSString *param = params[i];\n\n\t\tif (i != index) {\n\t\t\t[sequence appendString:@\" \"];\n\t\t}\n\n\t\t[sequence appendString:param];\n\t}\n\n\treturn [sequence copy];\n}\n\n- (void)markAsNotHistoric\n{\n\tself->_isHistoric = NO;\n}\n\n- (nullable NSString *)senderNickname\n{\n\treturn self.sender.nickname;\n}\n\n- (nullable NSString *)senderUsername\n{\n\treturn self.sender.username;\n}\n\n- (nullable NSString *)senderAddress\n{\n\treturn self.sender.address;\n}\n\n- (nullable NSString *)senderHostmask\n{\n\treturn self.sender.hostmask;\n}\n\n- (BOOL)senderIsServer\n{\n\treturn self.sender.isServer;\n}\n\n- (void)populateDuringCopy:(__kindof XRPortablePropertyObject *)newObject mutableCopy:(BOOL)mutableCopy\n{\n\tIRCMessage *object = (IRCMessage *)newObject;\n\n\tobject->_batchToken = self->_batchToken;\n\tobject->_command = self->_command;\n\tobject->_commandNumeric = self->_commandNumeric;\n\tobject->_isHistoric = self->_isHistoric;\n\tobject->_isEventOnlyMessage = self->_isEventOnlyMessage;\n\tobject->_isPrintOnlyMessage = self->_isPrintOnlyMessage;\n\tobject->_messageTags = self->_messageTags;\n\tobject->_params = self->_params;\n\tobject->_receivedAt = self->_receivedAt;\n\tobject->_sender = self->_sender;\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCMessageMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCMessage (IRCMessageLineParser)\n\n- (BOOL)parseLine:(NSString *)line forClient:(nullable IRCClient *)client\n{\n\tNSParameterAssert(line != nil);\n\n\tNSMutableString *lineMutable = [line mutableCopy];\n\n\t/* Parse extension information (if present) */\n\tif ([lineMutable hasPrefix:@\"@\"]) {\n\t\tNSString *extensionInfo = lineMutable.token;\n\n\t\tif (extensionInfo.length <= 1) {\n\t\t\treturn NO;\n\t\t}\n\n\t\textensionInfo = [extensionInfo substringFromIndex:1];\n\n\t\t[self parseExtensions:extensionInfo forClient:client];\n\t}\n\n\t/* Parse sender information (if present) */\n\tif ([lineMutable hasPrefix:@\":\"]) {\n\t\tNSString *senderInfo = lineMutable.token;\n\n\t\tif (senderInfo.length <= 1) {\n\t\t\treturn NO;\n\t\t}\n\n\t\tsenderInfo = [senderInfo substringFromIndex:1];\n\n\t\t[self parseSender:senderInfo forClient:client];\n\t} else {\n\t\t/* If the line does not have a sender, then we use the \n\t\t server address as the sender. If that isn't known, then\n\t\t we use the the address the user has configured. */\n\t\t/* -serverAddress is only nil when the client isn't\n\t\t connected anywhere. We are parsing messages when\n\t\t connected somewhere so it's safe to cast it as\n\t\t as non-nil at least here. */\n\t\tNSString * _Nonnull serverAddress = (NSString * _Nonnull)client.serverAddress;\n\n\t\tIRCPrefixMutable *sender = [IRCPrefixMutable new];\n\n\t\tsender.nickname = serverAddress;\n\n\t\tsender.hostmask = serverAddress;\n\n\t\tsender.isServer = YES;\n\n\t\tself->_sender = [sender copy];\n\t}\n\n\t/* Parse command */\n\tNSString *command = lineMutable.token;\n\n\tif (command.length < 1) {\n\t\treturn NO;\n\t}\n\n\tif (command.isNumericOnly) {\n\t\tself->_command = [command copy];\n\n\t\tself->_commandNumeric = command.integerValue;\n\t} else {\n\t\tself->_command = [command.uppercaseString copy];\n\n\t\tself->_commandNumeric = 0;\n\t}\n\n\t/* Parse remaining data */\n\tNSMutableArray<NSString *> *parameters = [NSMutableArray new];\n\n\twhile (lineMutable.length > 0) {\n\t\tif ([lineMutable hasPrefix:@\":\"])\n\t\t{\n\t\t\tNSString *sequence = [lineMutable substringFromIndex:1];\n\n\t\t\t[parameters addObject:sequence];\n\n\t\t\tbreak;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSString *sequence = lineMutable.token;\n\n\t\t\t[parameters addObject:sequence];\n\t\t}\n\t}\n\n\tself->_params = [parameters copy];\n\n\t/* Return success */\n\treturn YES;\n}\n\n- (void)parseExtensions:(NSString *)extensionInfo forClient:(nullable IRCClient *)client\n{\n\tNSParameterAssert(extensionInfo != nil);\n\n\t/* Chop the tags up using ; as a divider as defined by the syntax\n\t located at: <http://ircv3.net/specs/core/message-tags-3.2.html> */\n\t/* An example grouping would look like the following:\n\t @aaa=bbb;ccc;example.com/ddd=eee */\n\tNSDictionary<NSString *, NSString *> *extensions =\n\t[extensionInfo formDataUsingSeparator:@\";\" decodingBlock:^NSString *(NSString *value) {\n\t\treturn value.decodedMessageTagString;\n\t}];\n\n\tself->_messageTags = [extensions copy];\n\n\t/* If there is no client, then further processing is not possible */\n\tif (client == nil) {\n\t\treturn;\n\t}\n\n\t/* Check for known capacities */\n\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityServerTime]) {\n\t\t/* We support two time extensions. The time= value is the date and\n\t\t time in the format as defined by ISO 8601:2004(E) 4.3.2. */\n\t\t/* The t= value is a legacy value in a epoch time. We always favor\n\t\t the new time= format over the old. */\n\t\tNSString *dateString = extensions[@\"time\"];\n\n\t\tif (dateString == nil) {\n\t\t\tdateString = extensions[@\"t\"];\n\t\t}\n\n\t\tif (dateString) {\n\t\t\tNSDate *dateObject = nil;\n\n\t\t\tif ([dateString onlyContainsCharactersFromCharacterSet:[NSCharacterSet ZeroToNineDecimalCharacterSet]]) {\n\t\t\t\tdateObject = [NSDate dateWithTimeIntervalSince1970:dateString.doubleValue];\n\t\t\t} else {\n\t\t\t\tdateObject = [TXSharedISOStandardDateFormatter() dateFromString:dateString];\n\t\t\t}\n\n\t\t\tif (dateObject) {\n\t\t\t\tself->_receivedAt = [dateObject copy];\n\n\t\t\t\tself->_isHistoric = YES;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityBatch]) {\n\t\tNSString *batchToken = extensions[@\"batch\"];\n\n\t\tif ([batchToken onlyContainsCharactersFromCharacterSet:[NSCharacterSet Ato9UnderscoreDash]]) {\n\t\t\tself->_batchToken = [batchToken copy];\n\n\t\t\tself->_parentBatchMessage = [client queuedBatchMessageWithToken:batchToken];\n\t\t}\n\t}\n}\n\n- (void)parseSender:(NSString *)senderInfo forClient:(nullable IRCClient *)client\n{\n\tNSParameterAssert(senderInfo != nil);\n\n\tIRCPrefixMutable *sender = [IRCPrefixMutable new];\n\n\tNSString *senderNickname = nil;\n\tNSString *senderUsername = nil;\n\tNSString *senderAddress = nil;\n\n\tsender.hostmask = senderInfo;// Declare entire section as host\n\n\t/* Parse the user info into their appropriate sections or return NO if we can't. */\n\tif ([senderInfo hostmaskComponents:&senderNickname username:&senderUsername address:&senderAddress onClient:client]) {\n\t\tsender.nickname = senderNickname;\n\t\tsender.username = senderUsername;\n\t\tsender.address = senderAddress;\n\t} else {\n\t\tsender.nickname = senderInfo;\n\n\t\tsender.isServer = YES;\n\t}\n\n\tself->_sender = [sender copy];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCMessageMutable\n\n@dynamic batchToken;\n@dynamic command;\n@dynamic commandNumeric;\n@dynamic isHistoric;\n@dynamic isEventOnlyMessage;\n@dynamic isPrintOnlyMessage;\n@dynamic messageTags;\n@dynamic params;\n@dynamic receivedAt;\n@dynamic sender;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCMessage self];\n}\n\n- (void)setBatchToken:(nullable NSString *)batchToken\n{\n\tif (self->_batchToken != batchToken) {\n\t\tself->_batchToken = [batchToken copy];\n\t}\n}\n\n- (void)setCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tif (self->_command != command) {\n\t\tself->_command = [command copy];\n\t}\n}\n\n- (void)setCommandNumeric:(NSUInteger)commandNumeric\n{\n\tif (self->_commandNumeric != commandNumeric) {\n\t\tself->_commandNumeric = commandNumeric;\n\t}\n}\n\n- (void)setIsHistoric:(BOOL)isHistoric\n{\n\tif (self->_isHistoric != isHistoric) {\n\t\tself->_isHistoric = isHistoric;\n\t}\n}\n\n- (void)setIsEventOnlyMessage:(BOOL)isEventOnlyMessage\n{\n\tif (self->_isEventOnlyMessage != isEventOnlyMessage) {\n\t\tself->_isEventOnlyMessage = isEventOnlyMessage;\n\t}\n}\n\n- (void)setIsPrintOnlyMessage:(BOOL)isPrintOnlyMessage\n{\n\tif (self->_isPrintOnlyMessage != isPrintOnlyMessage) {\n\t\tself->_isPrintOnlyMessage = isPrintOnlyMessage;\n\t}\n}\n\n- (void)setMessageTags:(nullable NSDictionary<NSString *, NSString *> *)messageTags\n{\n\tif (self->_messageTags != messageTags) {\n\t\tself->_messageTags = [messageTags copy];\n\t}\n}\n\n- (void)setParams:(NSArray<NSString *> *)params\n{\n\tNSParameterAssert(params != nil);\n\n\tif (self->_params != params) {\n\t\tself->_params = [params copy];\n\t}\n}\n\n- (void)setReceivedAt:(NSDate *)receivedAt\n{\n\tNSParameterAssert(receivedAt != nil);\n\n\tif (self->_receivedAt != receivedAt) {\n\t\tself->_receivedAt = [receivedAt copy];\n\t}\n}\n\n- (void)setSender:(IRCPrefix *)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tif (self->_sender != sender) {\n\t\tself->_sender = [sender copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCMessageBatch.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCMessage.h\"\n#import \"IRCMessageBatchPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCMessageBatchMessageContainer ()\n@property (nonatomic, strong) NSMutableDictionary *internalBatchEntries;\n@end\n\n@interface IRCMessageBatchMessage ()\n@property (nonatomic, strong) NSMutableArray *internalBatchEntries;\n@end\n\n#pragma mark -\n\n@implementation IRCMessageBatchMessageContainer\n\n- (NSDictionary *)queuedEntries\n{\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn @{};\n\t\t}\n\n\t\treturn [self.internalBatchEntries copy];\n\t}\n}\n\n- (void)dequeueEntries\n{\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.internalBatchEntries removeAllObjects];\n\t}\n}\n\n- (void)dequeueEntry:(id)entry\n{\n\tNSParameterAssert(entry != nil);\n\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *batchToken = nil;\n\n\t\tif ([entry isKindOfClass:[IRCMessageBatchMessage class]]) {\n\t\t\tbatchToken = [entry batchToken];\n\t\t} else if ([entry isKindOfClass:[NSString class]]) {\n\t\t\tbatchToken = entry;\n\n\t\t\tentry = self.internalBatchEntries[batchToken];\n\t\t}\n\n\t\tif (batchToken == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[entry dequeueEntries];\n\n\t\t[self.internalBatchEntries removeObjectForKey:batchToken];\n\t}\n}\n\n- (void)queueEntry:(id)entry\n{\n\tNSParameterAssert(entry != nil);\n\n\tif ([entry isKindOfClass:[IRCMessageBatchMessage class]] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *batchToken = [entry batchToken];\n\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\tself.internalBatchEntries = [NSMutableDictionary dictionary];\n\t\t}\n\n\t\tself.internalBatchEntries[batchToken] = entry;\n\t}\n}\n\n- (id)queuedEntryWithBatchToken:(NSString *)batchToken\n{\n\tNSParameterAssert(batchToken != nil);\n\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn nil;\n\t\t}\n\n\t\treturn self.internalBatchEntries[batchToken];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCMessageBatchMessage\n\n- (NSArray *)queuedEntries\n{\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn @[];\n\t\t}\n\n\t\treturn [self.internalBatchEntries copy];\n\t}\n}\n\n- (void)dequeueEntries\n{\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.internalBatchEntries removeAllObjects];\n\t}\n}\n\n- (void)queueEntry:(id)entry\n{\n\tNSParameterAssert(entry != nil);\n\n\tif ([entry isKindOfClass:[IRCMessage class]] == NO &&\n\t\t[entry isKindOfClass:[IRCMessageBatchMessage class]] == NO)\n\t{\n\t\treturn;\n\t}\n\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\tself.internalBatchEntries = [NSMutableArray array];\n\t\t}\n\n\t\t[self.internalBatchEntries addObject:entry];\n\t}\n}\n\n- (void)dequeueEntry:(id)entry\n{\n\tNSParameterAssert(entry != nil);\n\n\tif ([entry isKindOfClass:[IRCMessage class]] == NO &&\n\t\t[entry isKindOfClass:[IRCMessageBatchMessage class]] == NO)\n\t{\n\t\treturn;\n\t}\n\n\t@synchronized(self.internalBatchEntries) {\n\t\tif (self.internalBatchEntries == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.internalBatchEntries removeObject:entry];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCModeInfo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCModeInfoInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCModeInfo\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol\n{\n\treturn [self initWithModeSymbol:modeSymbol modeIsSet:NO modeParameter:nil];\n}\n\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet\n{\n\treturn [self initWithModeSymbol:modeSymbol modeIsSet:modeIsSet modeParameter:nil];\n}\n\n- (instancetype)initWithModeSymbol:(NSString *)modeSymbol modeIsSet:(BOOL)modeIsSet modeParameter:(nullable NSString *)modeParameter\n{\n\tNSParameterAssert(modeSymbol.length == 1);\n\n\tif ((self = [super init])) {\n\t\tself->_modeSymbol = [modeSymbol copy];\n\t\tself->_modeIsSet = modeIsSet;\n\t\tself->_modeParameter = [modeParameter copy];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)populateDuringCopy:(__kindof XRPortablePropertyObject *)newObject mutableCopy:(BOOL)mutableCopy\n{\n\tIRCModeInfo *object = (IRCModeInfo *)newObject;\n\n\tobject->_modeSymbol = self->_modeSymbol;\n\tobject->_modeIsSet = self->_modeIsSet;\n\tobject->_modeParameter = self->_modeParameter;\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCModeInfoMutable self];\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCModeInfo class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCModeInfo *objectCast = (IRCModeInfo *)object;\n\n\treturn (self.modeIsSet == objectCast.modeIsSet &&\n\t\t\t\n\t\t\t((self.modeSymbol == nil && objectCast.modeSymbol == nil) ||\n\t\t\t [self.modeSymbol isEqualToString:objectCast.modeSymbol]) &&\n\n\t\t\t((self.modeParameter == nil && objectCast.modeParameter == nil) ||\n\t\t\t [self.modeParameter isEqualToString:objectCast.modeParameter]));\n}\n\n- (BOOL)isModeForChangingMemberModeOn:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif (self.modeParameter.length == 0) {\n\t\treturn NO;\n\t}\n\n\treturn [client.supportInfo modeSymbolIsUserPrefix:self.modeSymbol];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCModeInfoMutable\n\n@dynamic modeIsSet;\n@dynamic modeSymbol;\n@dynamic modeParameter;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCModeInfo self];\n}\n\n- (void)setModeIsSet:(BOOL)modeIsSet\n{\n\tif (self->_modeIsSet != modeIsSet) {\n\t\tself->_modeIsSet = modeIsSet;\n\t}\n}\n\n- (void)setModeSymbol:(NSString *)modeSymbol\n{\n\tNSParameterAssert(modeSymbol.length == 1);\n\n\tif (self->_modeSymbol != modeSymbol) {\n\t\tself->_modeSymbol = [modeSymbol copy];\n\t}\n}\n\n- (void)setModeParameter:(nullable NSString *)modeParameter\n{\n\tif (self->_modeParameter != modeParameter) {\n\t\tself->_modeParameter = [modeParameter copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCNetworkList.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCResourceManager.h\"\n#import \"IRCNetworkList.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCNetworkList ()\n@property (nonatomic, copy, readwrite) NSArray<IRCNetwork *> *listOfNetworks;\n@end\n\n@interface IRCNetwork ()\n@property (nonatomic, copy, readwrite) NSString *networkName;\n@property (nonatomic, copy, readwrite) NSString *serverAddress;\n@property (nonatomic, assign, readwrite) uint16_t serverPort;\n@property (nonatomic, assign, readwrite) BOOL prefersSecuredConnection;\n\n- (instancetype)initWithNetworkNamed:(NSString *)networkName networkConfiguration:(NSDictionary<NSString *, id> *)networkConfiguration;\n@end\n\n@implementation IRCNetworkList\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tNSMutableArray<IRCNetwork *> *listOfNetworks = [NSMutableArray array];\n\n\tNSDictionary *networkList = [TPCResourceManager dictionaryFromResources:@\"IRCNetworks\" cacheValue:NO];\n\n\tNSArray *networkNamesUnsorted = networkList.allKeys;\n\n\tNSArray *networkNamesSorted = [networkNamesUnsorted sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];\n\n\tfor (NSString *networkName in networkNamesSorted) {\n\t\tNSDictionary<NSString *, id> *networkConfiguration = networkList[networkName];\n\n\t\t  IRCNetwork *networkObject =\n\t\t[[IRCNetwork alloc] initWithNetworkNamed:networkName networkConfiguration:networkConfiguration];\n\n\t\t[listOfNetworks addObject:networkObject];\n\t}\n\n\tself.listOfNetworks = listOfNetworks;\n}\n\n- (nullable IRCNetwork *)networkNamed:(NSString *)networkName\n{\n\tNSParameterAssert(networkName != nil);\n\n\tIRCNetwork *network =\n\t[self.listOfNetworks objectPassingTest:^BOOL(IRCNetwork *network, NSUInteger index, BOOL *stop) {\n\t\treturn [network.networkName isEqualToStringIgnoringCase:networkName];\n\t}];\n\n\treturn network;\n}\n\n- (nullable IRCNetwork *)networkWithServerAddress:(NSString *)serverAddress\n{\n\tNSParameterAssert(serverAddress != nil);\n\n\tIRCNetwork *network =\n\t[self.listOfNetworks objectPassingTest:^BOOL(IRCNetwork *network, NSUInteger index, BOOL *stop) {\n\t\treturn [network.serverAddress isEqualToStringIgnoringCase:serverAddress];\n\t}];\n\n\treturn network;\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCNetwork\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithNetworkNamed:(NSString *)networkName networkConfiguration:(NSDictionary<NSString *, id> *)networkConfiguration\n{\n\tNSParameterAssert(networkName != nil);\n\tNSParameterAssert(networkConfiguration != nil);\n\n\tif ((self = [super init])) {\n\t\tself.networkName = networkName;\n\n\t\t[self populateNetworkConfiguration:networkConfiguration];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)populateNetworkConfiguration:(NSDictionary<NSString *, id> *)networkConfiguration\n{\n\tNSParameterAssert(networkConfiguration != nil);\n\n\tself.serverAddress = networkConfiguration[@\"serverAddress\"];\n\n\tself.serverPort = [networkConfiguration unsignedShortForKey:@\"serverPort\"];\n\n\tself.prefersSecuredConnection = [networkConfiguration boolForKey:@\"prefersSecuredConnection\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCPrefix.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCPrefixInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCPrefix\n\n- (void)populateDefaultsPostflight\n{\n\tSetVariableIfNil(self->_nickname, @\"\")\n\tSetVariableIfNil(self->_hostmask, @\"\")\n}\n\n- (void)populateDuringCopy:(__kindof XRPortablePropertyObject *)newObject mutableCopy:(BOOL)mutableCopy\n{\n\tIRCPrefix *object = (IRCPrefix *)newObject;\n\n\tobject->_isServer = self->_isServer;\n\tobject->_hostmask = self->_hostmask;\n\tobject->_nickname = self->_nickname;\n\tobject->_username = self->_username;\n\tobject->_address = self->_address;\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCPrefixMutable self];\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCPrefix class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCPrefix *objectCast = (IRCPrefix *)object;\n\n\treturn (self.isServer == objectCast.isServer &&\n\n\t\t\t((self.nickname == nil && objectCast.nickname == nil) ||\n\t\t\t [self.nickname isEqualToString:objectCast.nickname]) &&\n\n\t\t\t((self.username == nil && objectCast.username == nil) ||\n\t\t\t [self.username isEqualToString:objectCast.username]) &&\n\n\t\t\t((self.address == nil && objectCast.address == nil) ||\n\t\t\t [self.address isEqualToString:objectCast.address]) &&\n\n\t\t\t((self.hostmask == nil && objectCast.hostmask == nil) ||\n\t\t\t [self.hostmask isEqualToString:objectCast.hostmask]));\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCPrefixMutable\n\n@dynamic isServer;\n@dynamic nickname;\n@dynamic username;\n@dynamic address;\n@dynamic hostmask;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCPrefix self];\n}\n\n- (void)setIsServer:(BOOL)isServer\n{\n\tif (self->_isServer != isServer) {\n\t\tself->_isServer = isServer;\n\t}\n}\n\n- (void)setNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self->_nickname != nickname) {\n\t\tself->_nickname = [nickname copy];\n\t}\n}\n\n- (void)setUsername:(nullable NSString *)username\n{\n\tif (self->_username != username) {\n\t\tself->_username = [username copy];\n\t}\n}\n\n- (void)setAddress:(nullable NSString *)address\n{\n\tif (self->_address != address) {\n\t\tself->_address = [address copy];\n\t}\n}\n\n- (void)setHostmask:(NSString *)hostmask\n{\n\tNSParameterAssert(hostmask != nil);\n\n\tif (self->_hostmask != hostmask) {\n\t\tself->_hostmask = [hostmask copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCSendingMessage.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCCommandIndex.h\"\n#import \"IRCSendingMessage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCSendingMessage\n\n+ (NSString *)stringWithCommand:(NSString *)command arguments:(nullable NSArray<NSString *> *)arguments\n{\n\tNSParameterAssert(command != nil);\n\n\tNSString *commandUppercase = command.uppercaseString;\n\n\tif (arguments.count == 0) {\n\t\treturn commandUppercase;\n\t}\n\n\tNSMutableString *builtString = [NSMutableString stringWithString:commandUppercase];\n\n\tNSInteger colonIndexBase = [IRCCommandIndex colonPositionForRemoteCommand:command];\n\n\tNSInteger colonIndexCount = 0;\n\n\tfor (NSString *argument in arguments) {\n\t\tif (argument.length == 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\t[builtString appendString:@\" \"];\n\n\t\tif (colonIndexBase == NSNotFound) {\n\t\t\t// Guess where the colon (:) should go.\n\t\t\t//\n\t\t\t// A colon is supposed to represent a section of an outgoing command\n\t\t\t// that has a parameter which contains spaces. For example, PRIVMSG\n\t\t\t// is in the format \"PRIVMSG #channel :long message\" — The message\n\t\t\t// will have spaces part of it, so we inform the server.\n\n\t\t\tif (colonIndexCount == (arguments.count - 1) && ([argument hasPrefix:@\":\"] || [argument contains:@\" \"])) {\n\t\t\t\t[builtString appendString:@\":\"];\n\t\t\t}\n\t\t} else {\n\t\t\t// We know where it goes thanks to the command index\n\n\t\t\tif (colonIndexCount == colonIndexBase) {\n\t\t\t\t[builtString appendString:@\":\"];\n\t\t\t}\n\t\t}\n\n\t\t[builtString appendString:argument];\n\n\t\tcolonIndexCount += 1;\n\t}\n\n\treturn [builtString copy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCServer.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRC.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCServerInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCServer\n\n- (instancetype)init\n{\n\treturn [super initWithDictionary:@{}];\n}\n\n- (void)initializedClassHealthCheck\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\t/* Health checks are disabled because Server Properties might\n\twrite an empty server address to the class then perform a\n\tcopy on the object which would throw an exception. */\n\t/* TODO: Modify Server Properties to be more friendly. */\n\n#if 0\n\tif (self.mutable) {\n\t\treturn;\n\t}\n\n\tNSParameterAssert(self->_serverAddress.length > 0);\n\tNSParameterAssert(self->_serverPort > 0 && self->_serverPort <= TXMaximumTCPPort);\n#endif\n}\n\n- (void)populateDefaultsPreflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tself->_defaults = @{\n\t\t@\"serverPort\" : @(IRCConnectionDefaultServerPort)\n\t};\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tSetVariableIfNil(self->_serverAddress, @\"\")\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n}\n\n- (void)populateDictionaryValues:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tNSMutableDictionary<NSString *, id> *defaultsMutable = [self->_defaults mutableCopy];\n\n\t[defaultsMutable addEntriesFromDictionary:dic];\n\n\t[defaultsMutable assignBoolTo:&self->_prefersSecuredConnection forKey:@\"prefersSecuredConnection\"];\n\n\t[defaultsMutable assignStringTo:&self->_serverAddress forKey:@\"serverAddress\"];\n\t[defaultsMutable assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[defaultsMutable assignUnsignedShortTo:&self->_serverPort forKey:@\"serverPort\"];\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t[dic setBool:self.prefersSecuredConnection forKey:@\"prefersSecuredConnection\"];\n\n\t[dic maybeSetObject:self.serverAddress forKey:@\"serverAddress\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[dic setUnsignedShort:self.serverPort forKey:@\"serverPort\"];\n\n\treturn [dic copy];\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCServer *config = [self allocForCopyAsMutable:mutableCopy];\n\n\tconfig->_defaults = self->_defaults;\n\n\tconfig->_serverPassword = self->_serverPassword;\n\n\tconfig->_destroyKeychainItemsDuringDealloc = self->_destroyKeychainItemsDuringDealloc;\n\n\tif (uniquing) {\n\t\tconfig->_uniqueIdentifier = [NSString stringWithUUID];\n\t}\n\n\treturn [config initWithDictionary:self.dictionaryValueForCopy];\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [IRCServerMutable self];\n}\n\n- (void)dealloc\n{\n\tif (self.destroyKeychainItemsDuringDealloc) {\n\t\t[self destroyServerPasswordKeychainItem];\n\t}\n}\n\n#pragma mark -\n#pragma mark Keychain Management\n\n- (nullable NSString *)serverPassword\n{\n\tif (self->_serverPassword) {\n\t\treturn self->_serverPassword;\n\t}\n\n\treturn self.serverPasswordFromKeychain;\n}\n\n- (nullable NSString *)serverPasswordFromKeychain\n{\n\tNSString *serverPasswordServiceName = [NSString stringWithFormat:@\"textual.server.%@\", self.uniqueIdentifier];\n\n\tNSString *kcPassword = [XRKeychain getPasswordFromKeychainItem:@\"Textual (Server Password)\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   serviceName:serverPasswordServiceName];\n\n\treturn kcPassword;\n}\n\n- (void)writeServerPasswordToKeychain\n{\n\tif (self->_serverPassword == nil) {\n\t\treturn;\n\t}\n\n\tNSString *serverPasswordServiceName = [NSString stringWithFormat:@\"textual.server.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain modifyOrAddKeychainItem:@\"Textual (Server Password)\"\n\t\t\t\t\t\t   withItemKind:@\"application password\"\n\t\t\t\t\t\t\tforUsername:nil\n\t\t\t\t\t\twithNewPassword:self->_serverPassword\n\t\t\t\t\t\t\tserviceName:serverPasswordServiceName];\n\n\tself->_serverPassword = nil;\n}\n\n- (void)destroyServerPasswordKeychainItem\n{\n\tNSString *serverPasswordServiceName = [NSString stringWithFormat:@\"textual.server.%@\", self.uniqueIdentifier];\n\n\t[XRKeychain deleteKeychainItem:@\"Textual (Server Password)\"\n\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t   serviceName:serverPasswordServiceName];\n\n\tself->_serverPassword = nil;\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCServerMutable\n\n@dynamic prefersSecuredConnection;\n@dynamic serverAddress;\n@dynamic serverPassword;\n@dynamic serverPort;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [IRCServer self];\n}\n\n- (void)setPrefersSecuredConnection:(BOOL)prefersSecuredConnection\n{\n\tif (self->_prefersSecuredConnection != prefersSecuredConnection) {\n\t\tself->_prefersSecuredConnection = prefersSecuredConnection;\n\t}\n}\n\n- (void)setServerAddress:(NSString *)serverAddress\n{\n\tNSParameterAssert(serverAddress != nil);\n\n\tif (self->_serverAddress != serverAddress) {\n\t\tself->_serverAddress = [serverAddress copy];\n\t}\n}\n\n- (void)setServerPassword:(nullable NSString *)serverPassword\n{\n\tif (self->_serverPassword != serverPassword) {\n\t\tself->_serverPassword = [serverPassword copy];\n\t}\n}\n\n- (void)setServerPort:(uint16_t)serverPort\n{\n\tif (self->_serverPort != serverPort) {\n\t\tself->_serverPort = serverPort;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCTimerCommand.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannel.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOTimer.h\"\n#import \"IRCTimerCommandPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nstatic NSUInteger IRCTimedCommandLastIdentifier = 0;\n\n@interface IRCTimedCommand ()\n@property (nonatomic, copy, readwrite) NSString *identifier;\n@property (nonatomic, copy, readwrite) NSString *clientId;\n@property (nonatomic, copy, nullable, readwrite) NSString *channelId;\n@property (nonatomic, copy, readwrite) NSString *command;\n@property (nonatomic, strong) TLOTimer *timer;\n@property (nonatomic, assign) BOOL startedBefore;\n@end\n\n@implementation IRCTimedCommand\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(client != nil);\n\n\treturn [self initWithCommand:command onClient:client inChannel:nil];\n}\n\n- (instancetype)initWithCommand:(NSString *)command onClient:(IRCClient *)client inChannel:(nullable IRCChannel *)channel\n{\n\tNSParameterAssert(command != nil);\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.clientId = client.uniqueIdentifier;\n\t\tself.channelId = channel.uniqueIdentifier;\n\n\t\tself.command = command;\n\n\t\t[self assignIdentifier];\n\n\t\t[self initTimerForClient:client];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self.timer stop];\n\n\tself.timer = nil;\n}\n\n- (void)assignIdentifier\n{\n\tIRCTimedCommandLastIdentifier++;\n\n\tself.identifier = [NSString stringWithUnsignedInteger:IRCTimedCommandLastIdentifier];\n}\n\n- (void)initTimerForClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\t__weak typeof(self) weakSelf = self;\n\n\tself.timer =\n\t[TLOTimer timerWithActionBlock:^(TLOTimer * _Nonnull sender) {\n\t\t[client onTimedCommand:weakSelf];\n\t}];\n}\n\n- (void)start:(NSTimeInterval)timerInterval\n{\n\t[self start:timerInterval onRepeat:NO iterations:0];\n}\n\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer\n{\n\t[self start:timerInterval onRepeat:repeatTimer iterations:0];\n}\n\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations\n{\n\t[self.timer start:timerInterval onRepeat:repeatTimer iterations:iterations];\n\n\tself.startedBefore = YES;\n}\n\n- (void)stop\n{\n\t[self.timer stop];\n}\n\n- (BOOL)restart\n{\n\tif (self.startedBefore == NO) {\n\t\treturn NO;\n\t}\n\n\t[self start:self.timerInterval onRepeat:self.repeatTimer iterations:self.iterations];\n\n\treturn YES;\n}\n\n- (NSTimeInterval)timerInterval\n{\n\treturn self.timer.interval;\n}\n\n- (BOOL)timerIsActive\n{\n\treturn self.timer.timerIsActive;\n}\n\n- (BOOL)repeatTimer\n{\n\treturn self.timer.repeatTimer;\n}\n\n- (NSUInteger)iterations\n{\n\treturn self.timer.iterations;\n}\n\n- (NSUInteger)currentIteration\n{\n\treturn self.timer.currentIteration;\n}\n\n- (NSTimeInterval)startTime\n{\n\treturn self.timer.startTime;\n}\n\n- (NSTimeInterval)timeRemaining\n{\n\treturn self.timer.timeRemaining;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCTreeItem.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCTreeItemPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wincomplete-implementation\"\n@implementation IRCTreeItem\n\n- (BOOL)isUnread\n{\n\treturn (self.treeUnreadCount > 0);\n}\n\n- (void)resetState\n{\n\tself.dockUnreadCount = 0;\n\n\tself.nicknameHighlightCount = 0;\n\n\tself.treeUnreadCount = 0;\n}\n\n@end\n#pragma clang diagnostic pop\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/IRCWorld.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *\t* Redistributions of source code must retain the above copyright\n *\t  notice, this list of conditions and the following disclaimer.\n *\t* Redistributions in binary form must reproduce the above copyright\n *\t  notice, this list of conditions and the following disclaimer in the\n *\t  documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual and/or Codeux Software, nor the names of\n *    its contributors may be used to endorse or promote products derived\n * \t  from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCServer.h\"\n#import \"IRCTreeItemPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _autoConnectDelay\t\t\t\t1\n\n#define _reconnectAfterWakeupDelay\t\t8\n\n#define _savePeriodicallyThreshold\t\t300\n\nNSString * const IRCWorldClientListDefaultsKey = @\"World Controller Client Configurations\";\n\nNSString * const IRCWorldClientListWasModifiedNotification = @\"IRCWorldClientListWasModifiedNotification\";\n\nNSString * const IRCWorldDateHasChangedNotification = @\"IRCWorldDateHasChangedNotification\";\n\nNSString * const IRCWorldWillDestroyClientNotification = @\"IRCWorldWillDestroyClientNotification\";\nNSString * const IRCWorldWillDestroyChannelNotification = @\"IRCWorldWillDestroyChannelNotification\";\n\n@interface IRCWorld ()\n@property (nonatomic, strong) NSMutableArray<IRCClient *> *clients;\n@property (nonatomic, assign) BOOL preferencesDidChangeTimerIsActive;\n@property (nonatomic, assign) CFAbsoluteTime savePeriodicallyLastSave;\n@property (nonatomic, copy) NSDate *lastDateHasChangedDate;\n@end\n\n@implementation IRCWorld\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.clients = [NSMutableArray new];\n\n\tself.preferencesDidChangeTimerIsActive = NO;\n\n\tself.savePeriodicallyLastSave = CFAbsoluteTimeGetCurrent();\n}\n\n- (void)dealloc\n{\n\t[self cancelPerformRequests];\n}\n\n#pragma mark -\n#pragma mark Configuration\n\n- (void)setupConfiguration\n{\n\tself.isImportingConfiguration = YES;\n\n\t[mainWindowServerList() beginUpdates];\n\n\tNSArray *clientList = [TPCPreferences clientList];\n\n\tfor (NSDictionary *client in clientList) {\n\t\tIRCClientConfig *e = [[IRCClientConfig alloc] initWithDictionary:client];\n\n\t\t[self createClientWithConfig:e reload:YES];\n\t}\n\n\t[mainWindowServerList() endUpdates];\n\n\tself.isImportingConfiguration = NO;\n\n\t[self setupOtherServices];\n}\n\n- (void)setupOtherServices\n{\n\t[self setupMidnightTimer];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(dateChanged:) name:NSSystemClockDidChangeNotification object:nil];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(userDefaultsDidChange:) name:TPCPreferencesUserDefaultsDidChangeNotification object:nil];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(mainWindowAppearanceChanged:) name:TVCMainWindowAppearanceChangedNotification object:nil];\n}\n\n- (NSArray *)clientConfigurations\n{\n\tNSMutableArray *configurations = [NSMutableArray array];\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[configurations addObject:[u configurationDictionary]];\n\t}\n\n\treturn [configurations copy];\n}\n\n- (void)save\n{\n\tNSArray *clientList = [self clientConfigurations];\n\n\t[TPCPreferences setClientList:clientList];\n}\n\n- (void)savePeriodically\n{\n\tCFAbsoluteTime now = CFAbsoluteTimeGetCurrent();\n\n\tif ((self.savePeriodicallyLastSave + _savePeriodicallyThreshold) < now) {\n\t\t self.savePeriodicallyLastSave = now;\n\n\t\t[self save];\n\t}\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing IRC world\");\n\n\tLogToConsoleTerminationProgress(\"Removing IRC world observers\");\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\tLogToConsoleTerminationProgress(\"Preparing clients: %{public}ld\", self.clientCount);\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u prepareForApplicationTermination];\n\t}\n}\n\n- (void)userDefaultsDidChange:(NSNotification *)notification\n{\n\tif (themeSettings().js_postPreferencesDidChangesNotifications == NO) {\n\t\treturn; // Cancel operation...\n\t}\n\n\tif (self.preferencesDidChangeTimerIsActive == NO) {\n\t\tself.preferencesDidChangeTimerIsActive = YES;\n\n\t\t[self performSelectorInCommonModes:@selector(informAllViewsUserDefaultsDidChange) withObject:nil afterDelay:1.0];\n\t}\n}\n\n- (void)informAllViewsUserDefaultsDidChange\n{\n\tself.preferencesDidChangeTimerIsActive = NO;\n\n\t[self evaluateFunctionOnAllViews:@\"Textual.preferencesDidChange\" arguments:nil onQueue:YES];\n}\n\n- (void)mainWindowAppearanceChanged:(NSNotification *)notification\n{\n\tif (themeSettings().js_postAppearanceChangesNotification == NO) {\n\t\treturn;\n\t}\n\n\t[self informAllViewsMainWindowAppearanceChanged];\n}\n\n- (void)informAllViewsMainWindowAppearanceChanged\n{\n\tTVCMainWindowAppearance *appearance = mainWindow().userInterfaceObjects;\n\n\t[self evaluateFunctionOnAllViews:@\"Textual.appearanceDidChange\" arguments:@[appearance.shortAppearanceDescription] onQueue:YES];\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (NSArray<IRCClient *> *)clientList\n{\n\t@synchronized(self.clients) {\n\t\treturn [self.clients copy];\n\t}\n}\n\n- (void)setClientList:(NSArray<IRCClient *> *)clientList\n{\n\t@synchronized(self.clients) {\n\t\t[self.clients removeAllObjects];\n\n\t\t[self.clients addObjectsFromArray:clientList];\n\n\t\t[self postClientListWasModifiedNotification];\n\t}\n}\n\n- (NSUInteger)clientCount\n{\n\t@synchronized(self.clients) {\n\t\treturn self.clients.count;\n\t}\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)postClientListWasModifiedNotification\n{\n\t[RZNotificationCenter() postNotificationName:IRCWorldClientListWasModifiedNotification object:self];\n}\n\n- (void)autoConnectAfterWakeup:(BOOL)afterWakeUp\n{\n\tif (masterController().ghostModeIsOn && afterWakeUp == NO) {\n\t\treturn;\n\t}\n\n\tNSUInteger delay = 0;\n\n\tif (afterWakeUp) {\n\t\tdelay += _reconnectAfterWakeupDelay;\n\t}\n\n#define _isAutoConnecting\t\t(afterWakeUp == NO && u.config.autoConnect)\n#define _isWakingFromSleep\t\t(afterWakeUp\t   && u.config.autoSleepModeDisconnect && u.disconnectType == IRCClientDisconnectModeComputerSleep)\n\n\tfor (IRCClient *u in self.clientList) {\n\t\tif (_isWakingFromSleep == NO && _isAutoConnecting == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[u autoConnectWithDelay:delay afterWakeUp:afterWakeUp];\n\n\t\tdelay += _autoConnectDelay;\n\t}\n\n#undef _isWakingFromSleep\n#undef _isAutoConnecting\n}\n\n- (void)prepareForSleep\n{\n\tif ([TPCPreferences disconnectOnSleep] == NO) {\n\t\treturn;\n\t}\n\n\tfor (IRCClient *u in self.clientList) {\n\t\tif (u.isConnected == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tu.disconnectType = IRCClientDisconnectModeComputerSleep;\n\n\t\t[u quit];\n\t}\n}\n\n- (void)prepareForScreenSleep\n{\n\tif ([TPCPreferences setAwayOnScreenSleep] == NO) {\n\t\treturn;\n\t}\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u toggleAwayStatus:YES];\n\t}\n}\n\n- (void)wakeFromScreenSleep\n{\n\tif ([TPCPreferences setAwayOnScreenSleep] == NO) {\n\t\treturn;\n\t}\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u toggleAwayStatus:NO];\n\t}\n}\n\n- (void)noteReachabilityChanged:(BOOL)reachable\n{\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u noteReachabilityChanged:reachable];\n\t}\n}\n\n- (void)preferencesChanged\n{\n\t[menuController() preferencesChanged];\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u preferencesChanged];\n\t}\n}\n\n- (void)setupMidnightTimer\n{\n\t[self setupMidnightTimerWithNotification:NO];\n}\n\n- (void)setupMidnightTimerWithNotification:(BOOL)fireNotification\n{\n\t/* Ask for the day, month, and year from the current calendar. */\n\t/* We are not asking for time which means that it will default to zero. */\n\tNSDateComponents *currentDayComponents = [RZCurrentCalendar() components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];\n\n\tNSDate *lastMidnight = [RZCurrentCalendar() dateFromComponents:currentDayComponents];\n\n\t/* Create date components one day in the future. */\n\t/* All other values default to zero. */\n\tNSDateComponents *futureDayComponents = [NSDateComponents new];\n\n\tfutureDayComponents.day = 1;\n\n\t/* With the current date and future components, calculate\n\t the date on which our midnight timer will land. */\n\tNSDate *nextMidnight = [RZCurrentCalendar() dateByAddingComponents:futureDayComponents toDate:lastMidnight options:0];\n\n\t/* Create timer for midnight in future. */\n\t/* We set the tolerance for the timer to absolute zero so that\n\t we are confident that OS X will not reschedule it. */\n\tNSTimer *midnightTimer = [[NSTimer alloc]\n\t\t\t\tinitWithFireDate:nextMidnight\n\t\t\t\t\t\tinterval:0.0\n\t\t\t\t\t\t  target:self\n\t\t\t\t\t\tselector:@selector(dateChanged:)\n\t\t\t\t\t\tuserInfo:nil\n\t\t\t\t\t\t repeats:NO];\n\n\tmidnightTimer.tolerance = 0.0;\n\n\t/* Schedule the timer on the run loop which will retain reference. */\n\t[RZMainRunLoop() addTimer:midnightTimer forMode:NSDefaultRunLoopMode];\n\n\t/* Do not fire notification if day hasn't changed. \n\t This check is down here, instead of at top, because we still want to\n\t reschedule timer when the system date changes. */\n\tif (self.lastDateHasChangedDate != nil) {\n\t\tif ([self.lastDateHasChangedDate isInSameDayAsDate:lastMidnight]) {\n\t\t\tLogToConsoleFault(\"Date changed event received but the day hasn't changed\");\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tself.lastDateHasChangedDate = lastMidnight;\n\n\t/* Post notification if needed. */\n\tif (fireNotification) {\n\t\t[RZNotificationCenter() postNotificationName:IRCWorldDateHasChangedNotification object:nil userInfo:nil];\n\n\t\t[self evaluateFunctionOnAllViews:@\"Textual.dateChanged\"\n\t\t\t\t\t\t\t   arguments:@[@(currentDayComponents.year),\n\t\t\t\t\t\t\t\t\t\t   @(currentDayComponents.month),\n\t\t\t\t\t\t\t\t\t\t   @(currentDayComponents.day)]\n\t\t\t\t\t\t\t\t onQueue:NO];\n\t}\n}\n\n- (void)dateChanged:(id)sender\n{\n\t/* We call the notifications in the timer so we do not have to\n\t ask for the current day components two times. */\n\n\t[self setupMidnightTimerWithNotification:YES];\n}\n\n#pragma mark -\n#pragma mark Tree Items\n\n- (NSArray<__kindof IRCTreeItem *> *)findItemsWithIds:(NSArray<NSString *> *)itemIds\n{\n\tNSParameterAssert(itemIds != nil);\n\n\tNSMutableArray<__kindof IRCTreeItem *> *items = [NSMutableArray array];\n\n\tfor (IRCClient *u in self.clientList) {\n\t\tif ([itemIds containsObject:u.uniqueIdentifier]) {\n\t\t\t[items addObject:u];\n\t\t}\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tif ([itemIds containsObject:c.uniqueIdentifier]) {\n\t\t\t\t[items addObject:c];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [items copy];\n}\n\n- (nullable IRCTreeItem *)findItemWithId:(NSString *)itemId\n{\n\tif (itemId == nil) {\n\t\treturn nil;\n\t}\n\n\tfor (IRCClient *u in self.clientList) {\n\t\tif ([itemId isEqualToString:u.uniqueIdentifier]) {\n\t\t\treturn u;\n\t\t}\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tif ([itemId isEqualToString:c.uniqueIdentifier]) {\n\t\t\t\treturn c;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (nullable IRCClient *)findClientWithId:(NSString *)clientId\n{\n\treturn (IRCClient *)[self findItemWithId:clientId];\n}\n\n- (nullable IRCChannel *)findChannelWithId:(NSString *)channelId onClientWithId:(NSString *)clientId\n{\n\treturn (IRCChannel *)[self findItemWithId:channelId];\n}\n\n- (nullable IRCTreeItem *)findItemWithPasteboardString:(NSString *)string\n{\n\treturn [self findItemWithId:string];\n}\n\n- (NSString *)pasteboardStringForItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\treturn item.uniqueIdentifier;\n}\n\n- (nullable IRCClient *)findClientWithServerAddress:(NSString *)serverAddress\n{\n\tfor (IRCClient *u in self.clientList) {\n\t\tfor (IRCServer *s in u.config.serverList) {\n\t\t\tif ([s.serverAddress isEqualToStringIgnoringCase:serverAddress]) {\n\t\t\t\treturn u;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark JavaScript\n\n- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments\n{\n\t[self evaluateFunctionOnAllViews:function arguments:arguments onQueue:YES];\n}\n\n- (void)evaluateFunctionOnAllViews:(NSString *)function arguments:(nullable NSArray *)arguments onQueue:(BOOL)onQueue\n{\n\tNSParameterAssert(function != nil);\n\n\tif (masterController().applicationIsTerminating) {\n\t\treturn;\n\t}\n\n\tfor (IRCClient *u in self.clientList) {\n\t\t[u.viewController evaluateFunction:function withArguments:arguments onQueue:onQueue];\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t[c.viewController evaluateFunction:function withArguments:arguments onQueue:onQueue];\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Factory\n\n- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config\n{\n\treturn [self createClientWithConfig:config reload:YES];\n}\n\n- (IRCClient *)createClientWithConfig:(IRCClientConfig *)config reload:(BOOL)reload\n{\n\tNSParameterAssert(config != nil);\n\n\tIRCClient *client = [[IRCClient alloc] initWithConfig:config];\n\n\tclient.viewController = [self createViewControllerWithClient:client channel:nil];\n\n\tNSMutableArray<IRCChannel *> *channelList = [NSMutableArray array];\n\n\tfor (IRCChannelConfig *channelConfig in client.config.channelList) {\n\t\tIRCChannel *channel =\n\t\t[self createChannelWithConfig:channelConfig onClient:client add:NO adjust:NO reload:NO];\n\n\t\t[channelList addObject:channel];\n\t}\n\n\tclient.channelList = channelList;\n\n\t@synchronized(self.clients) {\n\t\t[self.clients addObject:client];\n\n\t\tif (reload) {\n\t\t\tNSInteger index = [self.clients indexOfObject:client];\n\n\t\t\t[mainWindowServerList() addItemToList:index inParent:nil];\n\t\t}\n\n\t\tif (self.clients.count == 1) {\n\t\t\t[mainWindow() select:client];\n\t\t}\n\t}\n\n\t[mainWindow() reloadLoadingScreen];\n\n\t[menuController() populateNavigationChannelList];\n\n\t[self postClientListWasModifiedNotification];\n\n\treturn client;\n}\n\n- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client\n{\n\treturn [self createChannelWithConfig:config onClient:client add:YES adjust:YES reload:YES];\n}\n\n- (IRCChannel *)createChannelWithConfig:(IRCChannelConfig *)config onClient:(IRCClient *)client add:(BOOL)add adjust:(BOOL)adjust reload:(BOOL)reload\n{\n\tNSParameterAssert(config != nil);\n\tNSParameterAssert(client != nil);\n\n\tIRCChannel *channel = [[IRCChannel alloc] initWithConfig:config];\n\n\tchannel.associatedClient = client;\n\n\tchannel.viewController = [self createViewControllerWithClient:client channel:channel];\n\n\tif (add) {\n\t\t[client addChannel:channel];\n\t}\n\n\tif (reload) {\n\t\tNSInteger index = [client.channelList indexOfObject:channel];\n\n\t\t[mainWindowServerList() addItemToList:index inParent:client];\n\t}\n\n\tif (adjust) {\n\t\t[mainWindow() adjustSelection];\n\n\t\t[menuController() populateNavigationChannelList];\n\t}\n\n\treturn channel;\n}\n\n- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client\n{\n\treturn [self createPrivateMessage:nickname onClient:client asType:IRCChannelTypePrivateMessage];\n}\n\n- (IRCChannel *)createPrivateMessage:(NSString *)nickname onClient:(IRCClient *)client asType:(IRCChannelType)type\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(type == IRCChannelTypePrivateMessage ||\n\t\t\t\t\t  type == IRCChannelTypeUtility);\n\n\tIRCChannelConfigMutable *config = [IRCChannelConfigMutable new];\n\n\tconfig.channelName = nickname;\n\n\tconfig.type = type;\n\n\tIRCChannel *channel = [self createChannelWithConfig:config onClient:client add:YES adjust:YES reload:YES];\n\n\tif (client.isLoggedIn && channel.isPrivateMessage) {\n\t\t[channel activate];\n\t}\n\n\treturn channel;\n}\n\n- (TVCLogController *)createViewControllerWithClient:(IRCClient *)client channel:(nullable IRCChannel *)channel\n{\n\tNSParameterAssert(client != nil);\n\n\tTVCLogController *viewController = nil;\n\n\tif (channel == nil) {\n\t\tviewController = [[TVCLogController alloc] initWithClient:client inWindow:mainWindow()];\n\t} else {\n\t\tviewController = [[TVCLogController alloc] initWithChannel:channel inWindow:mainWindow()];\n\t}\n\n\treturn viewController;\n}\n\n- (void)selectOtherBeforeDestroy:(IRCTreeItem *)target\n{\n\tNSParameterAssert(target != nil);\n\n\tif (target.isClient) {\n\t\t[mainWindow() deselectGroup:target];\n\t} else {\n\t\t[mainWindow() deselect:target];\n\t}\n}\n\n- (void)destroyClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\t/* It is not safe to destroy the client while connected. */\n\tif (client.isConnecting || client.isConnected) {\n\t\t__weak IRCWorld *weakSelf = self;\n\n\t\t__weak IRCClient *weakClient = client;\n\n\t\tclient.disconnectCallback = ^{\n\t\t\t[weakSelf destroyClient:weakClient];\n\t\t};\n\n\t\t[client quit];\n\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() postNotificationName:IRCWorldWillDestroyClientNotification object:client];\n\n\t[self selectOtherBeforeDestroy:client];\n\n\t[client prepareForPermanentDestruction];\n\n\t@try {\n\t\t[mainWindowServerList() removeItemFromList:client];\n\t}\n\t@catch (NSException *exception) {\n\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\tLogStackTrace();\n\t}\n\n\t@synchronized(self.clients) {\n\t\t[self.clients removeObjectIdenticalTo:client];\n\t}\n\n\t[self postClientListWasModifiedNotification];\n\n\t[mainWindow() reloadLoadingScreen];\n\n\t[menuController() populateNavigationChannelList];\n}\n\n- (void)destroyChannel:(IRCChannel *)channel\n{\n\t[self destroyChannel:channel reload:YES part:YES];\n}\n\n- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload\n{\n\t[self destroyChannel:channel reload:reload part:YES];\n}\n\n- (void)destroyChannel:(IRCChannel *)channel reload:(BOOL)reload part:(BOOL)partChannel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[RZNotificationCenter() postNotificationName:IRCWorldWillDestroyChannelNotification object:channel];\n\n\tIRCClient *client = channel.associatedClient;\n\n\tif (partChannel) {\n\t\t[client partChannel:channel];\n\t}\n\n\tif (reload) {\n\t\t[self selectOtherBeforeDestroy:channel];\n\t}\n\n\t[channel prepareForPermanentDestruction];\n\n\tif (client.lastSelectedChannel == channel) {\n\t\tclient.lastSelectedChannel = nil;\n\t}\n\n\tif (reload) {\n\t\t@try {\n\t\t\t[mainWindowServerList() removeItemFromList:channel];\n\t\t}\n\t\t@catch (NSException *exception) {\n\t\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\t\tLogStackTrace();\n\t\t}\n\n\t\t[client removeChannel:channel];\n\n\t\t[mainWindow() adjustSelection];\n\n\t\t[menuController() populateNavigationChannelList];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/Users/IRCChannelUser.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCUserPrivate.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCChannelUserInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCChannelUser ()\n@property (atomic, strong, readwrite) IRCUser *user;\n@property (readonly) IRCClient *client;\n@property (readonly) NSString *highestRankedUserMode;\n@end\n\n@implementation IRCChannelUser\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithUser:(IRCUser *)user\n{\n\tNSParameterAssert(user != nil);\n\n\tif ((self = [super init])) {\n\t\tself.user = user;\n\n\t\t[self prepareInitialState];\n\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself->_lastWeightFade = CFAbsoluteTimeGetCurrent();\n\n\tself->_creationTime = [[NSDate date] timeIntervalSince1970];\n}\n\n- (void)populateDefaultsPostflight\n{\n\tSetVariableIfNil(self->_modes, @\"\")\n}\n\n- (void)changeUserToUser:(IRCUser *)user\n{\n\tNSParameterAssert(user != nil);\n\n\tself.user = user;\n}\n\n- (IRCClient *)client\n{\n\treturn self.user.client;\n}\n\n- (BOOL)userModesContainsMode:(NSString *)mode\n{\n\treturn [self.modes contains:mode];\n}\n\n- (NSString *)highestRankedUserMode\n{\n\tNSString *modes = self.modes;\n\n\tif (modes.length == 0) {\n\t\treturn modes;\n\t}\n\n\treturn [modes stringCharacterAtIndex:0];\n}\n\n- (NSString *)mark\n{\n\tIRCISupportInfo *supportInfo = self.client.supportInfo;\n\n\tNSString *mode = self.highestRankedUserMode;\n\n\tNSString *mark = [supportInfo userPrefixForModeSymbol:mode];\n\n\tif (mark) {\n\t\treturn mark;\n\t}\n\n\treturn @\"\";\n}\n\n- (NSUInteger)channelRank\n{\n\tIRCISupportInfo *supportInfo = self.client.supportInfo;\n\n\tNSString *mode = self.highestRankedUserMode;\n\n\treturn [supportInfo rankForUserPrefixWithMode:mode];\n}\n\n- (BOOL)isOp\n{\n\treturn [self.modes containsCharacters:@\"qOao\"];\n}\n\n- (BOOL)isHalfOp \n{\n\treturn [self.modes containsCharacters:@\"qOaoh\"];\n}\n\n- (IRCUserRank)rank\n{\n\tNSString *mode = self.highestRankedUserMode;\n\n\treturn [self rankForModeSymbol:mode];\n}\n\n- (IRCUserRank)ranks\n{\n\tIRCUserRank ranks = 0;\n\n\tNSString *modes = self.modes;\n\n\tfor (NSUInteger i = 0; i < modes.length; i++) {\n\t\tNSString *mode = [modes stringCharacterAtIndex:i];\n\n\t\tIRCUserRank rank = [self rankForModeSymbol:mode];\n\n\t\tif (rank != IRCUserRankNone) {\n\t\t\tranks |= rank;\n\t\t}\n\t}\n\n\tif (ranks == 0) {\n\t\tranks |= IRCUserRankNone;\n\t}\n\n\treturn ranks;\n}\n\n- (IRCUserRank)rankForModeSymbol:(nullable NSString *)modeSymbol\n{\n\tif (modeSymbol == nil) {\n\t\treturn IRCUserRankNone;\n\t}\n\n\tif ([modeSymbol isEqualToString:@\"y\"] ||\n\t\t[modeSymbol isEqualToString:@\"Y\"])\n\t{\n\t\treturn IRCUserRankIRCopByMode;\n\t}\n\telse if ([modeSymbol isEqualToString:@\"q\"] ||\n\t\t\t [modeSymbol isEqualToString:@\"O\"])\n\t{\n\t\treturn IRCUserRankChannelOwner;\n\t} else if ([modeSymbol isEqualToString:@\"a\"]) {\n\t\treturn IRCUserRankSuperOperator;\n\t} else if ([modeSymbol isEqualToString:@\"o\"]) {\n\t\treturn IRCUserRankNormalOperator;\n\t} else if ([modeSymbol isEqualToString:@\"h\"]) {\n\t\treturn IRCUserRankHalfOperator;\n\t} else if ([modeSymbol isEqualToString:@\"v\"]) {\n\t\treturn IRCUserRankVoiced;\n\t}\n\n\treturn IRCUserRankNone;\n}\n\n- (double)totalWeight\n{\n\t[self decayConversation];\n\n\treturn (self->_incomingWeight + self->_outgoingWeight);\n}\n\n- (void)outgoingConversation\n{\n\tdouble change = ((lrint(self->_outgoingWeight) == 0) ? 20 : 5);\n\n\tself->_outgoingWeight += change;\n}\n\n- (void)incomingConversation\n{\n\tdouble change = ((lrint(self->_incomingWeight) == 0) ? 100 : 20);\n\n\tself->_incomingWeight += change;\n}\n\n- (void)conversation\n{\n\tdouble change = ((lrint(self->_incomingWeight) == 0) ? 4 : 1);\n\n\tself->_incomingWeight += change;\n}\n\n- (void)decayConversation\n{\n\tCFAbsoluteTime now = CFAbsoluteTimeGetCurrent();\n\n\tdouble minutes = ((now - self->_lastWeightFade) / 60);\n\n\tif (minutes > 1) {\n\t\tself->_lastWeightFade = now;\n\n\t\tif (self->_incomingWeight > 0) {\n\t\t\tself->_incomingWeight /= pow(2, minutes);\n\t\t}\n\n\t\tif (self->_outgoingWeight > 0) {\n\t\t\tself->_outgoingWeight /= pow(2, minutes);\n\t\t}\n\t}\n}\n\n- (NSComparisonResult)compareUsingWeights:(IRCChannelUser *)other\n{\n\tNSParameterAssert(other != nil);\n\n\tdouble localWeight = self.totalWeight;\n\n\tdouble remoteWeight = other.totalWeight;\n\n\tif (localWeight > remoteWeight) {\n\t\treturn NSOrderedAscending;\n\t} else if (localWeight < remoteWeight) {\n\t\treturn NSOrderedDescending;\n\t}\n\n\treturn [self compareUsingRank:other];\n}\n\n- (NSComparisonResult)compareUsingRank:(IRCChannelUser *)other\n{\n\tNSParameterAssert(other != nil);\n\n\tBOOL favorIRCop = [TPCPreferences memberListSortFavorsServerStaff];\n\n\tif (favorIRCop && self.user.isIRCop && other.user.isIRCop == NO) {\n\t\treturn NSOrderedAscending;\n\t} else if (favorIRCop && self.user.isIRCop == NO && other.user.isIRCop) {\n\t\treturn NSOrderedDescending;\n\t}\n\n\tNSNumber *localRank = @([self channelRank]);\n\n\tNSNumber *remoteRank = @([other channelRank]);\n\n\tNSComparisonResult normalRank = [localRank compare:remoteRank];\n\n\tNSComparisonResult invertedRank = NSInvertedComparisonResult(normalRank);\n\n\tif (invertedRank == NSOrderedSame) {\n\t\treturn [self.user.nickname caseInsensitiveCompare:other.user.nickname];\n\t}\n\n\treturn invertedRank;\n}\n\n+ (NSComparator)channelRankComparator\n{\n\treturn [^(IRCChannelUser *object1, IRCChannelUser *object2) {\n\t\treturn [object1 compareUsingRank:object2];\n\t} copy];\n}\n\n+ (NSComparator)nicknameLengthComparator\n{\n\treturn [^(IRCChannelUser *object1, IRCChannelUser *object2) {\n\t\treturn (object1.user.nickname.length <=\n\t\t\t\tobject2.user.nickname.length);\n\t} copy];\n}\n\n- (NSString *)description\n{\n\treturn [NSString stringWithFormat:@\"<IRCChannelUser %@%@>\", self.mark, self.user.nickname];\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCChannelUser class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCChannelUser *objectCast = (IRCChannelUser *)object;\n\n\treturn (self.user == objectCast.user &&\n\n\t\t\t((self.modes == nil && objectCast.modes == nil) ||\n\t\t\t [self.modes isEqualToString:objectCast.modes]));\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCChannelUser *object = [self allocForCopyAsMutable:mutableCopy];\n\n\tobject->_user = self->_user;\n\n\tobject->_modes = self->_modes;\n\n\tobject->_creationTime = self->_creationTime;\n\n\tobject->_incomingWeight = self->_incomingWeight;\n\tobject->_outgoingWeight = self->_outgoingWeight;\n\tobject->_lastWeightFade = self->_lastWeightFade;\n\n\treturn [object initOnCopy];\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCChannelUserMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCChannelUser (IRCUserRelationsPrivate)\n\n- (void)disassociateWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[self.user disassociateUserWithChannel:channel];\n}\n\n- (void)associateWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[self.user associateUser:self withChannel:channel];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCChannelUserMutable\n\n@dynamic modes;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCChannelUser self];\n}\n\n- (void)setModes:(NSString *)modes\n{\n\tNSParameterAssert(modes != nil);\n\n\tif (self->_modes != modes) {\n\t\tself->_modes = [modes copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/Users/IRCUser.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCUserPersistentStorePrivate.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCUserInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* IRCUser has an internal timer that is started when relations reach zero.\n This timer runs for five minutes, using a GCD timer. When the timer fires,\n it removes the user from the client, thus remove any trace of it. */\n#define _removeUserTimerInterval\t\t\t\t\t(60 * 5) // 5 minutes\n\n#define _presentAwayMessageFor301Threshold\t\t\t300.0\n\n@interface IRCUser ()\n@property (nonatomic, weak, readwrite) IRCClient *client;\n@property (nonatomic, strong) IRCUserPersistentStore *persistentStore;\n@property (readonly) IRCUserRelations *relationsInt;\n@end\n\n@implementation IRCUser\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithNickname:(NSString *)nickname onClient:(IRCClient *)client\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_nickname = [nickname copy];\n\n\t\tself.client = client;\n\n\t\t[self createNewPersistentStoreObject];\n\t}\n\n\treturn self;\n}\n\n- (void)createNewPersistentStoreObject\n{\n\tself.persistentStore = [IRCUserPersistentStore new];\n\n\tself.persistentStore.relations = [IRCUserRelations new];\n}\n\n- (void)dealloc\n{\n\t[self cancelRemoveUserTimer];\n}\n\n- (IRCUserRelations *)relationsInt\n{\n\treturn self.persistentStore.relations;\n}\n\n- (void)markAsAway\n{\n\t[self setIsAway:YES];\n}\n\n- (void)markAsReturned\n{\n\t[self setIsAway:NO];\n}\n\n- (void)setIsAway:(BOOL)isAway\n{\n\tif (self->_isAway != isAway) {\n\t\tself->_isAway = isAway;\n\t}\n}\n\n- (BOOL)presentAwayMessageFor301\n{\n\tCFAbsoluteTime now = CFAbsoluteTimeGetCurrent();\n\n\tif ((self.persistentStore.presentAwayMessageFor301LastEvent + _presentAwayMessageFor301Threshold) < now) {\n\t\t self.persistentStore.presentAwayMessageFor301LastEvent = now;\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (nullable NSString *)hostmaskFragment\n{\n\tNSString *username = self.username;\n\tNSString *address = self.address;\n\n\tif (username == nil || address == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSString stringWithFormat:@\"%@@%@\", username, address];\n}\n\n- (nullable NSString *)hostmask\n{\n\tNSString *nickname = self.nickname;\n\tNSString *username = self.username;\n\tNSString *address = self.address;\n\n\tif (username == nil || address == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSString stringWithFormat:@\"%@!%@@%@\", nickname, username, address];\n}\n\n- (NSString *)banMask\n{\n\tNSString *nickname = self.nickname;\n\tNSString *username = self.username;\n\tNSString *address = self.address;\n\n\tif (username == nil || address == nil) {\n\t\treturn [NSString stringWithFormat:@\"%@!*@*\", nickname];\n\t}\n\n\tswitch ([TPCPreferences banFormat]) {\n\t\tcase TXHostmaskBanFormatWHNIN:\n\t\t{\n\t\t\treturn [NSString stringWithFormat:@\"*!*@%@\", address];\n\t\t}\n\t\tcase TXHostmaskBanFormatWHAINN:\n\t\t{\n\t\t\treturn [NSString stringWithFormat:@\"*!%@@%@\", username, address];\n\t\t}\n\t\tcase TXHostmaskBanFormatWHANNI:\n\t\t{\n\t\t\treturn [NSString stringWithFormat:@\"%@!*%@\", nickname, address];\n\t\t}\n\t\tcase TXHostmaskBanFormatExact:\n\t\t{\n\t\t\treturn [NSString stringWithFormat:@\"%@!%@@%@\", nickname, username, address];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (NSString *)lowercaseNickname\n{\n\treturn self.nickname.lowercaseString;\n}\n\n- (NSString *)uppercaseNickname\n{\n\treturn self.nickname.uppercaseString;\n}\n\n- (NSString *)description\n{\n\treturn [NSString stringWithFormat:@\"<IRCUser %@>\", self.nickname];\n}\n\n- (BOOL)isEqual:(id)object\n{\n\tif (object == nil) {\n\t\treturn NO;\n\t}\n\n\tif (object == self) {\n\t\treturn YES;\n\t}\n\n\tif ([object isKindOfClass:[IRCUser class]] == NO) {\n\t\treturn NO;\n\t}\n\n\tIRCUser *objectCast = (IRCUser *)object;\n\n\treturn (self.client == objectCast.client &&\n\n\t\t\t((self.nickname == nil && objectCast.nickname == nil) ||\n\t\t\t [self.nickname isEqualToString:objectCast.nickname]) &&\n\n\t\t\t((self.username == nil && objectCast.username == nil) ||\n\t\t\t [self.username isEqualToString:objectCast.username]) &&\n\n\t\t\t((self.address == nil && objectCast.address == nil) ||\n\t\t\t [self.address isEqualToString:objectCast.address]) &&\n\n\t\t\t((self.realName == nil && objectCast.realName == nil) ||\n\t\t\t [self.realName isEqualToString:objectCast.realName]) &&\n\n\t\t\tself.isAway == objectCast.isAway &&\n\t\t\tself.isIRCop == objectCast.isIRCop);\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCUser *object = [self allocForCopyAsMutable:mutableCopy];\n\n\tobject->_client = self->_client;\n\n\tobject->_persistentStore = self->_persistentStore;\n\n\tobject->_nickname = self->_nickname;\n\tobject->_username = self->_username;\n\tobject->_address = self->_address;\n\n\tobject->_realName = self->_realName;\n\n\tobject->_isAway = self->_isAway;\n\tobject->_isIRCop = self->_isIRCop;\n\n\treturn [object initOnCopy];\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCUserMutable self];\n}\n\n- (void)updateRemoveUserTimerBlockToFire\n{\n\t/* If the timer is already active, we reset the block that is scheduled\n\t so that the user that is targeted is always the primary */\n\tdispatch_source_t removeUserTimer = self.persistentStore.removeUserTimer;\n\n\tif (removeUserTimer == nil) {\n\t\treturn;\n\t}\n\n\tdispatch_block_t blockToFire = [self removeUserTimerBlockToFire];\n\n\tdispatch_source_set_event_handler(removeUserTimer, blockToFire);\n}\n\n- (void)toggleRemoveUserTimer\n{\n\tif (self.relationsInt.numberOfRelations > 0) {\n\t\t[self cancelRemoveUserTimer];\n\t} else {\n\t\t[self startRemoveUserTimer];\n\t}\n}\n\n- (void)startRemoveUserTimer\n{\n\tdispatch_source_t removeUserTimer = self.persistentStore.removeUserTimer;\n\n\tif (removeUserTimer != NULL) {\n\t\treturn;\n\t}\n\n\tdispatch_block_t blockToFire = [self removeUserTimerBlockToFire];\n\n\tremoveUserTimer = XRScheduleBlockOnGlobalQueue(blockToFire, _removeUserTimerInterval);\n\n\tXRResumeScheduledBlock(removeUserTimer);\n\n\tif (removeUserTimer == NULL) {\n\t\tLogToConsoleFault(\"Failed to create timer to remove user\");\n\n\t\tblockToFire(); // Remove user if timer isn't available\n\n\t\treturn;\n\t}\n\n\tself.persistentStore.removeUserTimer = removeUserTimer;\n}\n\n- (void)cancelRemoveUserTimer\n{\n\tdispatch_source_t removeUserTimer = self.persistentStore.removeUserTimer;\n\n\tif (removeUserTimer == nil) {\n\t\treturn;\n\t}\n\n\tXRCancelScheduledBlock(removeUserTimer);\n\n\tself.persistentStore.removeUserTimer = nil;\n}\n\n- (dispatch_block_t)removeUserTimerBlockToFire\n{\n\t/* Using weak references means that the object can be deallocated when \n\t the timer is active. -dealloc will cancel the timer if it is active. */\n\n\t__weak IRCClient *client = self.client;\n\n\t__weak IRCUser *user = self;\n\n\treturn [^{\n\t\t[client removeUser:user];\n\t} copy];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCUser (IRCUserRelationsPrivate)\n\n- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel\n{\n\t[self.relationsInt associateUser:user withChannel:channel];\n\n\t[self toggleRemoveUserTimer];\n}\n\n- (void)disassociateUserWithChannel:(IRCChannel *)channel\n{\n\t[self.relationsInt disassociateUserWithChannel:channel];\n\n\t[self toggleRemoveUserTimer];\n}\n\n- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel\n{\n\treturn [self.relationsInt userAssociatedWithChannel:channel];\n}\n\n- (void)relinkRelations\n{\n\tNSArray *relatedUsers = self.relationsInt.relatedUsers;\n\n\t[relatedUsers makeObjectsPerformSelector:@selector(changeUserToUser:) withObject:self];\n}\n\n- (void)becamePrimaryUser\n{\n\t[self updateRemoveUserTimerBlockToFire];\n\n\t[self relinkRelations];\n}\n\n- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block\n{\n\t[self.relationsInt enumerateRelations:block];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCUser (IRCUserRelations)\n\n- (NSDictionary<IRCChannel *, IRCChannelUser *> *)relations\n{\n\treturn self.relationsInt.relations;\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCUserMutable\n\n@dynamic nickname;\n@dynamic username;\n@dynamic address;\n@dynamic realName;\n@dynamic isAway;\n@dynamic isIRCop;\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\treturn [self initWithNickname:@\"\" onClient:client];\n}\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCUser self];\n}\n\n- (void)setNickname:(NSString *)nickname\n{\n\tNSParameterAssert(nickname != nil);\n\n\tif (self->_nickname\t!= nickname) {\n\t\tself->_nickname = [nickname copy];\n\t}\n}\n\n- (void)setUsername:(nullable NSString *)username\n{\n\tif (self->_username != username) {\n\t\tself->_username = [username copy];\n\t}\n}\n\n- (void)setAddress:(nullable NSString *)address\n{\n\tif (self->_address != address) {\n\t\tself->_address = [address copy];\n\t}\n}\n\n- (void)setRealName:(nullable NSString *)realName\n{\n\tif (self->_realName != realName) {\n\t\tself->_realName = [realName copy];\n\t}\n}\n\n- (void)setIsAway:(BOOL)isAway\n{\n\tif (self->_isAway != isAway) {\n\t\tself->_isAway = isAway;\n\t}\n}\n\n- (void)setIsIRCop:(BOOL)isIRCop\n{\n\tif (self->_isIRCop != isIRCop) {\n\t\tself->_isIRCop = isIRCop;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/Users/IRCUserNicknameColorStyleGenerator.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CommonCrypto/CommonDigest.h>\n\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _overridesDefaultsKey\t\t\t@\"Nickname Color Style Overrides (v2)\"\n\n@implementation IRCUserNicknameColorStyleGenerator\n\n+ (NSString *)nicknameColorStyleForString:(NSString *)inputString\n{\n\treturn [self nicknameColorStyleForString:inputString isOverride:NULL];\n}\n\n+ (NSString *)nicknameColorStyleForString:(NSString *)inputString isOverride:(BOOL * _Nullable)isOverride\n{\n\tNSParameterAssert(inputString != nil);\n\n\tNSString *unshuffledString = inputString.lowercaseString;\n\n\tNSColor *styleOverride = [self nicknameColorStyleOverrideForKey:unshuffledString];\n\n\tif (styleOverride) {\n\t\tif (isOverride) {\n\t\t\t*isOverride = YES;\n\t\t}\n\n\t\treturn styleOverride.hexadecimalValue;\n\t} else {\n\t\tif (isOverride) {\n\t\t\t*isOverride = NO;\n\t\t}\n\t}\n\n\tTPCThemeSettingsNicknameColorStyle colorStyle = themeSettings().nicknameColorStyle;\n\n\tNSNumber *stringHash =\n\t[self hashForString:unshuffledString colorStyle:colorStyle];\n\n\treturn [self nicknameColorStyleForHash:stringHash colorStyle:colorStyle];\n}\n\n+ (NSString *)nicknameColorStyleForHash:(NSNumber *)stringHash colorStyle:(TPCThemeSettingsNicknameColorStyle)colorStyle\n{\n\tNSParameterAssert(stringHash != nil);\n\n\tBOOL onLightBackground = (colorStyle == TPCThemeSettingsNicknameColorStyleLight);\n\n\tunsigned int stringHash32 = stringHash.intValue;\n\n\tint shash = (stringHash32 >> 1);\n\tint lhash = (stringHash32 >> 2);\n\n\tint h = (stringHash32 % 360);\n\n\tint s;\n\tint l;\n\n\tif (onLightBackground)\n\t{\n\t\ts = (shash % 50 + 35);   // 35 - 85\n\t\tl = (lhash % 38 + 20);   // 20 - 58\n\n\t\t// Lower lightness for Yellow, Green, Cyan\n\t\tif (h > 45 && h <= 195) {\n\t\t\tl = (lhash % 21 + 20);   // 20 - 41\n\n\t\t\tif (l > 31) {\n\t\t\t\ts = (shash % 40 + 55);   // 55 - 95\n\t\t\t} else {\n\t\t\t\ts = (shash % 35 + 65);   // 65 - 95\n\t\t\t}\n\t\t}\n\n\t\t// Give the reds a bit more saturation\n\t\tif (h <= 25 || h >= 335) {\n\t\t\ts = (shash % 33 + 45); // 45 - 78\n\t\t}\n\t}\n\telse\n\t{\n\t\ts = (shash % 50 + 45);   // 50 - 95\n\t\tl = (lhash % 36 + 45);   // 45 - 81\n\n\t\t// give the pinks a wee bit more lightness\n\t\tif (h >= 280 && h < 335) {\n\t\t\tl = (lhash % 36 + 50); // 50 - 86\n\t\t}\n\n\t\t// Give the blues a smaller (but lighter) range\n\t\tif (h >= 210 && h < 240) {\n\t\t\tl = (lhash % 30 + 60); // 60 - 90\n\t\t}\n\n\t\t// Tone down very specific range of blue/purple\n\t\tif (h >= 240 && h < 280) {\n\t\t\ts = (shash % 55 + 40); // 40 - 95\n\t\t\tl = (lhash % 20 + 65); // 65 - 85\n\t\t}\n\n\t\t// Give the reds a bit less saturation\n\t\tif (h <= 25 || h >= 335) {\n\t\t\ts = (shash % 33 + 45); // 45 - 78\n\t\t}\n\n\t\t// Give the yellows and greens a bit less saturation as well\n\t\tif (h >= 50 && h <= 150) {\n\t\t\ts = (shash % 50 + 40); // 40 - 90\n\t\t}\n\t}\n\n\treturn [NSString stringWithFormat:@\"hsl(%i,%i%%,%i%%)\", h, s, l];\n}\n\n+ (NSString *)preprocessString:(NSString *)inputString colorStyle:(TPCThemeSettingsNicknameColorStyle)colorStyle\n{\n\tNSParameterAssert(inputString != nil);\n\n\treturn [NSString stringWithFormat:@\"a-%@\", inputString];\n}\n\n+ (NSNumber *)hashForString:(NSString *)inputString colorStyle:(TPCThemeSettingsNicknameColorStyle)colorStyle\n{\n\tNSParameterAssert(inputString != nil);\n\n\tNSString *stringToHash = [self preprocessString:inputString colorStyle:colorStyle];\n\n\tNSData *stringToHashData = [stringToHash dataUsingEncoding:NSUTF8StringEncoding];\n\n\tNSMutableData *hashedData = [NSMutableData dataWithLength:CC_MD5_DIGEST_LENGTH];\n\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\tCC_MD5(stringToHashData.bytes, (CC_LONG)stringToHashData.length, hashedData.mutableBytes);\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\tunsigned int hashedValue;\n\t[hashedData getBytes:&hashedValue length:sizeof(unsigned int)];\n\n\treturn @(hashedValue);\n}\n\n/*\n *   Color override storage talks in NSColor instead of hexadecimal strings for a few reasons:\n *    1. Easier to work with when modifying. No need to perform messy string conversion.\n *    2. Easier to change output format in another update (if that decision is made)\n */\n+ (void)migrateNicknameColorStyleOverrides\n{\n\t/* Migrate from database that used NSArchiver to one that uses NSKeyedArchiver. */\n\t/* This migration is non-destructive to the legacy database. The data that is\n\t translated to NSKeyedUnarchiver is saved into a new defaults key. */\n\n\tNSDictionary *legacyOverrides = [RZUserDefaults() dictionaryForKey:@\"Nickname Color Style Overrides\"];\n\n\tNSMutableDictionary<NSString *, NSData *> *newOverrides = [NSMutableDictionary dictionaryWithCapacity:legacyOverrides.count];\n\n\t[legacyOverrides enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t\tid override = [NSUnarchiver unarchiveObjectWithData:obj];\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\t\tif (override == nil || [override isKindOfClass:[NSColor class]] == NO) {\n\t\t\tLogToConsoleError(\"Failed to decode contents of '%{private}@'\", key);\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSError *error;\n\n\t\toverride = [NSKeyedArchiver archivedDataWithRootObject:override\n\t\t\t\t\t\t\t\t\t\t requiringSecureCoding:YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t error:&error];\n\n\t\tif (error) {\n\t\t\tLogToConsoleError(\"Failed to decode contents for '%{private}@': %{public}@\",\n\t\t\t\t key, error.description);\n\n\t\t\treturn;\n\t\t}\n\n\t\t[newOverrides setObject:override forKey:key];\n\t}];\n\n\t[RZUserDefaults() setObject:[newOverrides copy] forKey:_overridesDefaultsKey];\n}\n\n+ (nullable NSColor *)nicknameColorStyleOverrideForKey:(NSString *)styleKey\n{\n\tNSParameterAssert(styleKey != nil);\n\n\tNSDictionary *colorOverrides = [RZUserDefaults() dictionaryForKey:_overridesDefaultsKey];\n\n\tif (colorOverrides == nil) {\n\t\treturn nil;\n\t}\n\n\tid colorObject = colorOverrides[styleKey];\n\n\tif ([colorObject isKindOfClass:[NSData class]] == NO) {\n\t\treturn nil;\n\t}\n\n\tNSError *error;\n\n\tNSColor *colorValue = [NSKeyedUnarchiver unarchivedObjectOfClass:[NSColor class]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tfromData:colorObject\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&error];\n\n\tif (error) {\n\t\tLogToConsoleError(\"Failed to decode color for '%{private}@': %{public}@\",\n\t\t\t\tstyleKey, error.description);\n\t}\n\n\treturn colorValue;\n}\n\n+ (void)setNicknameColorStyleOverride:(nullable NSColor *)styleValue forKey:(NSString *)styleKey\n{\n\tNSParameterAssert(styleKey != nil);\n\n\tNSDictionary *colorOverrides = [RZUserDefaults() dictionaryForKey:_overridesDefaultsKey];\n\n\tif (colorOverrides == nil && styleValue == nil) {\n\t\treturn;\n\t}\n\n\tNSData *colorObject = nil;\n\n\tif (styleValue) {\n\t\tNSError *error;\n\n\t\tcolorObject = [NSKeyedArchiver archivedDataWithRootObject:styleValue\n\t\t\t\t\t\t\t\t\t\t\trequiringSecureCoding:YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\terror:&error];\n\n\t\tif (error) {\n\t\t\tLogToConsoleError(\"Failed to decode color for '%{private}@': %{public}@\",\n\t\t\t\t styleKey, error.description);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (colorOverrides == nil) {\n\t\t\tcolorOverrides = [NSDictionary new];\n\t\t}\n\t}\n\n\tNSMutableDictionary *colorOverridesNew = [colorOverrides mutableCopy];\n\n\tif (styleValue == nil) {\n\t\t[colorOverridesNew removeObjectForKey:styleKey];\n\t} else {\n\t\tcolorOverridesNew[styleKey] = colorObject;\n\t}\n\n\tif (colorOverridesNew.count == 0) {\n\t\t[RZUserDefaults() removeObjectForKey:_overridesDefaultsKey];\n\t} else {\n\t\t[RZUserDefaults() setObject:[colorOverridesNew copy] forKey:_overridesDefaultsKey];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/Users/IRCUserPersistentStore.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCUserPersistentStorePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation IRCUserPersistentStore\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/IRC/Users/IRCUserRelations.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCChannel.h\"\n#import \"IRCUserRelationsPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCUserRelations ()\n@property (nonatomic, strong, nullable) NSMutableDictionary<IRCChannel *, IRCChannelUser *> *relationsPrivate;\n@end\n\n@implementation IRCUserRelations\n\n- (NSDictionary<IRCChannel *, IRCChannelUser *> *)relations\n{\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn @{};\n\t\t}\n\n\t\treturn [self.relationsPrivate copy];\n\t}\n}\n\n- (NSArray<IRCChannel *> *)relatedChannels\n{\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn @[];\n\t\t}\n\n\t\treturn self.relationsPrivate.allKeys;\n\t}\n}\n\n- (NSArray<IRCChannelUser *> *)relatedUsers\n{\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn @[];\n\t\t}\n\n\t\treturn self.relationsPrivate.allValues;\n\t}\n}\n\n- (void)enumerateRelations:(void (NS_NOESCAPE ^)(IRCChannel *channel, IRCChannelUser *member, BOOL *stop))block\n{\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.relationsPrivate enumerateKeysAndObjectsUsingBlock:block];\n\t}\n}\n\n- (NSUInteger)numberOfRelations\n{\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn self.relationsPrivate.count;\n\t}\n}\n\n- (void)associateUser:(IRCChannelUser *)user withChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(user != nil);\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\tself.relationsPrivate = [NSMutableDictionary dictionary];\n\t\t}\n\n\t\t/* IRCChannel does not really support copying. It returns self.\n\t\t The protocol is declared here in a cast, instead of in the\n\t\t header for IRCChannel, so plugin author's don't make a mistake. */\n\t\tself.relationsPrivate[(IRCChannel <NSCopying> *)channel] = user;\n\t}\n}\n\n- (void)disassociateUserWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.relationsPrivate removeObjectForKey:channel];\n\n\t\tif (self.relationsPrivate.count == 0) {\n\t\t\tself.relationsPrivate = nil;\n\t\t}\n\t}\n}\n\n- (nullable IRCChannelUser *)userAssociatedWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif (channel.isChannel == NO) {\n\t\treturn nil;\n\t}\n\n\t@synchronized (self.relationsPrivate) {\n\t\tif (self.relationsPrivate == nil) {\n\t\t\treturn nil;\n\t\t}\n\n\t\treturn self.relationsPrivate[channel];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/Color Formatting/IRCColorFormat.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCLogRenderer.h\"\n#import \"IRC.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClient.h\"\n#import \"IRCColorFormatPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const IRCTextFormatterBoldAttributeName = @\"IRCTextFormatterBoldAttributeName\";\nNSString * const IRCTextFormatterItalicAttributeName = @\"IRCTextFormatterItalicAttributeName\";\nNSString * const IRCTextFormatterMonospaceAttributeName = @\"IRCTextFormatterMonospaceAttributeName\";\nNSString * const IRCTextFormatterStrikethroughAttributeName = @\"IRCTextFormatterStrikethroughAttributeName\";\nNSString * const IRCTextFormatterUnderlineAttributeName = @\"IRCTextFormatterUnderlineAttributeName\";\nNSString * const IRCTextFormatterForegroundColorAttributeName = @\"IRCTextFormatterForegroundColorAttributeName\";\nNSString * const IRCTextFormatterBackgroundColorAttributeName = @\"IRCTextFormatterBackgroundColorAttributeName\";\nNSString * const IRCTextFormatterSpoilerAttributeName = @\"IRCTextFormatterSpoilerAttributeName\";\n\n#pragma mark -\n#pragma mark Private Headers\n\n@interface NSMutableString (IRCTextFormatterPrivate)\n- (NSUInteger)wrapIRCTextFormatterResultWith:(NSUInteger)minimumIndex maxDistance:(NSUInteger)maxDistance;\n@end\n\n#pragma mark -\n#pragma mark Effects Container\n\n@interface IRCTextFormatterEffect ()\n@property (nonatomic, assign, readwrite) IRCTextFormatterEffectType type;\n@property (nonatomic, copy, nullable, readwrite) NSString *value;\n@property (nonatomic, assign, readwrite) UniChar controlCharacter;\n@property (nonatomic, assign, readwrite) NSUInteger length;\n@end\n\n@interface IRCTextFormatterEffects ()\n@property (nonatomic, copy, readwrite) NSArray<IRCTextFormatterEffect *> *effects;\n@property (nonatomic, assign, readwrite) NSUInteger maximumLength;\n@end\n\n@implementation IRCTextFormatterEffect\n\n+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type\n{\n\treturn [[self alloc] initWithEffect:type withValue:nil];\n}\n\n+ (nullable instancetype)effectWithType:(IRCTextFormatterEffectType)type withValue:(nullable id)value\n{\n\treturn [[self alloc] initWithEffect:type withValue:value];\n}\n\n- (instancetype)init\n{\n\treturn [self initWithEffect:IRCTextFormatterEffectNone withValue:nil];\n}\n\n- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type\n{\n\treturn [self initWithEffect:type withValue:nil];\n}\n\n- (nullable instancetype)initWithEffect:(IRCTextFormatterEffectType)type withValue:(nullable id)value\n{\n\tif ((self = [super init])) {\n\t\treturn [self _setupWithEffect:type withValue:value];\n\t}\n\n\treturn nil;\n}\n\n- (nullable instancetype)_setupWithEffect:(IRCTextFormatterEffectType)type withValue:(nullable id)value\n{\n\tUniChar controlCharacter = 0x00;\n\n\tNSUInteger valueLength = 0;\n\n\tNSString *valueOut = nil;\n\n\tswitch (type) {\n\t\tcase IRCTextFormatterEffectNone:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectBold:\n\t\t{\n\t\t\tcontrolCharacter = IRCTextFormatterEffectBoldCharacter;\n\n\t\t\tvalueLength = 2; // opening and closing\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectItalic:\n\t\t{\n\t\t\tcontrolCharacter = IRCTextFormatterEffectItalicCharacter;\n\n\t\t\tvalueLength = 2; // opening and closing\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectMonospace:\n\t\t{\n\t\t\tcontrolCharacter = IRCTextFormatterEffectMonospaceCharacter;\n\n\t\t\tvalueLength = 2; // opening and closing\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectStrikethrough:\n\t\t{\n\t\t\tcontrolCharacter = IRCTextFormatterEffectStrikethroughCharacter;\n\n\t\t\tvalueLength = 2; // opening and closing\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectUnderline:\n\t\t{\n\t\t\tcontrolCharacter = IRCTextFormatterEffectUnderlineCharacter;\n\n\t\t\tvalueLength = 2; // opening and closing\n\n\t\t\tbreak;\n\t\t}\n\t\tcase IRCTextFormatterEffectForegroundColor:\n\t\tcase IRCTextFormatterEffectBackgroundColor:\n\t\t{\n\t\t\tif ([value isKindOfClass:[NSColor class]])\n\t\t\t{\n\t\t\t\tcontrolCharacter = IRCTextFormatterEffectColorAsHexCharacter;\n\n\t\t\t\tvalueOut = [[value hexadecimalValue] substringFromIndex:1]; // Remove leading #\n\t\t\t}\n\t\t\telse if ([value isKindOfClass:[NSNumber class]])\n\t\t\t{\n\t\t\t\tcontrolCharacter = IRCTextFormatterEffectColorAsDigitCharacter;\n\n\t\t\t\tvalueOut = [value integerStringValueWithLeadingZero];\n\t\t\t}\n\n\t\t\tif (valueOut == nil) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tif (type == IRCTextFormatterEffectForegroundColor) {\n\t\t\t\tvalueLength = (valueOut.length + 2); // opening and closing\n\t\t\t} else {\n\t\t\t\tvalueLength = (valueOut.length + 1); // leading comma\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t/* We return nil because all other formatters are just aliases.\n\t\t\t For example, spoiler is an alias for foreground and background. */\n\n\t\t\treturn nil;\n\t\t}\n\t}\n\n\tself.type = type;\n\n\tself.controlCharacter = controlCharacter;\n\n\tself.value = valueOut;\n\n\tself.length = valueLength;\n\n\treturn self;\n}\n\n- (void)appendToStartOf:(NSMutableString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tIRCTextFormatterEffectType type = self.type;\n\n\tNSString *value = self.value;\n\n\tif (type == IRCTextFormatterEffectBackgroundColor) {\n\t\t[string appendFormat:@\",%@\", value];\n\n\t\treturn;\n\t}\n\n\tUniChar controlCharacter = self.controlCharacter;\n\n\tif (value == nil) {\n\t\t[string appendFormat:@\"%c\", controlCharacter];\n\t} else {\n\t\t[string appendFormat:@\"%c%@\", controlCharacter, value];\n\t}\n}\n\n- (void)appendToEndOf:(NSMutableString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tif (self.type == IRCTextFormatterEffectBackgroundColor) {\n\t\treturn;\n\t}\n\n\t[string appendFormat:@\"%c\", self.controlCharacter];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCTextFormatterEffects\n\n+ (instancetype)effectsInAttributes:(NSDictionary<NSString *, id> *)attributes\n{\n\treturn [[self alloc] initWithAttributes:attributes];\n}\n\n- (instancetype)init\n{\n\treturn [self initWithAttributes:@{}];\n}\n\n- (instancetype)initWithAttributes:(NSDictionary<NSString *, id> *)attributes\n{\n\tif ((self = [super init])) {\n\t\treturn [self _setupWithAttributes:attributes];\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)_setupWithAttributes:(NSDictionary<NSString *, id> *)attributes\n{\n\tNSUInteger maximumLength = 0;\n\n\tNSMutableArray *effects = [NSMutableArray arrayWithCapacity:7];\n\n\tIRCTextFormatterEffect *foregroundColor = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectForegroundColor withValue:attributes[IRCTextFormatterForegroundColorAttributeName]];\n\tIRCTextFormatterEffect *backgroundColor = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectBackgroundColor withValue:attributes[IRCTextFormatterBackgroundColorAttributeName]];\n\n\tif (foregroundColor) {\n\t\t[effects addObject:foregroundColor];\n\n\t\tmaximumLength += foregroundColor.length;\n\n\t\t/* It's important that the background color ALWAYS follows the foreground\n\t\t color because the array will be enumerated in order to append the effects. */\n\t\t/* Type of values must be the same. Can't mix and match integer color with hex. */\n\t\tif (foregroundColor.controlCharacter ==\n\t\t\tbackgroundColor.controlCharacter)\n\t\t{\n\t\t\t[effects addObject:backgroundColor];\n\n\t\t\tmaximumLength += backgroundColor.length;\n\t\t}\n\t}\n\n\tBOOL textIsBold = [attributes boolForKey:IRCTextFormatterBoldAttributeName];\n\tBOOL textIsItalicized = [attributes boolForKey:IRCTextFormatterItalicAttributeName];\n\tBOOL textIsMonospace = [attributes boolForKey:IRCTextFormatterMonospaceAttributeName];\n\tBOOL textIsStruckthrough = [attributes boolForKey:IRCTextFormatterStrikethroughAttributeName];\n\tBOOL textIsUnderlined = [attributes boolForKey:IRCTextFormatterUnderlineAttributeName];\n\n\tif (textIsBold) {\n\t\tIRCTextFormatterEffect *effect = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectBold];\n\n\t\t[effects addObject:effect];\n\n\t\tmaximumLength += effect.length;\n\t}\n\n\tif (textIsItalicized) {\n\t\tIRCTextFormatterEffect *effect = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectItalic];\n\n\t\t[effects addObject:effect];\n\n\t\tmaximumLength += effect.length;\n\t}\n\n\tif (textIsMonospace) {\n\t\tIRCTextFormatterEffect *effect = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectMonospace];\n\n\t\t[effects addObject:effect];\n\n\t\tmaximumLength += effect.length;\n\t}\n\n\tif (textIsStruckthrough) {\n\t\tIRCTextFormatterEffect *effect = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectStrikethrough];\n\n\t\t[effects addObject:effect];\n\n\t\tmaximumLength += effect.length;\n\t}\n\n\tif (textIsUnderlined) {\n\t\tIRCTextFormatterEffect *effect = [IRCTextFormatterEffect effectWithType:IRCTextFormatterEffectUnderline];\n\n\t\t[effects addObject:effect];\n\n\t\tmaximumLength += effect.length;\n\t}\n\n\tself.effects = effects;\n\n\tself.maximumLength = maximumLength;\n\n\treturn self;\n}\n\n- (void)appendToStartOf:(NSMutableString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tfor (IRCTextFormatterEffect *effect in self.effects) {\n\t\t[effect appendToStartOf:string];\n\t}\n}\n\n- (void)appendToEndOf:(NSMutableString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\t/* Remember to use a reverse enumerator when closing because\n\t we need to close in the same order in which we opened. */\n\tfor (IRCTextFormatterEffect *effect in self.effects.reverseObjectEnumerator) {\n\t\t[effect appendToEndOf:string];\n\t}\n}\n\n@end\n\n#pragma mark -\n#pragma mark Text Truncation\n\n@implementation NSAttributedString (IRCTextFormatterPrivate)\n\n- (NSString *)stringFormattedForChannel:(NSString *)channelName onClient:(IRCClient *)client withLineType:(TVCLogLineType)lineType effectiveRange:(NSRange * _Nullable)effectiveRange\n{\n\tNSParameterAssert(channelName != nil);\n\tNSParameterAssert(client != nil);\n\n\t/* ///////////////////////////////////////////////////// */\n\t/*\n\t Server-side truncation does not count the total number of characters\n\t in the received message alone. It also counts everything that precedes\n\t it including hostmask, channel name, and command, and newline.\n\n\t Example: \":<nickname>!<username>@<address> PRIVMSG #<channel> :<message>\\r\\n\"\n\n\t The following math takes into account this information.\n\n\t Do not extend this method to support anything more than plain text\n\t messages such as PRIVMSG, ACTION, and NOTICE.\n\t */\n\t/* ///////////////////////////////////////////////////// */\n\n#define\t_textTruncationPRIVMSGCommandConstant\t\t\t9  // \"PRIVMSG\" + surrounding spaces\n#define\t_textTruncationACTIONCommandConstant\t\t\t17 // \"PRIVMSG\" + surrounding spaces + 0x01 + \"ACTION\" + 0x01\n#define _textTruncationNOTICECommandConstant\t\t\t8  // \"NOTICE\" + surrounding spaces\n\n#define _textTruncationHostmaskConstant\t\t\t\t\t60 // Used if local hostmask is unknown\n\n\t/* Maximum distance from end of string that we will\n\t locate a character to perform wrapping on. */\n#define\t_textTruncationWrapMaxDistance\t\t\t25\n\n\t/* Add length of colon (\":\") */\n\tNSUInteger minimumLength = 1;\n\n\t/* Add length of hostmask */\n\tNSString *userHostmask = client.userHostmask;\n\n\tif (userHostmask == nil) {\n\t\tminimumLength += _textTruncationHostmaskConstant; // It's better to have something rather than nothing\n\t} else {\n\t\tminimumLength += userHostmask.length;\n\t}\n\n\t/* Add length of command */\n\tif (lineType == TVCLogLineTypePrivateMessage || lineType == TVCLogLineTypePrivateMessageNoHighlight) {\n\t\tminimumLength += _textTruncationPRIVMSGCommandConstant;\n\t} else if (lineType == TVCLogLineTypeAction || lineType == TVCLogLineTypeActionNoHighlight) {\n\t\tminimumLength += _textTruncationACTIONCommandConstant;\n\t} else if (lineType == TVCLogLineTypeNotice) {\n\t\tminimumLength += _textTruncationNOTICECommandConstant;\n\t} else {\n\t\tNSAssert(NO, @\"Line type not supported\");\n\t}\n\n\t/* Add length of channel name */\n\tminimumLength += channelName.length;\n\n\t/* Add length of space trailing channel name and colon (\" :\") */\n\tminimumLength += 2;\n\n\t/* Add length of trailing \\r\\n */\n\tminimumLength += 2;\n\n\t/* Calculate maximum length */\n\tNSUInteger maximumLength = TXMaximumIRCBodyLength;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tNSUInteger encryptionEstimate = [client lengthOfEncryptedMessageDirectedAt:channelName thatFitsWithinBounds:(maximumLength - minimumLength)];\n\n\tif (encryptionEstimate > 0) {\n\t\tmaximumLength = encryptionEstimate;\n\t}\n#endif\n\n\t/* Perform truncation */\n\tNSString *string = self.string;\n\n\tNSStringEncoding encoding = client.config.primaryEncoding;\n\n\tNSMutableString *result = [NSMutableString string];\n\n\t// Length of result with formatters\n\t__block NSUInteger resultLength = minimumLength;\n\n\t// Length of result without formatters\n\t__block NSUInteger deletionLength  = 0;\n\n\t// Range of attribute segment being worked on\n\tNSRange segmentRange;\n\n\t// Maximum range to find next attribute segment within.\n\t// Defaults to string length because we don't know where\n\t// the first attribute segment may be until first pass.\n\tNSRange limitRange = NSMakeRange(0, string.length);\n\n\t/* Enumerate attributes */\n\twhile (limitRange.length > 0) {\n\t\tBOOL breakLoopAfterAppend = NO;\n\n\t\t/* ///////////////////////////////////////////////////// */\n\t\t/* Gather information about the formatters and calculate\n\t\t the total number of bytes necessary to support them. */\n\t\t/* ///////////////////////////////////////////////////// */\n\n\t\tNSDictionary *attributes = [self attributesAtIndex:limitRange.location\n\t\t\t\t\t\t\t\t\t longestEffectiveRange:&segmentRange\n\t\t\t\t\t\t\t\t\t\t\t\t   inRange:limitRange];\n\n\t\tIRCTextFormatterEffects *formatters = [IRCTextFormatterEffects effectsInAttributes:attributes];\n\n\t\tNSUInteger formattersLength = formatters.maximumLength;\n\n\t\t/* ///////////////////////////////////////////////////// */\n\t\t/* Now that we know the minimum length and number of bytes\n\t\t for the formatters, we can start building the result. */\n\t\t/* ///////////////////////////////////////////////////// */\n\n\t\t/* At this point we do not care what the actual length of this segment is.\n\t\t The math only checks two things: Whether the formatter bytes found above\n\t\t will fit into this segment as well as at least one unicode character with\n\t\t a length of two. If neither of those can fit, then this segment is junk\n\t\t and we can break from it. */\n\n\t\t/* If the location of this segment is 0, then we don't have to worry\n\t\t about checking the length yet. Since the formatter bytes will occupy\n\t\t at maximum X entries at location 0, we can do our append until the\n\t\t next, middle, or end segment. */\n\n\t\tif (segmentRange.location > 0) {   // Length calculations for the middle of our string.\n\t\t\t\t\t\t\t\t\t\t   // Sally sold seashells down by the seashore.\n\t\t\t\t\t\t\t\t\t\t   //        |----------------------| <--- section we have to find\n\n\t\t\tNSUInteger\n\t\t\tnewLength = (resultLength\t\t\t+ // Length of what we have already formatted.\n\t\t\t\t\t\t formattersLength\t\t+ // The formatter bytes for this segment.\n\t\t\t\t\t\t 2);\t\t\t\t\t  // The sad little two. A single unicode character.\n\n\t\t\t/* Will this new segment exceed the maximum size? */\n\t\t\tif (newLength > maximumLength) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t/* Update math */\n\t\tresultLength += formattersLength;\n\n\t\t/* Append formatter openers */\n\t\t[formatters appendToStartOf:result];\n\n\t\t/* We now go character by character and append that. We keep appending until\n\t\t the segment is completed or we run out  of space. When that happens, we break.\n\t\t We have already added the formatter bytes into the math so any math checked in\n\t\t the loop will only be count towards the appended characters. */\n\t\tfor (NSUInteger i = 0; i < segmentRange.length;) {\n\t\t\tNSUInteger characterIndex = (segmentRange.location + i);\n\n\t\t\t/* While an emoji looks like only one character, it can be multiple bytes.\n\t\t\t We use -rangeOfComposedCharacterSequenceAtIndex: to know the true length\n\t\t\t of the character we are about to append. */\n\t\t\tNSRange characterRange = [string rangeOfComposedCharacterSequenceAtIndex:characterIndex];\n\n\t\t\tNSString *character = [string substringWithRange:characterRange];\n\n\t\t\t/* Update math */\n\t\t\tNSInteger characterSize = [character lengthOfBytesUsingEncoding:encoding];\n\n\t\t\tif (characterSize == 0) {\n\t\t\t\tcharacterSize = characterRange.length; // Just incase...\n\t\t\t}\n\n\t\t\tresultLength += characterSize;\n\n\t\t\t/* Would this character go over the max length? */\n\t\t\tif (resultLength > maximumLength) {\n\t\t\t\t/* Look for best character to wrap on */\n\t\t\t\tNSUInteger indexDifference = [result wrapIRCTextFormatterResultWith:segmentRange.location maxDistance:_textTruncationWrapMaxDistance];\n\n\t\t\t\tif (indexDifference != NSNotFound) {\n\t\t\t\t\tdeletionLength -= indexDifference;\n\t\t\t\t}\n\n\t\t\t\t/* Break attribute enumeration using stater variable\n\t\t\t\t because we are in nested statements. */\n\t\t\t\tbreakLoopAfterAppend = YES;\n\n\t\t\t\tbreak; // Break instead of return so that we can close formatters\n\t\t\t}\n\n\t\t\t/* Only update if we aren't at max */\n\t\t\tdeletionLength += characterRange.length;\n\n\t\t\ti += characterRange.length;\n\n\t\t\t/* Perform append */\n\t\t\t[result appendString:character];\n\t\t}\n\n\t\t/* Close formatters */\n\t\t[formatters appendToEndOf:result];\n\n\t\t/* Break from enumeration */\n\t\tif (breakLoopAfterAppend) {\n\t\t\tbreak;\n\t\t}\n\n\t\t/* Calculate next range to find an attribute segment within. */\n\t\tNSUInteger segmentRangeNewLength = (string.length - deletionLength);\n\n\t\tif (segmentRangeNewLength <= 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\tsegmentRange.location = deletionLength;\n\n\t\tsegmentRange.length = segmentRangeNewLength;\n\n\t\tlimitRange = segmentRange;\n\t} // attribute enumeration\n\n\t/* Return length that can be deleted to occupy the result */\n\tif ( effectiveRange) {\n\t\t*effectiveRange = NSMakeRange(0, deletionLength);\n\t}\n\n\t/* Debug information */\n\tLogToConsoleDebug(\"Minimum length: %{public}ld; Final length: %{public}ld; Difference: %{public}ld;\",\n\t\t minimumLength, resultLength, (maximumLength - resultLength));\n\n#undef _textTruncationPRIVMSGCommandConstant\n#undef _textTruncationACTIONCommandConstant\n#undef _textTruncationNOTICECommandConstant\n\n#undef _textTruncationHostmaskConstant\n\n#undef _textTruncationWrapMaxDistance\n\n\treturn result;\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSMutableAttributedString (IRCTextFormatterPrivate)\n\n- (NSString *)stringFormattedForChannel:(NSString *)channelName onClient:(IRCClient *)client withLineType:(TVCLogLineType)lineType\n{\n\tNSParameterAssert(channelName != nil);\n\tNSParameterAssert(client != nil);\n\n\tNSRange effectiveRange;\n\n\tNSString *result = [self stringFormattedForChannel:channelName onClient:client withLineType:lineType effectiveRange:&effectiveRange];\n\n\t[self deleteCharactersInRange:effectiveRange];\n\n\treturn result;\n}\n\n@end\n\n#pragma mark -\n\n@implementation NSAttributedString (IRCTextFormatter)\n\n#pragma mark -\n#pragma mark Text Truncation\n\n- (NSString *)stringFormattedForIRC\n{\n\tNSString *string = self.string;\n\n\tNSMutableString *result = [NSMutableString string];\n\n\t[self enumerateAttributesInRange:self.range\n\t\t\t\t\t\t\t options:0\n\t\t\t\t\t\t  usingBlock:^(NSDictionary *attributes, NSRange effectiveRange, BOOL *stop)\n\t {\n\t\t IRCTextFormatterEffects *formatters = [IRCTextFormatterEffects effectsInAttributes:attributes];\n\n\t\t [formatters appendToStartOf:result];\n\n\t\t NSString *segment = [string substringWithRange:effectiveRange];\n\n\t\t [result appendString:segment];\n\n\t\t [formatters appendToEndOf:result];\n\t }];\n\n\treturn result;\n}\n\n- (BOOL)IRCFormatterAttributeSetInRange:(IRCTextFormatterEffectType)effect\n\t\t\t\t\t\t\t\t  range:(NSRange)limitRange\n{\n\t__block BOOL returnValue = NO;\n\n\t[self enumerateAttributesInRange:limitRange\n\t\t\t\t\t\t\t options:0\n\t\t\t\t\t\t  usingBlock:^(NSDictionary *attributes, NSRange effectiveRange, BOOL *stop)\n\t {\n\t\t switch (effect) {\n\t\t\t case IRCTextFormatterEffectNone:\n\t\t\t {\n\t\t\t\t\tbreak;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBold:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterBoldAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectItalic:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterItalicAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectMonospace:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterMonospaceAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectUnderline:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterUnderlineAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectStrikethrough:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterStrikethroughAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectForegroundColor:\n\t\t\t {\n\t\t\t\t id foregroundColor = attributes[IRCTextFormatterForegroundColorAttributeName];\n\n\t\t\t\t if (foregroundColor == nil) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t if ([foregroundColor isKindOfClass:[NSNumber class]])\n\t\t\t\t {\n\t\t\t\t\t NSInteger colorCode = [foregroundColor integerValue];\n\n\t\t\t\t\t if (colorCode < 0 || colorCode > IRCTextFormatterEffectColorHighestDigit) {\n\t\t\t\t\t\t return;\n\t\t\t\t\t }\n\t\t\t\t }\n\t\t\t\t else if ([foregroundColor isKindOfClass:[NSColor class]] == NO)\n\t\t\t\t {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBackgroundColor:\n\t\t\t {\n\t\t\t\t id backgroundColor = attributes[IRCTextFormatterBackgroundColorAttributeName];\n\n\t\t\t\t if (backgroundColor == nil) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t if ([backgroundColor isKindOfClass:[NSNumber class]])\n\t\t\t\t {\n\t\t\t\t\t NSInteger colorCode = [backgroundColor integerValue];\n\n\t\t\t\t\t if (colorCode < 0 || colorCode > IRCTextFormatterEffectColorHighestDigit) {\n\t\t\t\t\t\t return;\n\t\t\t\t\t }\n\t\t\t\t }\n\t\t\t\t else if ([backgroundColor isKindOfClass:[NSColor class]] == NO)\n\t\t\t\t {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectSpoiler:\n\t\t\t {\n\t\t\t\t if ([attributes boolForKey:IRCTextFormatterSpoilerAttributeName] == NO) {\n\t\t\t\t\t return;\n\t\t\t\t }\n\n\t\t\t\t returnValue = YES;\n\n\t\t\t\t *stop = YES;\n\n\t\t\t\t break;\n\t\t\t }\n\t\t }\n\t }];\n\n\treturn returnValue;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Adding/Removing Formatting\n\n@implementation NSMutableAttributedString (IRCTextFormatter)\n\n- (void)setIRCFormatterAttribute:(IRCTextFormatterEffectType)effect\n\t\t\t\t\t\t   value:(id)value\n\t\t\t\t\t\t   range:(NSRange)limitRange\n{\n\t[self enumerateAttributesInRange:limitRange\n\t\t\t\t\t\t\t options:NSAttributedStringEnumerationReverse\n\t\t\t\t\t\t  usingBlock:^(NSDictionary *attributes, NSRange effectiveRange, BOOL *stop)\n\t {\n\t\t NSFont *baseFont = attributes[NSFontAttributeName];\n\n\t\t switch (effect) {\n\t\t\t case IRCTextFormatterEffectNone:\n\t\t\t {\n\t\t\t\t\tbreak;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBold:\n\t\t\t {\n\t\t\t\t if ([baseFont fontTraitSet:NSBoldFontMask] == NO) {\n\t\t\t\t\t baseFont = [RZFontManager() convertFont:baseFont toHaveTrait:NSBoldFontMask];\n\t\t\t\t }\n\n\t\t\t\t if (baseFont) {\n\t\t\t\t\t [self addAttribute:IRCTextFormatterBoldAttributeName value:@(YES) range:effectiveRange];\n\n\t\t\t\t\t [self addAttribute:NSFontAttributeName value:baseFont range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectItalic:\n\t\t\t {\n\t\t\t\t if ([baseFont fontTraitSet:NSItalicFontMask] == NO) {\n\t\t\t\t\t baseFont = [RZFontManager() convertFont:baseFont toHaveTrait:NSItalicFontMask];\n\t\t\t\t }\n\n\t\t\t\t if (baseFont) {\n\t\t\t\t\t [self addAttribute:IRCTextFormatterItalicAttributeName value:@(YES) range:effectiveRange];\n\n\t\t\t\t\t [self addAttribute:NSFontAttributeName value:baseFont range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectMonospace:\n\t\t\t {\n\t\t\t\t baseFont = [RZFontManager() convertFont:baseFont toFamily:@\"Menlo\"];\n\n\t\t\t\t [self addAttribute:IRCTextFormatterMonospaceAttributeName value:@(YES) range:effectiveRange];\n\n\t\t\t\t [self addAttribute:NSFontAttributeName value:baseFont range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectUnderline:\n\t\t\t {\n\t\t\t\t [self addAttribute:IRCTextFormatterUnderlineAttributeName value:@(YES) range:effectiveRange];\n\n\t\t\t\t [self addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectStrikethrough:\n\t\t\t {\n\t\t\t\t [self addAttribute:IRCTextFormatterStrikethroughAttributeName value:@(YES) range:effectiveRange];\n\n\t\t\t\t [self addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleSingle) range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectForegroundColor:\n\t\t\t {\n\t\t\t\t if (value == nil) {\n\t\t\t\t\t break;\n\t\t\t\t }\n\n\t\t\t\t if ([value isKindOfClass:[NSNumber class]])\n\t\t\t\t {\n\t\t\t\t\t NSInteger colorCode = [value integerValue];\n\n\t\t\t\t\t if (colorCode >= 0 && colorCode <= IRCTextFormatterEffectColorHighestDigit) {\n\t\t\t\t\t\t [self addAttribute:IRCTextFormatterForegroundColorAttributeName value:@(colorCode) range:effectiveRange];\n\n\t\t\t\t\t\t [self addAttribute:NSForegroundColorAttributeName value:[TVCLogRenderer mapColorCode:colorCode] range:effectiveRange];\n\t\t\t\t\t }\n\t\t\t\t }\n\t\t\t\t else if ([value isKindOfClass:[NSColor class]])\n\t\t\t\t {\n\t\t\t\t\t [self addAttribute:IRCTextFormatterForegroundColorAttributeName value:value range:effectiveRange];\n\n\t\t\t\t\t [self addAttribute:NSForegroundColorAttributeName value:value range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBackgroundColor:\n\t\t\t {\n\t\t\t\t if (value == nil) {\n\t\t\t\t\t break;\n\t\t\t\t }\n\n\t\t\t\t if ([value isKindOfClass:[NSNumber class]])\n\t\t\t\t {\n\t\t\t\t\t NSInteger colorCode = [value integerValue];\n\n\t\t\t\t\t if (colorCode >= 0 && colorCode <= IRCTextFormatterEffectColorHighestDigit) {\n\t\t\t\t\t\t [self addAttribute:IRCTextFormatterBackgroundColorAttributeName value:@(colorCode) range:effectiveRange];\n\n\t\t\t\t\t\t [self addAttribute:NSBackgroundColorAttributeName value:[TVCLogRenderer mapColorCode:colorCode] range:effectiveRange];\n\t\t\t\t\t }\n\t\t\t\t }\n\t\t\t\t else if ([value isKindOfClass:[NSColor class]])\n\t\t\t\t {\n\t\t\t\t\t [self addAttribute:IRCTextFormatterBackgroundColorAttributeName value:value range:effectiveRange];\n\n\t\t\t\t\t [self addAttribute:NSBackgroundColorAttributeName value:value range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectSpoiler:\n\t\t\t {\n\t\t\t\t [self addAttribute:IRCTextFormatterSpoilerAttributeName value:value range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t }\n\t }];\n}\n\n- (void)removeIRCFormatterAttribute:(IRCTextFormatterEffectType)effect\n\t\t\t\t\t\t\t  range:(NSRange)limitRange\n{\n\t[self enumerateAttributesInRange:limitRange\n\t\t\t\t\t\t\t options:NSAttributedStringEnumerationReverse\n\t\t\t\t\t\t  usingBlock:^(NSDictionary *attributes, NSRange effectiveRange, BOOL *stop)\n\t {\n\t\t NSFont *baseFont = attributes[NSFontAttributeName];\n\n\t\t if (baseFont == nil) {\n\t\t\t return;\n\t\t }\n\n\t\t switch (effect) {\n\t\t\t case IRCTextFormatterEffectNone:\n\t\t\t {\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBold:\n\t\t\t {\n\t\t\t\t if ([baseFont fontTraitSet:NSBoldFontMask]) {\n\t\t\t\t\t baseFont = [RZFontManager() convertFont:baseFont toNotHaveTrait:NSBoldFontMask];\n\n\t\t\t\t\t if (baseFont) {\n\t\t\t\t\t\t [self addAttribute:NSFontAttributeName value:baseFont range:effectiveRange];\n\t\t\t\t\t }\n\n\t\t\t\t\t [self removeAttribute:IRCTextFormatterBoldAttributeName range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectItalic:\n\t\t\t {\n\t\t\t\t if ([baseFont fontTraitSet:NSItalicFontMask]) {\n\t\t\t\t\t baseFont = [RZFontManager() convertFont:baseFont toNotHaveTrait:NSItalicFontMask];\n\n\t\t\t\t\t if (baseFont) {\n\t\t\t\t\t\t [self addAttribute:NSFontAttributeName value:baseFont range:effectiveRange];\n\t\t\t\t\t }\n\n\t\t\t\t\t [self removeAttribute:IRCTextFormatterItalicAttributeName range:effectiveRange];\n\t\t\t\t }\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectMonospace:\n\t\t\t {\n\t\t\t\t [self removeAttribute:NSFontAttributeName range:effectiveRange];\n\n\t\t\t\t [self removeAttribute:IRCTextFormatterMonospaceAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectUnderline:\n\t\t\t {\n\t\t\t\t [self removeAttribute:NSUnderlineStyleAttributeName range:effectiveRange];\n\n\t\t\t\t [self removeAttribute:IRCTextFormatterUnderlineAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectStrikethrough:\n\t\t\t {\n\t\t\t\t [self removeAttribute:NSStrikethroughStyleAttributeName range:effectiveRange];\n\n\t\t\t\t [self removeAttribute:IRCTextFormatterStrikethroughAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectForegroundColor:\n\t\t\t {\n\t\t\t\t [self removeAttribute:NSBackgroundColorAttributeName range:effectiveRange];\n\n\t\t\t\t [self removeAttribute:IRCTextFormatterForegroundColorAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectBackgroundColor:\n\t\t\t {\n\t\t\t\t [self removeAttribute:NSBackgroundColorAttributeName range:effectiveRange];\n\n\t\t\t\t [self removeAttribute:IRCTextFormatterBackgroundColorAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t\t case IRCTextFormatterEffectSpoiler:\n\t\t\t {\n\t\t\t\t [self removeAttribute:IRCTextFormatterSpoilerAttributeName range:effectiveRange];\n\n\t\t\t\t break;\n\t\t\t }\n\t\t }\n\t }];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Truncation Helpers\n\n@implementation NSMutableString (IRCTextFormatterPrivate)\n\n/* Look for best character to wrap on */\n/* Now this is where the append gets a little technical. We want clean\n truncation. Not half-assed ones. Therefore, if we have space character\n and it is within a certain range of the end of the line, then we will\n stop append at that instead of breaking inside of a word. */\n/* Returns number of characters deleted from self or NSNotFound if none. */\n/* minimumIndex is index we can't pass so that we always wrap within our\n own segment and not within another. */\n/* maxDistance is how far back we search backwards from the end.\n While similar, this value is different compared to minimumIndex.\n maxDistance is a suggestion whereas minimumIndex is a must. */\n- (NSUInteger)wrapIRCTextFormatterResultWith:(NSUInteger)minimumIndex maxDistance:(NSUInteger)maxDistance\n{\n\tNSParameterAssert(maxDistance > 0);\n\n\tNSUInteger selfLength = self.length;\n\n\tNSUInteger searchIndex = ((self.length - 1) - maxDistance);\n\n\tNSRange searchRange = NSMakeRange(searchIndex, maxDistance);\n\n\tNSRange spaceRange = [self rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet]\n\t\t\t\t\t\t\t\t\t\t\t   options:NSBackwardsSearch\n\t\t\t\t\t\t\t\t\t\t\t\t range:searchRange];\n\n\tif (spaceRange.location == NSNotFound ||\n\t\tspaceRange.location < minimumIndex)\n\t{\n\t\treturn NSNotFound;\n\t}\n\n\tNSInteger indexDifference = (selfLength - spaceRange.location);\n\n\t[self deleteCharactersInRange:NSMakeRange(spaceRange.location, indexDifference)];\n\n\treturn indexDifference;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/External Libraries/Sockets/OELReachability.m",
    "content": "/*\n Copyright (c) 2011, Tony Million.\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n this list of conditions and the following disclaimer in the documentation\n and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n POSSIBILITY OF SUCH DAMAGE.\n */\n\n#import <SystemConfiguration/SystemConfiguration.h>\n\n#import \"OELReachability.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface OELReachability ()\n@property (nonatomic, assign) SCNetworkReachabilityRef reachabilityRef;\n\n- (void)reachabilityChanged:(SCNetworkReachabilityFlags)flags;\n@end\n\nstatic void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info)\n{\n\tOELReachability *reachability = ((__bridge OELReachability *)info);\n\n\t[reachability reachabilityChanged:flags];\n}\n\n@implementation OELReachability\n\n+ (nullable OELReachability *)reachabilityForInternetConnection\n{\n\tSCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, \"www.google.com\");\n\n\tif (ref) {\n\t\treturn [[self alloc] initWithReachabilityRef:ref];\n\t}\n\n\treturn nil;\n}\n\n- (OELReachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref\n{\n\tif ((self = [super init]))\n\t{\n\t\tself.reachabilityRef = ref;\n\t}\n\n\treturn self;\n}\n\n- (void)dealloc\n{\n\t[self stopNotifier];\n\n\tif (self.reachabilityRef)\n\t{\n\t\tCFRelease(self.reachabilityRef);\n\t\t\t\t  self.reachabilityRef = nil;\n\t}\n\n\tself.reachableBlock\t= nil;\n\tself.unreachableBlock = nil;\n}\n\n- (BOOL)startNotifier\n{\n\tSCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};\n\n\tif (SCNetworkReachabilitySetCallback(self.reachabilityRef, TMReachabilityCallback, &context)) {\n\t\tif (SCNetworkReachabilityScheduleWithRunLoop(self.reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n- (void)stopNotifier\n{\n\tSCNetworkReachabilitySetCallback(self.reachabilityRef, NULL, NULL);\n\n\tSCNetworkReachabilityUnscheduleFromRunLoop(self.reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);\n}\n\n- (BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags\n{\n\tif ((flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable) {\n\t\treturn YES;\n\t} else {\n\t\treturn NO;\n\t}\n}\n\n- (BOOL)isReachable\n{\n\tSCNetworkReachabilityFlags flags;\n\n\tif (SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) == FALSE) {\n\t\treturn NO;\n\t}\n\n\treturn [self isReachableWithFlags:flags];\n}\n\n- (void)reachabilityChanged:(SCNetworkReachabilityFlags)flags\n{\n\tif ([self isReachableWithFlags:flags]) {\n\t\tif (self.reachableBlock) {\n\t\t\tself.reachableBlock(self);\n\t\t}\n\t} else {\n\t\tif (self.unreachableBlock) {\n\t\t\tself.unreachableBlock(self);\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/License Manager/Standalone/TLOLicenseManager.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* \n*\n*  TLOLicenseManager is designed to enforce remote license signatures, but\n*  Textual is open source so it does not make much sense to design it in such\n*  a way that tries to prevent copying.\n*\n*  The license manager is designed to work in very specific ways:\n*\n*  1. Given a documented public key, then the public key is used to verify the\n*     signature that is present in license files.\n*\n*  2. A hash of the public key is hardcoded into a function. On launch, the hash\n*     of the expected public key and the activate public key are compared. If they\n*     are not equal, then this copy of Textual is not \"Genuine\" — in this case, the\n*     user is presented a small prompt informing that Textual is open source and they\n*     should prefer the open source version over a possibly pirated version.\n*\n*  3. At no time shall the license manager make an attempt to lock a user out of\n*     application. At most, limit functionality to trial-mode level.\n*\n*/\n\n/* \n *\tThis source file does not contain source code from, but is designed\n *\taround concepts of, the open source project known as \"AquaticPrime\"\n *\n *\t<https://github.com/bdrister/AquaticPrime>\n*/\n#pragma mark -\n#pragma mark Private Implementation\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\nstatic SecKeyRef TLOLicenseManagerPublicKey = NULL;\nstatic BOOL TLOLicenseManagerPublicKeyIsGenuineResult = YES;\n\nstatic NSDictionary<NSString *, id> * _Nullable TLOLicenseManagerCachedLicenseDictionary = nil;\n\nNSString * const TLOLicenseManagerHashOfGenuinePublicKey = @\"2e14fea44d634095e91a8048404c4ea90d9487a0676f48e89b846a6926b2f4c1\";\nNSString * const TLOLicenseManagerLicenseKeyRegularExpression = @\"^([a-z]{1,12})\\\\-([a-z]{1,12})\\\\-([a-z]{1,12})\\\\-([0-9]{1,35})$\";\nNSUInteger const TLOLicenseManagerLicenseKeyExpectedLength = 45;\nNSInteger const TLOLicenseManagerTrialModeMaximumLifespan = (-2592000); // 30 days in seconds\nNSUInteger const TLOLicenseManagerCurrentLicenseGeneration = 1;\n\nvoid TLOLicenseManagerDeleteLicenseFileIfBlacklisted(void);\nBOOL TLOLicenseManagerLicenseKeyBlacklisted(NSString *licenseKey);\nBOOL TLOLicenseManagerLicenseDictionaryIsValid(NSDictionary<NSString *, id> *licenseDictionary);\nvoid TLOLicenseManagerPopulatePublicKeyRef(void);\nvoid TLOLicenseManagerSetPublicKeyIsGenuine(void);\nBOOL TLOLicenseManagerLicenseFileExists(void);\nCFDataRef TLOLicenseManagerExportContentsOfKeyRef(SecKeyRef theKeyRef, BOOL isPublicKey);\nNSData * _Nullable TLOLicenseManagerPublicKeyContents(void);\nNSData * _Nullable TLOLicenseManagerLicenseFileContents(void);\nTLOLicenseManagerActionResult TLOLicenseManagerLoadLicenseDictionary(void);\nTLOLicenseManagerActionResult TLOLicenseManagerLoadLicenseDictionaryWithData(NSData *licenseContents);\nNSDictionary<NSString *, id> * _Nullable TLOLicenseManagerLicenseDictionary(void);\nNSDictionary<NSString *, id> * _Nullable TLOLicenseManagerLicenseDictionaryWithData(NSData *licenseContents);\nNSURL * _Nullable TLOLicenseManagerTrialModeInformationFilePath(void);\nvoid TLOLicenseManagerMigrateLicenseFiles(void);\nNSURL * _Nullable TLOLicenseManagerLicenseFilePath(void);\nNSNumberFormatter *TLOLicenseManagerStringValueNumberFormatter(void);\nNSString *TLOLicenseManagerStringValueForObject(id object);\n\nNSString * const TLOLicenseManagerLicenseDictionaryKeyCreationDate\t\t\t= @\"licenseCreationDate\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeyGeneration\t\t\t= @\"licenseGeneration\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeyLicenseKey\t\t\t= @\"licenseKey\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeyProductName\t\t\t= @\"licenseProductName\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeyOwnerContactAddress\t= @\"licenseOwnerContactAddress\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeyOwnerName\t\t\t\t= @\"licenseOwnerName\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeySignature\t\t\t\t= @\"licenseSignature\";\nNSString * const TLOLicenseManagerLicenseDictionaryKeySignatureGeneration\t= @\"licenseSignatureGeneration\";\n#endif\n\n#pragma mark -\n#pragma mark Implementation\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\nvoid TLOLicenseManagerSetup(void)\n{\n\tstatic BOOL _setupComplete = NO;\n\n\tif (_setupComplete == NO) {\n\t\t_setupComplete = YES;\n\n\t\tTLOLicenseManagerPopulatePublicKeyRef();\n\n\t\tTLOLicenseManagerMigrateLicenseFiles();\n\n\t\t(void)TLOLicenseManagerLoadLicenseDictionary();\n\n\t\tXRPerformBlockAsynchronouslyOnGlobalQueue(^{\n\t\t\tTLOLicenseManagerSetPublicKeyIsGenuine();\n\n\t\t\tTLOLicenseManagerDeleteLicenseFileIfBlacklisted();\n\t\t});\n\t}\n}\n\n#pragma mark -\n#pragma mark Trial Mode\n\nBOOL TLOLicenseManagerTextualIsRegistered(void)\n{\n\tif (TLOLicenseManagerPublicKeyIsGenuineResult == NO) {\n\t\treturn NO;\n\t} else if (TLOLicenseManagerLicenseFileExists() == NO) {\n\t\treturn NO;\n\t}\n\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\treturn (licenseDictionary != nil);\n}\n\nBOOL TLOLicenseManagerIsTrialExpired(void)\n{\n\tNSTimeInterval timeLeft = TLOLicenseManagerTimeRemainingTrial();\n\n\treturn (timeLeft >= 0);\n}\n\nNSTimeInterval TLOLicenseManagerTimeRemainingTrial(void)\n{\n\t/* Determine where trial information will be stored on disk. */\n\tNSURL *trialInformationFilePath = TLOLicenseManagerTrialModeInformationFilePath();\n\n\tif (trialInformationFilePath == nil) {\n\t\treturn 0;\n\t}\n\n\t/* If the trial information file does not exist yet, then create a new\n\t one which will define when the trial period began. */\n\t/* NSPropertyListSerialization is used by this function, in place of the built\n\t in NSData read & write methods, for better error reporting. */\n\tif ([RZFileManager() fileExistsAtURL:trialInformationFilePath] == NO)\n\t{\n\t\tNSDictionary *trialInformation = @{\n\t\t\t@\"trialPeriodStartDate\" : [NSDate date]\n\t\t};\n\n\t\tNSError *trialInformationPropertyListError = nil;\n\n\t\tNSData *trialInformationPropertyList =\n\t\t[NSPropertyListSerialization dataWithPropertyList:trialInformation\n\t\t\t\t\t\t\t\t\t\t\t\t   format:NSPropertyListBinaryFormat_v1_0\n\t\t\t\t\t\t\t\t\t\t\t\t  options:0\n\t\t\t\t\t\t\t\t\t\t\t\t\terror:&trialInformationPropertyListError];\n\n\t\tif (trialInformationPropertyList == nil) {\n\t\t\tLogToConsoleError(\"Failed to create trial information property list: %{public}@\", trialInformationPropertyListError.localizedDescription);\n\n\t\t\treturn 0; // Cannot continue function...\n\t\t}\n\n\t\tNSError *trialInformationWriteError = nil;\n\n\t\tif ([trialInformationPropertyList writeToURL:trialInformationFilePath options:NSDataWritingAtomic error:&trialInformationWriteError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to write trial information to disk: %{public}@\", trialInformationWriteError.localizedDescription);\n\n\t\t\treturn 0; // Cannot continue function...\n\t\t}\n\n\t\tNSError *modifyTrialInformationAttributesError = nil;\n\n\t\tif ([trialInformationFilePath setResourceValue:@(YES) forKey:NSURLIsHiddenKey error:&modifyTrialInformationAttributesError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to modify attributes of trial information file: %{public}@\", modifyTrialInformationAttributesError.localizedDescription);\n\n\t\t\treturn 0; // Cannot continue function...\n\t\t}\n\n\t\tNSError *lockTrialInformationFileError = nil;\n\n\t\tif ([RZFileManager() lockItemAtPath:trialInformationFilePath.path error:&lockTrialInformationFileError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to lock the trial information file: %{public}@\", lockTrialInformationFileError.localizedDescription);\n\n\t\t\treturn 0; // Cannot continue function...\n\t\t}\n\t}\n\n\t/* Read trial information from disk. */\n\tNSError *trialInformationDataReadError = nil;\n\n\tNSData *trialInformationData = [NSData dataWithContentsOfURL:trialInformationFilePath options:0 error:&trialInformationDataReadError];\n\n\tif (trialInformationData == nil) {\n\t\tLogToConsoleError(\"Failed to read contents of trial information file: %{public}@\", trialInformationDataReadError.localizedDescription);\n\n\t\treturn 0; // Cannot continue function...\n\t}\n\n\tNSError *trialInformationPropertyListError = nil;\n\n\tNSDictionary *trialInformation =\n\t[NSPropertyListSerialization propertyListWithData:trialInformationData\n\t\t\t\t\t\t\t\t\t\t\t  options:NSPropertyListImmutable\n\t\t\t\t\t\t\t\t\t\t\t   format:NULL\n\t\t\t\t\t\t\t\t\t\t\t\terror:&trialInformationPropertyListError];\n\n\tif (trialInformation == nil) {\n\t\tLogToConsoleError(\"Failed to convert property list to NSDictionary: %{public}@\", trialInformationPropertyListError.localizedDescription);\n\n\t\treturn 0; // Cannot continue function...\n\t}\n\n\t/* Given dictionary, get start date of trial and return time left. */\n\tNSDate *trialPeriodStartDate = trialInformation[@\"trialPeriodStartDate\"];\n\n\tif (trialPeriodStartDate == nil || [trialPeriodStartDate isKindOfClass:[NSDate class]] == NO) {\n\t\tLogToConsoleError(\"The value of 'trialPeriodStartDate' is nil or not of kind 'NSDate'\");\n\n\t\treturn 0; // Cannot continue function...\n\t}\n\n\t/* trialPeriodStartInterval will be negative because it is in the past. */\n\tNSTimeInterval trialPeriodStartInterval = trialPeriodStartDate.timeIntervalSinceNow;\n\n\tif (trialPeriodStartInterval > 0) {\n\t\t/* Return expired date for those who try to be clever by setting future time. */\n\n\t\treturn 0;\n\t} else if (trialPeriodStartInterval < TLOLicenseManagerTrialModeMaximumLifespan) {\n\t\treturn 0;\n\t} else {\n\t\treturn (TLOLicenseManagerTrialModeMaximumLifespan - trialPeriodStartInterval);\n\t}\n}\n\nNSURL * _Nullable TLOLicenseManagerTrialModeInformationFilePath(void)\n{\n\tNSURL *sourceURL = [TPCPathInfo applicationSupportURL];\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Textual_Trial_Information_v2.plist\"];\n\n\treturn baseURL;\n}\n\n#pragma mark -\n#pragma mark User License File Validation\n\nBOOL TLOLicenseManagerLicenseKeyIsValid(NSString *licenseKey)\n{\n\tNSCParameterAssert(licenseKey != nil);\n\n\tif (licenseKey.length != TLOLicenseManagerLicenseKeyExpectedLength) {\n\t\treturn NO;\n\t}\n\n\tif ([XRRegularExpression string:licenseKey isMatchedByRegex:TLOLicenseManagerLicenseKeyRegularExpression withoutCase:YES] == NO) {\n\t\treturn NO;\n\t} else {\n\t\treturn YES;\n\t}\n}\n\nNSNumberFormatter *TLOLicenseManagerStringValueNumberFormatter(void)\n{\n\t/*\n\t\t Regardless of whether a number in returned dictionary is an\n\t\t integer or double, it is formatted in the signature with four\n\t\t fraction digits. This allows us to avoid having to determine\n\t\t what type of number NSNumber is actually storing. Just format\n\t\t everything the same exact way.\n\n\t\t Integer 1 = \"1.0000\",\n\t\t Double 2.43561 = \"2.4356\"\n\t */\n\tstatic NSNumberFormatter *numberFormatter = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tnumberFormatter = [NSNumberFormatter new];\n\n\t\tnumberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@\"en_US_POSIX\"];\n\t\tnumberFormatter.numberStyle = NSNumberFormatterDecimalStyle;\n\t\tnumberFormatter.alwaysShowsDecimalSeparator = YES;\n\t\tnumberFormatter.usesGroupingSeparator = NO;\n\t\tnumberFormatter.minimumFractionDigits = 4;\n\t\tnumberFormatter.maximumFractionDigits = 4;\n\t});\n\n\treturn numberFormatter;\n}\n\nNSString *TLOLicenseManagerStringValueForObject(id object)\n{\n\t/* The license dictionary can contain more than strings as of Textual 7.\n\t The license signature is the sum of all objects in the license dictionary,\n\t in alphabetical order, concatenated as strings. */\n\t/* This method returns the string representation of an object. */\n\tif ([object isKindOfClass:[NSArray class]])\n\t{\n\t\tNSMutableString *stringValue = [NSMutableString new];\n\n\t\t[object enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {\n\t\t\tNSString *objectValue = TLOLicenseManagerStringValueForObject(object);\n\n\t\t\t[stringValue appendFormat:@\"%lu%@\", index, objectValue];\n\t\t}];\n\n\t\treturn [stringValue copy];\n\t}\n\telse if ([object isKindOfClass:[NSDictionary class]])\n\t{\n\t\tNSMutableString *stringValue = [NSMutableString new];\n\n\t\tNSArray *sortedDictionaryKeys = [[object allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];\n\n\t\tfor (NSString *key in sortedDictionaryKeys) {\n\t\t\tNSString *objectValue = TLOLicenseManagerStringValueForObject(object[key]);\n\n\t\t\t[stringValue appendFormat:@\"%@%@\", key, objectValue];\n\t\t}\n\n\t\treturn [stringValue copy];\n\t}\n\telse if ([object isKindOfClass:[NSString class]])\n\t{\n\t\treturn object;\n\t}\n\telse if ([object isKindOfClass:[NSNumber class]])\n\t{\n\t\tif ([object isBooleanValue]) {\n\t\t\tif ([object boolValue]) {\n\t\t\t\treturn @\"YES\";\n\t\t\t} else {\n\t\t\t\treturn @\"NO\";\n\t\t\t}\n\t\t} else {\n\t\t\tNSNumberFormatter *numberFormatter = TLOLicenseManagerStringValueNumberFormatter();\n\n\t\t\treturn [numberFormatter stringFromNumber:object];\n\t\t}\n\t}\n\n\treturn @\"\";\n}\n\nTLOLicenseManagerActionResult TLOLicenseManagerVerifyLicenseSignatureWithDictionary(NSDictionary<NSString *, id> *licenseDictionary)\n{\n\tNSCParameterAssert(licenseDictionary != nil);\n\n\t/* Attempt to populate public key information. */\n\tif (TLOLicenseManagerPublicKey == NULL) {\n\t\treturn TLOLicenseManagerActionResultOther;\n\t}\n\n\t/* Retrieve license signature information */\n\tNSData *licenseSignature = licenseDictionary[TLOLicenseManagerLicenseDictionaryKeySignature];\n\n\tif (licenseSignature == nil) {\n\t\tLogToConsoleError(\"Missing license signature in license dictionary\");\n\n\t\treturn TLOLicenseManagerActionResultMalformedData;\n\t}\n\n\t/* Retrieve license generation */\n\tNSUInteger licenseGeneration = [licenseDictionary unsignedIntegerForKey:TLOLicenseManagerLicenseDictionaryKeyGeneration];\n\n\tif (licenseGeneration < TLOLicenseManagerCurrentLicenseGeneration) {\n\t\treturn TLOLicenseManagerActionResultGenerationPrevious;\n\t} else if (licenseGeneration > TLOLicenseManagerCurrentLicenseGeneration) {\n\t\treturn TLOLicenseManagerActionResultGenerationNext;\n\t}\n\n\tCFDataRef cfLicenseSignature = (__bridge CFDataRef)(licenseSignature);\n\n\t/* Combine all contents of the dictionary, in sorted order, excluding\n\t the license dictionary signature because thats used for comparison. */\n\tNSMutableDictionary *licenseDictionaryToCombine = [licenseDictionary mutableCopy];\n\n\t[licenseDictionaryToCombine removeObjectForKey:TLOLicenseManagerLicenseDictionaryKeySignature];\n\t[licenseDictionaryToCombine removeObjectForKey:TLOLicenseManagerLicenseDictionaryKeySignatureGeneration];\n\n\tNSString *combinedLicenseDataString = TLOLicenseManagerStringValueForObject(licenseDictionaryToCombine);\n\n\tif (combinedLicenseDataString.length <= 0) {\n\t\tLogToConsoleError(\"Length of combinedLicenseDataString is below or equal to zero (0)\");\n\n\t\treturn TLOLicenseManagerActionResultMalformedData;\n\t}\n\n\tNSData *combinedLicenseData = [combinedLicenseDataString dataUsingEncoding:NSUTF8StringEncoding];\n\n\tCFDataRef cfCombinedLicenseData = (__bridge CFDataRef)(combinedLicenseData);\n\n\t/* Setup transform function for verifying signature */\n\tSecTransformRef verifyFunction = SecVerifyTransformCreate(TLOLicenseManagerPublicKey, cfLicenseSignature, NULL);\n\n\tif (verifyFunction == NULL) {\n\t\tLogToConsoleError(\"Failed to create transform using SecVerifyTransformCreate()\");\n\n\t\treturn TLOLicenseManagerActionResultInvalidSignature;\n\t}\n\n\t/* Setup transform attributes */\n\tif (SecTransformSetAttribute(verifyFunction, kSecTransformInputAttributeName, cfCombinedLicenseData, NULL)\t\t== false ||\n\t\tSecTransformSetAttribute(verifyFunction, kSecDigestTypeAttribute, kSecDigestSHA2, NULL)\t\t\t\t\t\t== false ||\n\t\tSecTransformSetAttribute(verifyFunction, kSecDigestLengthAttribute, (__bridge CFNumberRef)@(256), NULL)\t\t== false)\n\t{\n\t\tCFRelease(verifyFunction);\n\n\t\tLogToConsoleError(\"Failed to modify transform attributes using SecTransformSetAttribute()\");\n\n\t\treturn TLOLicenseManagerActionResultInvalidSignature;\n\t}\n\n\t/* Perform signature verification */\n\tCFTypeRef cfVerifyResult = SecTransformExecute(verifyFunction, NULL);\n\n\tCFRelease(verifyFunction);\n\n\tBOOL verifyResult = NO;\n\n\tif (CFGetTypeID(cfVerifyResult) == CFBooleanGetTypeID()) {\n\t\tverifyResult = (cfVerifyResult == kCFBooleanTrue);\n\t} else {\n\t\tLogToConsoleError(\"SecTransformExecute() returned a result that is not of type: CFBooleanRef\");\n\t}\n\n\tif (cfVerifyResult != NULL) {\n\t\tCFRelease(cfVerifyResult);\n\t}\n\n\tif (verifyResult == NO) {\n\t\treturn TLOLicenseManagerActionResultInvalidSignature;\n\t}\n\n\treturn TLOLicenseManagerActionResultSuccess;\n}\n\n#pragma mark -\n#pragma mark Reading & Writing User License File\n\nvoid TLOLicenseManagerMigrateLicenseFiles(void)\n{\n\tNSURL *newLocation = [TPCPathInfo applicationSupportURL];\n\n\tNSURL *oldTrialData = [[TPCPathInfo userHomeURL] URLByAppendingPathComponent:@\"/Library/Application Support/Textual/Textual_Trial_Information_v2.plist\"];\n\tNSURL *newTrialData = [newLocation URLByAppendingPathComponent:@\"Textual_Trial_Information_v2.plist\"];\n\n\tNSError *moveError = nil;\n\n\tif ([RZFileManager() fileExistsAtURL:newTrialData] == NO &&\n\t\t[RZFileManager() fileExistsAtURL:oldTrialData]) {\n\t\tif ([RZFileManager() copyItemAtURL:oldTrialData toURL:newTrialData error:&moveError]) {\n\t\t\tLogToConsole(\"Moved trial data file to new location\");\n\t\t} else {\n\t\t\tLogToConsoleError(\"Moving trial data file to new location failed: %{public}@\", moveError.localizedDescription);\n\n\t\t\tmoveError = nil; // nil out for next move\n\t\t}\n\t}\n\n\tNSURL *oldLicenseData = [[TPCPathInfo userHomeURL] URLByAppendingPathComponent:@\"/Library/Application Support/Textual/Textual_User_License_v2.plist\"];\n\tNSURL *newLicenseData = [newLocation URLByAppendingPathComponent:@\"Textual_User_License_v2.plist\"];\n\n\tif ([RZFileManager() fileExistsAtURL:newLicenseData] == NO &&\n\t\t[RZFileManager() fileExistsAtURL:oldLicenseData]) {\n\t\tif ([RZFileManager() copyItemAtURL:oldLicenseData toURL:newLicenseData error:&moveError]) {\n\t\t\tLogToConsole(\"Moved license data file to new location\");\n\t\t} else {\n\t\t\tLogToConsoleError(\"Moving license data file to new location failed: %{public}@\", moveError.localizedDescription);\n\t\t}\n\t}\n}\n\nNSURL * _Nullable TLOLicenseManagerLicenseFilePath(void)\n{\n\tNSURL *sourceURL = [TPCPathInfo applicationSupportURL];\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Textual_User_License_v2.plist\"];\n\n\treturn baseURL;\n}\n\nTLOLicenseManagerActionResult TLOLicenseManagerDeleteLicenseFile(void)\n{\n\treturn TLOLicenseManagerWriteLicenseFileContents(nil);\n}\n\nTLOLicenseManagerActionResult TLOLicenseManagerWriteLicenseFileContents(NSData * _Nullable newContents)\n{\n\tNSURL *licenseFilePath = TLOLicenseManagerLicenseFilePath();\n\n\tif (newContents) {\n\t\tTLOLicenseManagerActionResult loadResult =\n\t\tTLOLicenseManagerLoadLicenseDictionaryWithData(newContents);\n\n\t\tif (loadResult != TLOLicenseManagerActionResultSuccess) {\n\t\t\tLogToConsoleError(\"Verify for new license file contents failed\");\n\n\t\t\treturn loadResult;\n\t\t}\n\n\t\tNSError *writeFileError = nil;\n\n\t\tif ([newContents writeToURL:licenseFilePath options:NSDataWritingAtomic error:&writeFileError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to write user license file with error: %{public}@\", writeFileError.localizedDescription);\n\n\t\t\treturn TLOLicenseManagerActionResultCannotWrite;\n\t\t}\n\t} else {\n\t\tTLOLicenseManagerCachedLicenseDictionary = nil;\n\n\t\tNSError *deleteError = nil;\n\n\t\tif ([RZFileManager() removeItemAtURL:licenseFilePath error:&deleteError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to delete user license file with error: %{public}@\", deleteError.localizedDescription);\n\n\t\t\treturn TLOLicenseManagerActionResultCannotWrite;\n\t\t}\n\t}\n\n\treturn TLOLicenseManagerActionResultSuccess;\n}\n\nBOOL TLOLicenseManagerLicenseFileExists(void)\n{\n\tNSURL *licenseFilePath = TLOLicenseManagerLicenseFilePath();\n\n\tif (licenseFilePath == nil) {\n\t\treturn NO;\n\t}\n\n\tBOOL isDirectory = NO;\n\n\tBOOL fileExists = [RZFileManager() fileExistsAtPath:licenseFilePath.path isDirectory:&isDirectory];\n\n\treturn (fileExists && isDirectory == NO);\n}\n\nNSData * _Nullable TLOLicenseManagerLicenseFileContents(void)\n{\n\tNSURL *licenseFilePath = TLOLicenseManagerLicenseFilePath();\n\n\tif (licenseFilePath == nil) {\n\t\tLogToConsoleError(\"Unable to determine the path to retrieve license information from\");\n\n\t\treturn nil;\n\t}\n\n\tif (TLOLicenseManagerLicenseFileExists() == NO) {\n\t\treturn nil;\n\t}\n\n\tNSError *readError = nil;\n\n\tNSData *licenseContents = [NSData dataWithContentsOfURL:licenseFilePath options:0 error:&readError];\n\n\tif (licenseContents == nil) {\n\t\tLogToConsoleError(\"Unable to read user license file. Error: %{public}@\", readError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\treturn licenseContents;\n}\n\nTLOLicenseManagerActionResult TLOLicenseManagerLoadLicenseDictionary(void)\n{\n\tNSData *licenseContents = TLOLicenseManagerLicenseFileContents();\n\n\tif (licenseContents == nil) {\n\t\treturn NO;\n\t}\n\n\treturn TLOLicenseManagerLoadLicenseDictionaryWithData(licenseContents);\n}\n\nTLOLicenseManagerActionResult TLOLicenseManagerLoadLicenseDictionaryWithData(NSData *licenseContents)\n{\n\tNSCParameterAssert(licenseContents != nil);\n\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionaryWithData(licenseContents);\n\n\tif (licenseDictionary == nil) {\n\t\treturn TLOLicenseManagerActionResultCannotRead;\n\t}\n\n\tTLOLicenseManagerActionResult result =\n\tTLOLicenseManagerVerifyLicenseSignatureWithDictionary(licenseDictionary);\n\n\tif (result == TLOLicenseManagerActionResultSuccess) {\n\t\tTLOLicenseManagerCachedLicenseDictionary = [licenseDictionary copy];\n\t}\n\n\treturn result;\n}\n\nNSDictionary<NSString *, id> *TLOLicenseManagerLicenseDictionaryWithData(NSData *licenseContents)\n{\n\tNSCParameterAssert(licenseContents != nil);\n\n\t/* The contents of the user license is /supposed/ to be a properly formatted\n\t property list as sent from the license system hosted on www.codeux.com */\n\tNSError *readError = nil;\n\n\tid licenseDictionary = [NSPropertyListSerialization propertyListWithData:licenseContents\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t options:NSPropertyListImmutable\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  format:NULL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&readError];\n\n\tif (licenseDictionary == nil || [licenseDictionary isKindOfClass:[NSDictionary class]] == NO) {\n\t\tif (readError) {\n\t\t\tLogToConsoleError(\"Failed to convert contents of user license into dictionary. Error: %{public}@\",\n\t\t\t\t  readError.localizedDescription);\n\t\t}\n\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary;\n}\n\nNSDictionary<NSString *, id> * _Nullable TLOLicenseManagerLicenseDictionary(void)\n{\n\treturn TLOLicenseManagerCachedLicenseDictionary;\n}\n\n#pragma mark -\n#pragma mark Public Key Access\n\nNSData * _Nullable TLOLicenseManagerPublicKeyContents(void)\n{\n\t/* Find where public key is */\n\tNSURL *publicKeyPath = [RZMainBundle() URLForResource:@\"RemoteLicenseSystemPublicKey\" withExtension:@\"pub\"];\n\n\tif (publicKeyPath == nil) {\n\t\tLogToConsoleError(\"Unable to find the public key used for verifying signatures\");\n\n\t\treturn nil;\n\t}\n\n\t/* Load contents of the public key */\n\tNSError *readError = nil;\n\n\tNSData *publicKeyContents = [NSData dataWithContentsOfURL:publicKeyPath options:0 error:&readError];\n\n\tif (publicKeyContents == nil) {\n\t\tLogToConsoleError(\"Unable to read contents of the public key used for verifying signatures. Error: %{public}@\",\n\t\t\t  readError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\treturn publicKeyContents;\n}\n\nvoid TLOLicenseManagerSetPublicKeyIsGenuine(void)\n{\n\tNSData *publicKeyContents = TLOLicenseManagerPublicKeyContents();\n\n\tif (publicKeyContents == nil) {\n\t\treturn;\n\t}\n\n\tNSString *publicKeyHash = publicKeyContents.sha256;\n\n\tif ([TLOLicenseManagerHashOfGenuinePublicKey isEqualToString:publicKeyHash]) {\n\t\tTLOLicenseManagerPublicKeyIsGenuineResult = YES;\n\t} else {\n\t\tTLOLicenseManagerPublicKeyIsGenuineResult = NO;\n\t}\n}\n\nvoid TLOLicenseManagerPopulatePublicKeyRef(void)\n{\n\tNSData *publicKeyContents = TLOLicenseManagerPublicKeyContents();\n\n\tif (publicKeyContents == nil) {\n\t\treturn;\n\t}\n\n\tSecItemImportExportKeyParameters importParameters;\n\n\timportParameters.flags = kSecKeyNoAccessControl;\n\timportParameters.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;\n\n\timportParameters.accessRef = NULL;\n\timportParameters.alertPrompt = NULL;\n\timportParameters.alertTitle = NULL;\n\timportParameters.passphrase = NULL;\n\n\timportParameters.keyAttributes = NULL;\n\timportParameters.keyUsage = NULL;\n\n\tSecExternalItemType itemType = kSecItemTypePublicKey;\n\n\tSecExternalFormat externalFormat = kSecFormatPEMSequence;\n\n\tint flags = 0;\n\n\tCFArrayRef tempArray = NULL;\n\n\tOSStatus operationStatus =\n\t\tSecItemImport((__bridge CFDataRef)(publicKeyContents), NULL, &externalFormat, &itemType, flags, &importParameters, NULL, &tempArray);\n\n\tif (operationStatus == noErr) {\n\t\tTLOLicenseManagerPublicKey = (SecKeyRef)CFArrayGetValueAtIndex(tempArray, 0);\n\n\t\tCFRetain(TLOLicenseManagerPublicKey);\n\n\t\tCFRelease(tempArray);\n\n\t\treturn;\n\t}\n\n\tLogToConsoleError(\"SecItemImport() failed to import public key with status code: %{public}i\",\n\t\t  operationStatus);\n}\n\n#pragma mark -\n#pragma mark User License File Information\n\nNSString * _Nullable TLOLicenseManagerLicenseOwnerName(void)\n{\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary[TLOLicenseManagerLicenseDictionaryKeyOwnerName];\n}\n\nNSString * _Nullable TLOLicenseManagerLicenseOwnerContactAddress(void)\n{\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary[TLOLicenseManagerLicenseDictionaryKeyOwnerContactAddress];\n}\n\nNSString * _Nullable TLOLicenseManagerLicenseKey(void)\n{\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary[TLOLicenseManagerLicenseDictionaryKeyLicenseKey];\n}\n\nNSUInteger TLOLicenseManagerLicenseGeneration(void)\n{\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\tif (licenseDictionary == nil) {\n\t\treturn 0;\n\t}\n\n\treturn [licenseDictionary unsignedIntegerForKey:TLOLicenseManagerLicenseDictionaryKeyGeneration];\n}\n\nNSString * _Nullable TLOLicenseManagerLicenseCreationDate(void)\n{\n\tNSDictionary *licenseDictionary = TLOLicenseManagerLicenseDictionary();\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary[TLOLicenseManagerLicenseDictionaryKeyCreationDate];\n}\n\nNSString * _Nullable TLOLicenseManagerLicenseCreationDateFormatted(void)\n{\n\tNSString *creationDateString = TLOLicenseManagerLicenseCreationDate();\n\n\tif (creationDateString == nil) {\n\t\treturn nil;\n\t}\n\n\tNSDateFormatter *dateFormatter = [NSDateFormatter new];\n\n\tdateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@\"en_US_POSIX\"];\n\n\tdateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@\"UTC\"];\n\n\tdateFormatter.dateFormat = @\"yyyy-MM-dd HH:mm:ss\";\n\n\tNSDate *creationDate = [dateFormatter dateFromString:creationDateString];\n\n\tif (creationDate == nil) {\n\t\treturn creationDateString;\n\t}\n\n\tdateFormatter.dateFormat = nil;\n\n\tdateFormatter.doesRelativeDateFormatting = YES;\n\n\tdateFormatter.dateStyle = NSDateFormatterLongStyle;\n\tdateFormatter.timeStyle = NSDateFormatterNoStyle;\n\n\treturn [dateFormatter stringFromDate:creationDate];\n}\n\n#pragma mark -\n#pragma mark Authorization\n\nNSString * TLOLicenseManagerAuthorizationCode(void)\n{\n\tNSString *code = [[NSUserDefaults standardUserDefaults] stringForKey:@\"TLOLicenseManagerAuthorizationCode\"];\n\n\tif (code == nil) {\n\t\tcode = @\"\";\n\t}\n\n\treturn code;\n}\n\n#pragma mark -\n#pragma mark Blacklist\n\nvoid TLOLicenseManagerDeleteLicenseFileIfBlacklisted(void)\n{\n\tNSString *licenseKey = TLOLicenseManagerLicenseKey();\n\n\tif (licenseKey == nil) {\n\t\treturn;\n\t}\n\n\tif (TLOLicenseManagerLicenseKeyBlacklisted(licenseKey) == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleInfo(\"License key '%{private}@' is blacklisted\", licenseKey);\n\n\tTLOLicenseManagerDeleteLicenseFile();\n}\n\nBOOL TLOLicenseManagerLicenseKeyBlacklisted(NSString *licenseKey)\n{\n\tNSCParameterAssert(licenseKey != nil);\n\n\tNSArray<NSString *> *blacklistedLicenseKeys = nil;\n\n\tif (blacklistedLicenseKeys == nil) {\n\t\tblacklistedLicenseKeys = @[\n\t\t\t@\"mushy-argyle-oryx-428112186934176870777339608\",\n\t\t\t@\"wicked-plaid-weasel-0681043544455415517323623\",\n\t\t\t@\"juicy-cyan-toad-72508217265703758416002094229\",\n\t\t\t@\"cheerful-turquoise-zebra-81864329409734131515\",\n\t\t\t@\"many-wavy-fly-7043700524134077492967431288170\",\n\t\t\t@\"helpful-jade-quelea-7403506199409693779877124\",\n\t\t\t@\"obnoxious-onyx-bear-9755065646001620521415702\",\n\t\t];\n\t}\n\n\treturn [blacklistedLicenseKeys containsObject:licenseKey];\n}\n\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/License Manager/Standalone/TLOLicenseManagerDownloader.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TDCAlert.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLicenseManagerDownloaderPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* URLs for performing certain actions with license keys. */\nNSString * const TLOLicenseManagerDownloaderLicenseAPIActivationURL\t\t\t\t\t\t= @\"https://licensing.textualapp.com/activateLicense.cs\";\nNSString * const TLOLicenseManagerDownloaderLicenseAPISendLostLicenseURL\t\t\t\t= @\"https://licensing.textualapp.com/sendLostLicense.cs\";\nNSString * const TLOLicenseManagerDownloaderLicenseAPIMigrateAppStoreURL\t\t\t\t= @\"https://licensing.textualapp.com/convertReceiptToLicense.cs\";\nNSString * const TLOLicenseManagerDownloaderLicenseAPILicenseUpgradeEligibilityURL\t\t= @\"https://licensing.textualapp.com/upgradeEligibility.cs\";\nNSString * const TLOLicenseManagerDownloaderLicenseAPIReceiptUpgradeEligibilityURL\t\t= @\"https://licensing.textualapp.com/upgradeEligibilityForReceipt.cs\";\n\n/* The license API throttles requests to prevent abuse. The following HTTP status \n code will inform Textual if it the license API has been overwhelmed. */\nNSUInteger const TLOLicenseManagerDownloaderRequestHTTPStatusSuccess = 200; // OK\nNSUInteger const TLOLicenseManagerDownloaderRequestHTTPStatusServiceIsBusy = 429; // Service is Busy\nNSUInteger const TLOLicenseManagerDownloaderRequestHTTPStatusTryAgainLater = 503; // Service Unavailable\n\n/* The following constants note status codes that may be returned part of the \n contents of a license API response body. This is not a complete list. */\nNSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeSuccess = 0;\nNSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeGenericError = 2000000;\nNSUInteger const TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy = 2000001;\n\n/* Private header */\ntypedef void (^TLOLicenseManagerDownloaderConnectionCompletionBlock)(TLOLicenseManagerDownloaderRequestType requestType, NSURLResponse * _Nullable response, NSData * _Nullable data);\n\n@interface TLOLicenseManagerDownloaderConnection : NSObject <NSURLConnectionDelegate>\n@property (nonatomic, weak) TLOLicenseManagerDownloader *delegate; // To be set by caller\n@property (nonatomic, assign) TLOLicenseManagerDownloaderRequestType requestType; // To be set by caller\n@property (nonatomic, copy) NSDictionary<NSString *, id> *requestContextInfo; // Information set by caller such as license key or e-mail address\n@property (nonatomic, strong) NSURLSessionTask *sessionTask;\n\n- (void)performRequest:(TLOLicenseManagerDownloaderConnectionCompletionBlock)completionBlock;\n\n- (void)cancelRequest;\n@end\n\n@interface TLOLicenseManagerDownloader ()\n@property (nonatomic, strong, nullable) TLOLicenseManagerDownloaderConnection *activeConnection;\n@end\n\n#define _connectionTimeoutInterval\t\t\t30.0\n\n@implementation TLOLicenseManagerDownloader\n\n#pragma mark -\n#pragma mark Public Interface\n\n- (void)activateLicense:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tNSDictionary *contextInfo = @{@\"licenseKey\" : licenseKey};\n\n\t[self performRequestType:TLOLicenseManagerDownloaderRequestTypeActivation\n\t\t\t\t\t context:contextInfo];\n}\n\n- (void)deactivateLicense\n{\n\tBOOL operationResult = self.actionBlock(TLOLicenseManagerDownloaderRequestStatusCodeSuccess, nil);\n\n\tif (self.completionBlock) {\n\t\tself.completionBlock(operationResult, TLOLicenseManagerDownloaderRequestStatusCodeSuccess, nil);\n\t}\n}\n\n- (void)checkUpgradeEligibilityOfLicense:(NSString *)licenseKey\n{\n\tNSParameterAssert(licenseKey != nil);\n\n\tNSDictionary *contextInfo = @{@\"licenseKey\" : licenseKey};\n\n\t[self performRequestType:TLOLicenseManagerDownloaderRequestTypeLicenseUpgradeEligibility\n\t\t\t\t\t context:contextInfo];\n}\n\n- (void)checkUpgradeEligibilityOfReceipt:(NSString *)receiptData\n{\n\tNSParameterAssert(receiptData != nil);\n\n\tNSString *macAddress = [XRSystemInformation formattedEthernetMacAddress];\n\n\tNSParameterAssert(macAddress != nil);\n\n\tNSDictionary *contextInfo = @{\n\t\t@\"receiptData\" : receiptData,\n\t\t@\"licenseOwnerMacAddress\" : macAddress\n\t};\n\n\t[self performRequestType:TLOLicenseManagerDownloaderRequestTypeReceiptUpgradeEligibility\n\t\t\t\t\t context:contextInfo];\n}\n\n- (void)requestLostLicenseKeyForContactAddress:(NSString *)contactAddress\n{\n\tNSParameterAssert(contactAddress != nil);\n\n\tNSDictionary *contextInfo = @{@\"licenseOwnerContactAddress\" : contactAddress};\n\n\t[self performRequestType:TLOLicenseManagerDownloaderRequestTypeSendLostLicense\n\t\t\t\t\t context:contextInfo];\n}\n\n- (void)migrateMacAppStorePurchase:(NSString *)receiptData licenseOwnerName:(NSString *)licenseOwnerName licenseOwnerContactAddress:(NSString *)licenseOwnerContactAddress\n{\n\tNSParameterAssert(receiptData != nil);\n\tNSParameterAssert(licenseOwnerName != nil);\n\tNSParameterAssert(licenseOwnerContactAddress != nil);\n\n\tNSString *macAddress = [XRSystemInformation formattedEthernetMacAddress];\n\n\tNSParameterAssert(macAddress != nil);\n\n\tNSDictionary *contextInfo = @{\n\t\t@\"receiptData\" : receiptData,\n\t\t@\"licenseOwnerName\"\t: licenseOwnerName,\n\t\t@\"licenseOwnerContactAddress\" : licenseOwnerContactAddress,\n\t\t@\"licenseOwnerMacAddress\" : macAddress\n\t};\n\n\t[self performRequestType:TLOLicenseManagerDownloaderRequestTypeMigrateAppStore\n\t\t\t\t\t context:contextInfo];\n}\n\n- (void)performRequestType:(TLOLicenseManagerDownloaderRequestType)requestType context:(NSDictionary<NSString *, id> *)requestContext\n{\n\tNSParameterAssert(requestContext != nil);\n\n\tif ( self.activeConnection != nil) {\n\t\t[self.activeConnection cancelRequest];\n\t}\n\n\tTLOLicenseManagerDownloaderConnection *connectionObject = [TLOLicenseManagerDownloaderConnection new];\n\n\tconnectionObject.delegate = self;\n\n\tconnectionObject.requestContextInfo = requestContext;\n\n\tconnectionObject.requestType = requestType;\n\n\t__weak TLOLicenseManagerDownloader *weakSelf = self;\n\n\t[connectionObject performRequest:^(TLOLicenseManagerDownloaderRequestType requestType, NSURLResponse *response, NSData *data) {\n\t\t/* Connection uses NSURLSession which is a background task. */\n\t\t/* The result of processing the response will update the UI\n\t\t which must always take place on the main thread. */\n\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t[weakSelf processResponse:response forRequestType:requestType contents:data];\n\t\t});\n\n\t\tweakSelf.activeConnection = nil;\n\t}];\n\n\tself.activeConnection = connectionObject;\n}\n\n- (void)cancelRequest\n{\n\tif (self.activeConnection == nil) {\n\t\treturn;\n\t}\n\n\t[self.activeConnection cancelRequest];\n\n\tself.activeConnection = nil;\n\n\tself.actionBlock = nil;\n\tself.errorBlock = nil;\n\tself.completionBlock = nil;\n}\n\n- (void)processResponse:(nullable NSURLResponse *)response forRequestType:(TLOLicenseManagerDownloaderRequestType)requestType contents:(nullable NSData *)responseContents\n{\n\t/* We assume the response failed until proven otherwise. */\n\tNSUInteger responseStatusCode = TLOLicenseManagerDownloaderRequestHTTPStatusTryAgainLater;\n\n\tif ([response isKindOfClass:[NSHTTPURLResponse class]]) {\n\t\tresponseStatusCode = ((NSHTTPURLResponse *)response).statusCode;\n\t}\n\n\t[self processResponseForRequestType:requestType\n\t\t\t\t\t\t httpStatusCode:responseStatusCode\n\t\t\t\t\t\t\t   contents:responseContents];\n}\n\n- (void)processResponseForRequestType:(TLOLicenseManagerDownloaderRequestType)requestType httpStatusCode:(NSUInteger)responseStatusCode contents:(nullable NSData *)responseContents\n{\n\t/* The license API returns content as property lists, including errors.\n\t This method will try to convert the returned contents into an NSDictionary\n\t (assuming its a valid property list). If that fails, then the method\n\t shows generic failure reason and logs to the console that the contents\n\t could not parsed. */\n\n\t/* Define defaults */\n\tid propertyList = nil;\n\n\t__block NSUInteger apiStatusCode = TLOLicenseManagerDownloaderRequestStatusCodeGenericError;\n\n\tif (responseStatusCode == TLOLicenseManagerDownloaderRequestHTTPStatusServiceIsBusy) {\n\t\tapiStatusCode = TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy;\n\t}\n\n\t__block id apiStatusContext = nil;\n\n\t/* Helper blocks */\n\tvoid (^performCompletionBlock)(BOOL) = ^(BOOL success)\n\t{\n\t\tif (self.completionBlock) {\n\t\t\tself.completionBlock(success, apiStatusCode, apiStatusContext);\n\t\t}\n\t};\n\n\tvoid (^presentError)(void) = ^(void)\n\t{\n\t\tif (\n\t\t\t/* Perform error block if it was not performed\n\t\t\t by some other condition presented below. */\n\t\t\t(self.errorBlock == nil ||\n\t\t\t self.errorBlock(apiStatusCode, apiStatusContext) == NO) &&\n\n\t\t\t/* Do we even present an error? */\n\t\t\tself.isSilentOnFailure == NO)\n\t\t{\n\t\t\t[self presentTryAgainLaterErrorDialog];\n\t\t}\n\n\t\tperformCompletionBlock(NO);\n\t};\n\n\tvoid (^presentErrorUnconditionally)(void) = ^(void)\n\t{\n\t\t[self presentTryAgainLaterErrorDialog];\n\n\t\tperformCompletionBlock(NO);\n\t};\n\n\t/* Convert contents into a dictionary */\n\tif (responseContents) {\n\t\tNSError *propertyListReadError = nil;\n\n\t\tpropertyList = [NSPropertyListSerialization propertyListWithData:responseContents\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t options:NSPropertyListImmutable\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  format:NULL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&propertyListReadError];\n\n\t\tif (propertyList == nil || [propertyList isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\tif (propertyListReadError) {\n\t\t\t\tLogToConsoleError(\"Failed to convert contents of request into dictionary. Error: %{public}@\",\n\t\t\t\t\t  propertyListReadError.localizedDescription);\n\t\t\t}\n\t\t}\n\t}\n\n\tid l_statusCode = propertyList[@\"Status Code\"];\n\n\tif (l_statusCode == nil || [l_statusCode isKindOfClass:[NSNumber class]] == NO) {\n\t\tLogToConsoleError(\"'Status Code' is nil or not of kind 'NSNumber'\");\n\n\t\treturn presentError();\n\t}\n\n\tapiStatusCode = [l_statusCode unsignedIntegerValue];\n\n\tapiStatusContext = propertyList[@\"Status Context\"];\n\n\t/* Process contents */\n\tif (responseStatusCode == TLOLicenseManagerDownloaderRequestHTTPStatusSuccess)\n\t{\n\t\t/* Process successful results */\n\t\tif (requestType == TLOLicenseManagerDownloaderRequestTypeActivation && apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeSuccess)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSData class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' is nil or not of kind 'NSData'\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.actionBlock != nil && self.actionBlock(apiStatusCode, apiStatusContext) == NO) {\n\t\t\t\tLogToConsoleError(\"Failed to write user license file contents\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.isSilentOnSuccess == NO) {\n\t\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[k39-7l]\")\n\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[jbs-64]\")\n\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\t\talternateButton:nil];\n\t\t\t}\n\n\t\t\treturn performCompletionBlock(YES);\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeSendLostLicense && apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeSuccess)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' is nil or not of kind 'NSDictionary'\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.actionBlock != nil && self.actionBlock(apiStatusCode, apiStatusContext) == NO) {\n\t\t\t\tLogToConsoleError(\"Action blocked returned error\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tNSString *licenseOwnerContactAddress = apiStatusContext[@\"licenseOwnerContactAddress\"];\n\n\t\t\tif (licenseOwnerContactAddress.length == 0) {\n\t\t\t\tLogToConsoleError(\"'licenseOwnerContactAddress' is nil or of zero length\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.isSilentOnSuccess == NO) {\n\t\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[fxj-s6]\", licenseOwnerContactAddress)\n\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[m4q-ul]\", licenseOwnerContactAddress)\n\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\t\talternateButton:nil];\n\t\t\t}\n\n\t\t\treturn performCompletionBlock(YES);\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeSuccess)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' is nil or not of kind 'NSDictionary'\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.actionBlock != nil && self.actionBlock(apiStatusCode, apiStatusContext) == NO) {\n\t\t\t\tLogToConsoleError(\"Action blocked returned error\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tNSString *licenseOwnerContactAddress = apiStatusContext[@\"licenseOwnerContactAddress\"];\n\n\t\t\tif (licenseOwnerContactAddress.length == 0) {\n\t\t\t\tLogToConsoleError(\"'licenseOwnerContactAddress' is nil or of zero length\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.isSilentOnSuccess == NO) {\n\t\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[yxk-ej]\", licenseOwnerContactAddress)\n\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[vxq-oa]\", licenseOwnerContactAddress)\n\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\t\talternateButton:nil];\n\t\t\t}\n\n\t\t\treturn performCompletionBlock(YES);\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeLicenseUpgradeEligibility && apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeSuccess)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' is nil or not of kind 'NSDictionary'\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.actionBlock != nil) {\n\t\t\t\t(void)self.actionBlock(apiStatusCode, apiStatusContext);\n\t\t\t}\n\n\t\t\treturn performCompletionBlock(YES);\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeReceiptUpgradeEligibility && apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeSuccess)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' is nil or not of kind 'NSDictionary'\");\n\n\t\t\t\treturn presentError();\n\t\t\t}\n\n\t\t\tif (self.actionBlock != nil) {\n\t\t\t\t(void)self.actionBlock(apiStatusCode, apiStatusContext);\n\t\t\t}\n\n\t\t\treturn performCompletionBlock(YES);\n\t\t}\n\t}\n\telse // TLOLicenseManagerDownloaderRequestStatusCodeSuccess\n\t{\n\t\tif ((self.errorBlock != nil &&\n\t\t\t self.errorBlock(apiStatusCode, apiStatusContext)) ||\n\t\t\tself.isSilentOnFailure)\n\t\t{\n\t\t\tif (self.completionBlock) {\n\t\t\t\tself.completionBlock(NO, apiStatusCode, apiStatusContext);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Errors related to license activation. */\n\t\tBOOL presentError = NO;\n\n\t\tif (apiStatusCode == TLOLicenseManagerDownloaderRequestStatusCodeServiceIsBusy)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[fvx-90]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[13u-4p]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeActivation && apiStatusCode == 6500000)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[wc7-mn]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[fg6-gf]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeActivation && apiStatusCode == 6500001)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' kind is not of 'NSDictionary'\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tNSString *licenseKey = apiStatusContext[@\"licenseKey\"];\n\n\t\t\tif (licenseKey.length == 0) {\n\t\t\t\tLogToConsoleError(\"'licenseKey' is nil or of zero length\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tBOOL userResponse = [TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[w1n-n0]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[u8h-qv]\", licenseKey.prettyLicenseKey)\n\t\t\t\t\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\t\t\t\t\t\talternateButton:TXTLS(@\"TLOLicenseManager[vgp-j6]\")];\n\n\t\t\tif (userResponse == NO) { // NO = alternate button\n\t\t\t\t[self contactSupport];\n\t\t\t}\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeActivation && apiStatusCode == 6500002)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' kind is not of 'NSDictionary'\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tNSString *licenseKey = apiStatusContext[@\"licenseKey\"];\n\n\t\t\tif (licenseKey.length == 0) {\n\t\t\t\tLogToConsoleError(\"'licenseKey' is nil or of zero length\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tNSInteger licenseKeyActivationLimit = [apiStatusContext integerForKey:@\"licenseKeyActivationLimit\"];\n\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[6aa-ow]\", licenseKeyActivationLimit)\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[o66-ox]\", licenseKey.prettyLicenseKey)\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\n\t\t/* Errors related to lost license recovery. */\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeSendLostLicense && apiStatusCode == 6400000)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[dio-y9]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[ocm-03]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeSendLostLicense && apiStatusCode == 6400001)\n\t\t{\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' kind is not of 'NSDictionary'\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tNSString *originalInput = apiStatusContext[@\"originalInput\"];\n\n\t\t\tif (originalInput.length == 0) {\n\t\t\t\tLogToConsoleError(\"'originalInput' is nil or of zero length\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[6zh-jr]\", originalInput)\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[r87-jw]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\n\t\t/* Error messages related to Mac App Store migration. */\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == 6600002)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[bu4-zk]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[ztd-5y]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == 6600003)\n\t\t{\n\t\t\t/* We do not present a custom dialog for this error, but we still log\n\t\t\t the contents of the context to the console to help diagnose issues. */\n\t\t\tif (apiStatusContext == nil || [apiStatusContext isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\t\tLogToConsoleError(\"'Status Context' kind is not of 'NSDictionary'\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tNSString *errorMessage = apiStatusContext[@\"Error Message\"];\n\n\t\t\tif (errorMessage.length == 0) {\n\t\t\t\tLogToConsoleError(\"'errorMessage' is nil or of zero length\");\n\n\t\t\t\treturn presentErrorUnconditionally();\n\t\t\t}\n\n\t\t\tLogToConsoleError(\"Receipt validation failed:\\n%{public}@\", errorMessage);\n\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[ujo-cd]\", errorMessage)\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[p9s-ak]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == 6600004)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[36y-49]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[enb-hw]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == 6600006)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[do9-8x]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[f49-rk]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse if (requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore && apiStatusCode == 6600007)\n\t\t{\n\t\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[4n2-ps]\")\n\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[t28-j9]\")\n\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpresentError = YES;\n\t\t}\n\n\t\t/* presentError defaults to NO because all conditions are caught above\n\t\t except those that may be added in future versions of the API not yet\n\t\t supported by this code. */\n\t\tif (presentError) {\n\t\t\tpresentErrorUnconditionally();\n\t\t} else {\n\t\t\tperformCompletionBlock(NO);\n\t\t}\n\t} // TLOLicenseManagerDownloaderRequestStatusCodeSuccess\n}\n\n- (void)presentTryAgainLaterErrorDialog\n{\n\tBOOL userResponse = [TDCAlert modalAlertWithMessage:TXTLS(@\"TLOLicenseManager[1cv-0v]\")\n\t\t\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"TLOLicenseManager[nhh-ts]\")\n\t\t\t\t\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\t\t\t\t\talternateButton:TXTLS(@\"TLOLicenseManager[bqw-cv]\")];\n\n\tif (userResponse == NO) { // NO = alternate button\n\t\t[self contactSupport];\n\t}\n}\n\n- (void)contactSupport\n{\n\t[menuController() contactSupport:nil];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Connection Assistant\n\n@implementation TLOLicenseManagerDownloaderConnection\n\n- (NSURL *)requestURL\n{\n\tNSString *requestURLString = nil;\n\n\tif (self.requestType == TLOLicenseManagerDownloaderRequestTypeActivation) {\n\t\trequestURLString = TLOLicenseManagerDownloaderLicenseAPIActivationURL;\n\t} else if (self.requestType == TLOLicenseManagerDownloaderRequestTypeSendLostLicense) {\n\t\trequestURLString = TLOLicenseManagerDownloaderLicenseAPISendLostLicenseURL;\n\t} else if (self.requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore) {\n\t\trequestURLString = TLOLicenseManagerDownloaderLicenseAPIMigrateAppStoreURL;\n\t} else if (self.requestType == TLOLicenseManagerDownloaderRequestTypeLicenseUpgradeEligibility) {\n\t\trequestURLString = TLOLicenseManagerDownloaderLicenseAPILicenseUpgradeEligibilityURL;\n\t} else if (self.requestType == TLOLicenseManagerDownloaderRequestTypeReceiptUpgradeEligibility) {\n\t\trequestURLString = TLOLicenseManagerDownloaderLicenseAPIReceiptUpgradeEligibilityURL;\n\t}\n\n\treturn [NSURL URLWithString:requestURLString];\n}\n\n- (NSString *)encodedRequestContextValue:(NSString *)contextKey\n{\n\tNSParameterAssert(contextKey != nil);\n\n\tNSString *contextValue = self.requestContextInfo[contextKey];\n\n\treturn contextValue.percentEncodedString;\n}\n\n- (BOOL)populateRequestPostData:(NSMutableURLRequest *)connectionRequest\n{\n\tNSParameterAssert(connectionRequest != nil);\n\n\t/* Post parameter(s) defined by this method are subject to change at\n\t any time because obviously, the license API is not public interface */\n\n\t/* Post data is sent as form values with key/value pairs. */\n\tNSString *currentUserLanguage = [NSLocale currentLocale].localeIdentifier;\n\n\tNSString *applicationVersion = [TPCApplicationInfo applicationVersion].percentEncodedString;\n\n\tNSString *authorization = TLOLicenseManagerAuthorizationCode();\n\n\tNSString *requestBodyString = nil;\n\n\tif (self.requestType == TLOLicenseManagerDownloaderRequestTypeActivation)\n\t{\n\t\tNSString *encodedContextInfo = [self encodedRequestContextValue:@\"licenseKey\"];\n\n\t\trequestBodyString = [NSString stringWithFormat:@\"licenseKey=%@&lang=%@&version=%@&authorization=%@\",\n\t\t\t\t\t\t\t encodedContextInfo, currentUserLanguage, applicationVersion, authorization];\n\t}\n\telse if (self.requestType == TLOLicenseManagerDownloaderRequestTypeSendLostLicense)\n\t{\n\t\tNSString *encodedContextInfo = [self encodedRequestContextValue:@\"licenseOwnerContactAddress\"];\n\n\t\trequestBodyString = [NSString stringWithFormat:@\"licenseOwnerContactAddress=%@&lang=%@&version=%@&authorization=%@\",\n\t\t\t\t encodedContextInfo, currentUserLanguage, applicationVersion, authorization];\n\t}\n\telse if (self.requestType == TLOLicenseManagerDownloaderRequestTypeMigrateAppStore)\n\t{\n\t\tNSString *receiptData = [self encodedRequestContextValue:@\"receiptData\"];\n\t\tNSString *licenseOwnerName = [self encodedRequestContextValue:@\"licenseOwnerName\"];\n\t\tNSString *licenseOwnerContactAddress = [self encodedRequestContextValue:@\"licenseOwnerContactAddress\"];\n\t\tNSString *licenseOwnerMacAddress = [self encodedRequestContextValue:@\"licenseOwnerMacAddress\"];\n\n\t\trequestBodyString =\n\t\t[NSString stringWithFormat:@\"receiptData=%@&licenseOwnerMacAddress=%@&licenseOwnerContactAddress=%@&licenseOwnerName=%@&lang=%@&version=%@&authorization=%@\",\n\t\t\t\treceiptData, licenseOwnerMacAddress, licenseOwnerContactAddress, licenseOwnerName, currentUserLanguage, applicationVersion, authorization];\n\t}\n\telse if (self.requestType == TLOLicenseManagerDownloaderRequestTypeLicenseUpgradeEligibility)\n\t{\n\t\tNSString *encodedContextInfo = [self encodedRequestContextValue:@\"licenseKey\"];\n\n\t\trequestBodyString = [NSString stringWithFormat:@\"licenseKey=%@&lang=%@&version=%@&authorization=%@\",\n\t\t\t\t encodedContextInfo, currentUserLanguage, applicationVersion, authorization];\n\t}\n\telse if (self.requestType == TLOLicenseManagerDownloaderRequestTypeReceiptUpgradeEligibility)\n\t{\n\t\tNSString *receiptData = [self encodedRequestContextValue:@\"receiptData\"];\n\t\tNSString *licenseOwnerMacAddress = [self encodedRequestContextValue:@\"licenseOwnerMacAddress\"];\n\n\t\trequestBodyString = [NSString stringWithFormat:@\"receiptData=%@&licenseOwnerMacAddress=%@&lang=%@&version=%@&authorization=%@\",\n\t\t\t\t receiptData, licenseOwnerMacAddress, currentUserLanguage, applicationVersion, authorization];\n\t}\n\n\tif (requestBodyString == nil) {\n\t\treturn NO;\n\t}\n\n\tNSData *requestBodyData = [requestBodyString dataUsingEncoding:NSASCIIStringEncoding];\n\n\tconnectionRequest.HTTPMethod = @\"POST\";\n\n\t[connectionRequest setValue:@\"application/x-www-form-urlencoded\" forHTTPHeaderField:@\"Content-Type\"];\n\n\tconnectionRequest.HTTPBody = requestBodyData;\n\n\treturn YES;\n}\n\n- (void)dealloc\n{\n\tself.delegate = nil;\n}\n\n- (void)cancelRequest\n{\n\tif ( self.sessionTask) {\n\t\t[self.sessionTask cancel];\n\t}\n}\n\n- (void)performRequest:(TLOLicenseManagerDownloaderConnectionCompletionBlock)completionBlock\n{\n\t/* Setup request including HTTP POST data. Return NO on failure */\n\tNSURL *requestURL = [self requestURL];\n\n\tif (requestURL == nil) {\n\t\treturn;\n\t}\n\n\tNSMutableURLRequest *baseRequest = [NSMutableURLRequest requestWithURL:requestURL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   cachePolicy:NSURLRequestReloadIgnoringCacheData\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   timeoutInterval:_connectionTimeoutInterval];\n\n\tif ([self populateRequestPostData:baseRequest] == NO) {\n\t\treturn;\n\t}\n\n\t/* Create the connection and start it */\n\tTLOLicenseManagerDownloaderRequestType requestType = self.requestType;\n\n\t__weak TLOLicenseManagerDownloaderConnection *weakSelf = self;\n\n\tNSURLSession *session = [NSURLSession sharedSession];\n\n\tNSURLSessionTask *task = [session dataTaskWithRequest:baseRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)\n\t{\n\t\tif (data == nil) {\n\t\t\tif (error) {\n\t\t\t\tLogToConsoleError(\"Request failed with error: %{public}@\",\n\t\t\t\t\terror.localizedDescription);\n\t\t\t}\n\n\t\t\tcompletionBlock(requestType, nil, nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\tcompletionBlock(requestType, response, data);\n\n\t\tweakSelf.sessionTask = nil;\n\t}];\n\n\t[task resume];\n\n\tself.sessionTask = task;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/License Manager/Standalone/TLOLicenseManagerLastGen.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPathInfo.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLOLicenseManagerLastGenPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n@implementation TLOLicenseManagerLastGen\n\n#pragma mark -\n#pragma mark Public Interface\n\n+ (nullable NSString *)licenseKey\n{\n\tNSDictionary *licenseDictionary = [self lastGenLicenseDictionary];\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self lastGenLicenseKeyWithLicenseDictionary:licenseDictionary];\n}\n\n+ (nullable NSString *)licenseKeyForLicenseContents:(NSData *)licenseContents\n{\n\tNSParameterAssert(licenseContents != nil);\n\n\tNSDictionary *licenseDictionary = [self lastGenLicenseDictionaryWithData:licenseContents];\n\n\tif (licenseDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *licenseKey = [self lastGenLicenseKeyWithLicenseDictionary:licenseDictionary];\n\n\treturn licenseKey;\n}\n\n#pragma mark -\n#pragma mark Public Interface\n\n+ (nullable NSString *)lastGenLicenseKeyWithLicenseDictionary:(NSDictionary<NSString *, id> *)licenseDictionary\n{\n\tNSParameterAssert(licenseDictionary != nil);\n\n\t/* The integrity of the file and whether it is properly signed does not\n\t matter for this class. We are only interested in whether the dictionary\n\t we have is last gen and whether it has a valid license key. If both are\n\t true, then we can advise user that they need to upgrade. Nothing more. */\n\tNSString *licenseKey = licenseDictionary[@\"licenseKey\"];\n\n\tif (TLOLicenseManagerLicenseKeyIsValid(licenseKey) == NO) {\n\t\treturn nil;\n\t}\n\n\t/* Last gen license dictionary did not have a license generation value. */\n\t/* If that is not present, than consider the dictionary last gen. */\n\tid licenseGeneration = licenseDictionary[@\"licenseGeneration\"];\n\n\tif (licenseGeneration == nil || [licenseGeneration isKindOfClass:[NSNumber class]] == NO) {\n\t\treturn licenseKey;\n\t}\n\n\tif ([licenseGeneration unsignedIntegerValue] != TLOLicenseManagerCurrentLicenseGeneration) {\n\t\treturn licenseKey;\n\t}\n\n\treturn nil;\n}\n\n+ (nullable NSURL *)lastGenLicenseFilePath\n{\n\tNSURL *sourceURL = [TPCPathInfo applicationSupportURL];\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Textual_User_License.plist\"];\n\n\treturn baseURL;\n}\n\n+ (nullable NSData *)lastGenLicenseFileContents\n{\n\tNSURL *licenseFilePath = [self lastGenLicenseFilePath];\n\n\tif (licenseFilePath == nil) {\n\t\tLogToConsoleError(\"Unable to determine the path to retrieve license information from\");\n\n\t\treturn nil;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:licenseFilePath] == NO) {\n\t\treturn nil;\n\t}\n\n\tNSError *readError = nil;\n\n\tNSData *licenseContents = [NSData dataWithContentsOfURL:licenseFilePath options:0 error:&readError];\n\n\tif (licenseContents == nil) {\n\t\tLogToConsoleError(\"Unable to read user license file (%{public}@). Error: %{public}@\", licenseFilePath.standardizedTildePath, readError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\treturn licenseContents;\n}\n\n+ (nullable NSDictionary<NSString *, id> *)lastGenLicenseDictionary\n{\n\tNSData *licenseContents = [self lastGenLicenseFileContents];\n\n\tif (licenseContents == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self lastGenLicenseDictionaryWithData:licenseContents];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)lastGenLicenseDictionaryWithData:(NSData *)licenseContents\n{\n\tNSParameterAssert(licenseContents != nil);\n\n\t/* The contents of the user license is /supposed/ to be a properly formatted\n\t property list as sent from the license system hosted on www.codeux.com */\n\tNSError *readError = nil;\n\n\tid licenseDictionary = [NSPropertyListSerialization propertyListWithData:licenseContents\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t options:NSPropertyListImmutable\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  format:NULL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   error:&readError];\n\n\tif (licenseDictionary == nil || [licenseDictionary isKindOfClass:[NSDictionary class]] == NO) {\n\t\tif (readError) {\n\t\t\tLogToConsoleError(\"Failed to convert contents of user license into dictionary. Error: %{public}@\",\n\t\t\t\t  readError.localizedDescription);\n\t\t}\n\n\t\treturn nil;\n\t}\n\n\treturn licenseDictionary;\n}\n\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOEncryptionManager.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowTitlebarAccessoryViewPrivate.h\"\n#import \"TVCLogRenderer.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCWorld.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n@interface TLOEncryptionManager () <OTRKitDelegate, OTRKitFingerprintManagerDialogDelegate>\n@property (nonatomic, strong, nullable) OTRKitFingerprintManagerDialog *fingerprintManagerDialog;\n@end\n\n@interface TLOEncryptionManagerEncodingDecodingObject : NSObject\n// Properties that should be manipulated to provide context information\n@property (nonatomic, copy, nullable) TLOEncryptionManagerEncodingDecodingCallbackBlock encodingCallback;\n@property (nonatomic, copy, nullable) TLOEncryptionManagerInjectCallbackBlock injectionCallback;\n@property (nonatomic, copy) NSString *messageFrom;\n@property (nonatomic, copy) NSString *messageTo;\n@property (nonatomic, copy) NSString *messageBody; // unencrypted value\n@end\n\n@implementation TLOEncryptionManager\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[self setupEncryptionManager];\n}\n\n- (nullable NSString *)pathToStoreEncryptionSecrets\n{\n\tNSString *sourcePath = [TPCPathInfo groupContainerApplicationSupport];\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *basePath = [sourcePath stringByAppendingPathComponent:@\"/Encryption Components/\"];\n\n\t[TPCPathInfo _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n- (void)setupEncryptionManager\n{\n\tOTRKit *otrKit = [OTRKit sharedInstance];\n\n\totrKit.accountNameSeparator = @\"@\";\n\n\totrKit.delegate = (id)self;\n\n\t[otrKit setupWithDataPath:[self pathToStoreEncryptionSecrets]];\n\n\t[self prepareEncryptionComponentPath:otrKit.fingerprintsPath];\n\t[self prepareEncryptionComponentPath:otrKit.instanceTagsPath];\n\t[self prepareEncryptionComponentPath:otrKit.privateKeyPath];\n\n\tNSURL *componentPathURL = [NSURL fileURLWithPath:otrKit.dataPath isDirectory:YES];\n\n\tNSError *attributesChangeError = nil;\n\n\tif ([componentPathURL setResourceValue:@(YES) forKey:NSURLIsHiddenKey error:&attributesChangeError] == NO) {\n\t\tLogToConsoleError(\"Failed to hide the folder at the path '%{private}@': %{private}@\",\n\t\t\tcomponentPathURL.standardizedTildePath, attributesChangeError.localizedDescription);\n\t}\n\n\t[otrKit setMaximumProtocolSize:[self otrKitProtocolMaximumMessageSize]\n\t\t\t\t\t   forProtocol:[self otrKitProtocol]];\n\n\t[self updatePolicy];\n}\n\n- (void)prepareEncryptionComponentPath:(NSString *)path\n{\n\tNSParameterAssert(path != nil);\n\n\t/* Create the path if it does not already exist. */\n\tif ([RZFileManager() fileExistsAtPath:path] == NO) {\n\t\tNSError *writeError = nil;\n\n\t\tif ([@\"\" writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&writeError] == NO) {\n\t\t\tLogToConsoleError(\"Failed to create base file for encryption component at path: %{private}@\",\n\t\t\t\t  writeError.localizedDescription);\n\t\t}\n\t}\n\n\t/* Files are stored in a location that is accessible to Time Machine\n\t which means we must mark the files to not be backed up. */\n\tNSURL *pathURL = [NSURL fileURLWithPath:path isDirectory:NO];\n\n\tNSError *attributesChangeError = nil;\n\n\tif ([pathURL setResourceValue:@(YES) forKey:NSURLIsExcludedFromBackupKey error:&attributesChangeError] == NO) {\n\t\tLogToConsoleError(\"Failed to exclude the files at the path '%{private}@' from backup: %{private}@\",\n\t\t\tpathURL.standardizedTildePath, attributesChangeError.localizedDescription);\n\t}\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing encryption manager\");\n}\n\n#pragma mark -\n#pragma mark Fingerprint Manager\n\n- (void)presentListOfFingerprints\n{\n\tif (self.fingerprintManagerDialog == nil) {\n\t\tOTRKitFingerprintManagerDialog *dialog = [OTRKitFingerprintManagerDialog new];\n\n\t\tdialog.delegate = (id)self;\n\n\t\tself.fingerprintManagerDialog = dialog;\n\t}\n\n\t[self.fingerprintManagerDialog open:mainWindow()];\n}\n\n#pragma mark -\n#pragma mark Account Name Information\n\n- (NSString *)accountNameForUser:(NSString *)nickname onClient:(IRCClient *)client\n{\n\tNSParameterAssert(nickname != nil);\n\tNSParameterAssert(client != nil);\n\n\treturn [NSString stringWithFormat:@\"%@%@%@\", nickname, [OTRKit sharedInstance].accountNameSeparator, client.uniqueIdentifier];\n}\n\n- (nullable NSString *)nicknameFromAccountName:(NSString *)accountName\n{\n\tNSParameterAssert(accountName != nil);\n\n\tNSString *nickname = [[OTRKit sharedInstance] leftPortionOfAccountName:accountName];\n\n\treturn nickname;\n}\n\n- (nullable IRCClient *)connectionFromAccountName:(NSString *)accountName\n{\n\tNSParameterAssert(accountName != nil);\n\n\tNSString *clientIdentifier = [[OTRKit sharedInstance] rightPortionOfAccountName:accountName];\n\n\treturn [worldController() findClientWithId:clientIdentifier];\n}\n\n#pragma mark -\n#pragma mark Starting Encryption & Stopping Encryption\n\n- (void)beginConversationWith:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\t[self refreshConversationWith:messageTo from:messageFrom presentMessage:TXTLS(@\"OffTheRecord[aii-2q]\")];\n}\n\n- (void)endConversationWith:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tOTRKitMessageState currentState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\n\tif (currentState == OTRKitMessageStateEncrypted) {\n\t\t[[OTRKit sharedInstance] disableEncryptionWithUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\t} else {\n\t\t[self presentErrorMessage:TXTLS(@\"OffTheRecord[g9p-8r]\") withAccountName:messageTo];\n\t}\n}\n\n- (void)refreshConversationWith:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\t[self refreshConversationWith:messageTo from:messageFrom presentMessage:TXTLS(@\"OffTheRecord[f59-3b]\")];\n}\n\n- (void)refreshConversationWith:(NSString *)messageTo from:(NSString *)messageFrom presentMessage:(NSString *)message\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\tNSParameterAssert(message != nil);\n\n\t[self presentMessage:message withAccountName:messageTo];\n\n\tOTRKitMessageState currentState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\n\tif (currentState == OTRKitMessageStateEncrypted) {\n\t\t[[OTRKit sharedInstance] disableEncryptionWithUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\t}\n\n\t[[OTRKit sharedInstance] initiateEncryptionWithUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\taccountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t   protocol:[self otrKitProtocol]\n\t\t\t\t\t\t\t\t\t\t\t asynchronously:YES];\n}\n\n#pragma mark -\n#pragma mark Socialist Millionaire\n\n- (void)authenticateUser:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tOTRKitMessageState currentState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\n\tif (currentState == OTRKitMessageStateEncrypted) {\n\t\t[OTRKitAuthenticationDialog requestAuthenticationForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprotocol:[self otrKitProtocol]];\n\t} else {\n\t\t[self presentErrorMessage:TXTLS(@\"OffTheRecord[jrv-gq]\") withAccountName:messageTo];\n\t}\n}\n\n#pragma mark -\n#pragma mark Encryption & Decryption\n\n- (void)decryptMessage:(NSString *)messageBody from:(NSString *)messageFrom to:(NSString *)messageTo decodingCallback:(nullable TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\tNSParameterAssert(messageBody != nil);\n\n\tTLOEncryptionManagerEncodingDecodingObject *messageObject = [TLOEncryptionManagerEncodingDecodingObject new];\n\n\tmessageObject.messageTo = messageTo;\n\tmessageObject.messageFrom = messageFrom;\n\n\tmessageObject.messageBody = messageBody;\n\n\tmessageObject.encodingCallback = decodingCallback;\n\n\t/* Messages are decoded synchronously because many things incoming\n\t from IRC are never passed through OTRKit. To keep the incoming\n\t queue synchronous, we keep it synchronous here. */\n\t[[OTRKit sharedInstance] decodeMessage:messageBody\n\t\t\t\t\t\t\t\t  username:messageFrom\n\t\t\t\t\t\t\t   accountName:messageTo\n\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]\n\t\t\t\t\t\t\tasynchronously:NO\n\t\t\t\t\t\t\t\t\t   tag:messageObject];\n}\n\n- (void)encryptMessage:(NSString *)messageBody from:(NSString *)messageFrom to:(NSString *)messageTo encodingCallback:(nullable TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback injectionCallback:(nullable TLOEncryptionManagerInjectCallbackBlock)injectionCallback\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\tNSParameterAssert(messageBody != nil);\n\n\tTLOEncryptionManagerEncodingDecodingObject *messageObject = [TLOEncryptionManagerEncodingDecodingObject new];\n\n\tmessageObject.messageTo = messageTo;\n\tmessageObject.messageFrom = messageFrom;\n\n\tmessageObject.messageBody = messageBody;\n\n\tmessageObject.encodingCallback = encodingCallback;\n\n\tmessageObject.injectionCallback = injectionCallback;\n\n\t[[OTRKit sharedInstance] encodeMessage:messageBody\n\t\t\t\t\t\t\t\t\t  tlvs:nil\n\t\t\t\t\t\t\t\t  username:messageTo\n\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]\n\t\t\t\t\t\t\tasynchronously:NO\n\t\t\t\t\t\t\t\t\t   tag:messageObject];\n}\n\n#pragma mark -\n#pragma mark Helper Methods\n\n- (OTRKitMessageState)messageStateFor:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tOTRKitMessageState currentState =\n\t\t[[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\tprotocol:[self otrKitProtocol]];\n\n\treturn currentState;\n}\n\n- (BOOL)safeToTransferFile:(NSString *)filename to:(NSString *)messageTo from:(NSString *)messageFrom isIncomingFileTransfer:(BOOL)isIncomingFileTransfer\n{\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tOTRKitMessageState currentState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\n\tif (currentState == OTRKitMessageStateEncrypted) {\n\t\tif (isIncomingFileTransfer) {\n\t\t\tBOOL continueop = [TDCAlert modalAlertWithMessage:TXTLS(@\"OffTheRecord[nuo-8s]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"OffTheRecord[mnw-qt]\", filename)\n\t\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"OffTheRecord[ng0-5q]\")];\n\n\t\t\treturn (continueop == NO);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSString *nickname = [self nicknameFromAccountName:messageTo];\n\n\t\t\tBOOL continueop = [TDCAlert modalAlertWithMessage:TXTLS(@\"OffTheRecord[7he-76]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"OffTheRecord[gcg-tv]\", filename, nickname)\n\t\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"OffTheRecord[0v0-ix]\")];\n\n\t\t\treturn (continueop == NO);\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)updateLockIconButton:(TVCMainWindowTitlebarAccessoryViewLockButton *)button withStateOf:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\tNSParameterAssert(button != nil);\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tOTRKitMessageState currentState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  protocol:[self otrKitProtocol]];\n\n\tif (currentState == OTRKitMessageStateEncrypted) {\n\t\tBOOL hasVerifiedKey = [[OTRKit sharedInstance] activeFingerprintIsVerifiedForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t protocol:[self otrKitProtocol]];\n\n\t\tif (hasVerifiedKey) {\n\t\t\tbutton.title = TXTLS(@\"OffTheRecord[l9n-p9]\");\n\n\t\t\t[button setIconAsLocked];\n\t\t} else {\n\t\t\tbutton.title = TXTLS(@\"OffTheRecord[w34-mg]\");\n\n\t\t\t/* Even though we are encrypted, our icon is still set to unlocked because\n\t\t\t the identity of messageTo still has not been authenticated. */\n\t\t\t[button setIconAsUnlocked];\n\t\t}\n\t} else {\n\t\tbutton.title = TXTLS(@\"OffTheRecord[anu-ky]\");\n\n\t\t[button setIconAsUnlocked];\n\t}\n}\n\n- (void)performBlock:(void (^)(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel))block inRelationToAccountName:(NSString *)accountName\n{\n\t[self performBlock:block inRelationToAccountName:accountName createWindowIfMissing:NO];\n}\n\n- (void)performBlock:(void (^)(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel))block inRelationToAccountName:(NSString *)accountName createWindowIfMissing:(BOOL)createWindowIfMissing\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\tIRCClient *client = [self connectionFromAccountName:accountName];\n\n\t\tif (client == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *nickname = [self nicknameFromAccountName:accountName];\n\n\t\tIRCChannel *channel = nil;\n\n\t\tif (createWindowIfMissing) {\n\t\t\tchannel = [client findChannelOrCreate:nickname isPrivateMessage:YES];\n\t\t} else {\n\t\t\tchannel = [client findChannel:nickname];\n\t\t}\n\n\t\tblock(nickname, client, channel);\n\t});\n}\n\n- (nullable NSString *)localizedStringForEvent:(OTRKitMessageEvent)event\n{\n\tNSString *localeKey = nil;\n\n#define _dv(event, localInt)\t\tcase (event): { localeKey = (localInt); break; }\n\n\tswitch (event) {\n\t\t_dv(OTRKitMessageEventEncryptionRequired,\t\t\t\t@\"jww-e0\")\n\t\t_dv(OTRKitMessageEventEncryptionError,\t\t\t\t\t@\"jvt-fi\")\n\t\t_dv(OTRKitMessageEventConnectionEnded,\t\t\t\t\t@\"c5o-2l\")\n\t\t_dv(OTRKitMessageEventSetupError,\t\t\t\t\t\t@\"uhy-85\")\n\t\t_dv(OTRKitMessageEventMessageReflected,\t\t\t\t\t@\"bl0-5i\")\n\t\t_dv(OTRKitMessageEventMessageResent,\t\t\t\t\t@\"c49-q0\")\n\t\t_dv(OTRKitMessageEventReceivedMessageNotInPrivate,\t\t@\"6v9-w3\")\n\t\t_dv(OTRKitMessageEventReceivedMessageUnreadable,\t\t@\"9if-xp\")\n\t\t_dv(OTRKitMessageEventReceivedMessageMalformed,\t\t\t@\"auo-n0\")\n\t\t_dv(OTRKitMessageEventLogHeartbeatReceived,\t\t\t\t@\"nl1-nf\")\n\t\t_dv(OTRKitMessageEventLogHeartbeatSent,\t\t\t\t\t@\"iwt-9f\")\n\t\t_dv(OTRKitMessageEventReceivedMessageGeneralError,\t\t@\"2zx-p6\")\n\t\t_dv(OTRKitMessageEventReceivedMessageUnencrypted,\t\t@\"1lf-f0\")\n\t\t_dv(OTRKitMessageEventReceivedMessageUnrecognized,\t\t@\"4by-8j\")\n\t\t_dv(OTRKitMessageEventReceivedMessageForOtherInstance,\t@\"c7t-vi\")\n\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n#undef _dv\n\n\tif (localeKey) {\n\t\tlocaleKey = [NSString stringWithFormat:@\"OffTheRecord[%@]\", localeKey];\n\n\t\treturn TXTLS(localeKey);\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)eventIsErroneous:(OTRKitMessageEvent)event\n{\n\tswitch (event) {\n\t\tcase OTRKitMessageEventEncryptionError:\n\t\tcase OTRKitMessageEventReceivedMessageGeneralError:\n\t\tcase OTRKitMessageEventReceivedMessageMalformed:\n\t\tcase OTRKitMessageEventReceivedMessageNotInPrivate:\n\t\tcase OTRKitMessageEventReceivedMessageUnreadable:\n\t\tcase OTRKitMessageEventReceivedMessageUnrecognized:\n\t\tcase OTRKitMessageEventEncryptionRequired:\n\t\t{\n\t\t\treturn YES;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\treturn NO;\n\t\t}\n\t}\n}\n\n- (void)printMessage:(NSString *)message inChannel:(IRCChannel *)channel onClient:(IRCClient *)client\n{\n\t[self printMessage:message inChannel:channel onClient:client escapeMessage:YES];\n}\n\n- (void)printMessage:(NSString *)message inChannel:(IRCChannel *)channel onClient:(IRCClient *)client escapeMessage:(BOOL)escapeMessage\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(client != nil);\n\n\t[client print:message\n\t\t\t   by:nil\n\t\tinChannel:channel\n\t\t   asType:TVCLogLineTypeOffTheRecordEncryptionStatus\n\t\t  command:TVCLogLineDefaultCommandValue\n\tescapeMessage:escapeMessage];\n}\n\n- (void)presentMessage:(NSString *)message withAccountName:(NSString *)accountName\n{\n\t[self presentMessage:message withAccountName:accountName escapeMessage:YES];\n}\n\n- (void)presentMessage:(NSString *)message withAccountName:(NSString *)accountName escapeMessage:(BOOL)escapeMessage\n{\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self printMessage:message inChannel:channel onClient:client escapeMessage:escapeMessage];\n\t} inRelationToAccountName:accountName\n\t\tcreateWindowIfMissing:YES];\n}\n\n- (void)presentErrorMessage:(NSString *)errorMessage withAccountName:(NSString *)accountName\n{\n\t[self presentErrorMessage:errorMessage withAccountName:accountName escapeMessage:YES];\n}\n\n- (void)presentErrorMessage:(NSString *)errorMessage withAccountName:(NSString *)accountName escapeMessage:(BOOL)escapeMessage\n{\n\t[self presentMessage:errorMessage withAccountName:accountName escapeMessage:escapeMessage];\n}\n\n- (void)authenticationStatusChangedForAccountName:(NSString *)accountName isVerified:(BOOL)isVerified\n{\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isVerified) {\n\t\t\t[self printMessage:TXTLS(@\"OffTheRecord[rj0-ys]\", nickname) inChannel:channel onClient:client];\n\t\t} else {\n\t\t\t[self printMessage:TXTLS(@\"OffTheRecord[ufr-mh]\", nickname) inChannel:channel onClient:client];\n\t\t}\n\n\t\t[channel noteEncryptionStateDidChange];\n\t} inRelationToAccountName:accountName];\n}\n\n#pragma mark -\n#pragma mark Off-the-Record Kit Delegate\n\n- (void)updatePolicy\n{\n\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\t[OTRKit sharedInstance].otrPolicy = OTRKitPolicyNever;\n\n\t\treturn;\n\t}\n\n\tif ([TPCPreferences textEncryptionIsRequired]) {\n\t\t[OTRKit sharedInstance].otrPolicy = OTRKitPolicyAlways;\n\t} else if ([TPCPreferences textEncryptionIsOpportunistic]) {\n\t\t[OTRKit sharedInstance].otrPolicy = OTRKitPolicyOpportunistic;\n\t} else {\n\t\t[OTRKit sharedInstance].otrPolicy = OTRKitPolicyManual;\n\t}\n}\n\n- (NSString *)otrKitProtocol\n{\n\treturn @\"prpl-irc\";\n}\n\n- (int)otrKitProtocolMaximumMessageSize\n{\n\treturn 400; // Chosen by fair dice roll.\n}\n\n- (NSString *)maybeInsertProperNegotiationMessage:(NSString *)message\n{\n\tstatic NSRegularExpression *boundryRegex = nil;\n\n\tif (boundryRegex == nil) {\n\t\tNSString *boundryMatch = [NSString stringWithFormat:\n\t\t\t@\"\\\\?OTRv?([0-9]+)\\\\?\\n<b>(.*)</b> has requested an \"\n\t\t\t@\"<a href=\\\"https://otr.cypherpunks.ca/\\\">Off-the-Record \"\n\t\t\t@\"private conversation</a>.  However, you do not have a plugin \"\n\t\t\t@\"to support that.\\nSee <a href=\\\"https://otr.cypherpunks.ca/\\\">\"\n\t\t\t@\"https://otr.cypherpunks.ca/</a> for more information.\"];\n\n\t\tboundryRegex = [NSRegularExpression regularExpressionWithPattern:boundryMatch options:0 error:NULL];\n\t}\n\n\tNSUInteger numberOfMatches = [boundryRegex numberOfMatchesInString:message options:0 range:message.range];\n\n\tif (numberOfMatches == 1) {\n\t\tNSArray *messageComponents = [message componentsSeparatedByString:@\"\\n\"];\n\n\t\treturn [NSString stringWithFormat:@\"%@ %@\", messageComponents[0], TXTLS(@\"OffTheRecord[8hr-8l]\")];\n\t}\n\n\treturn message;\n}\n\n- (void)otrKit:(OTRKit *)otrKit injectMessage:(NSString *)message username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol tag:(nullable id)tag\n{\n\tmessage = [self maybeInsertProperNegotiationMessage:message];\n\n\tif (tag && [tag isKindOfClass:[TLOEncryptionManagerEncodingDecodingObject class]]) {\n\t\tTLOEncryptionManagerEncodingDecodingObject *messageObject = tag;\n\n\t\tif (messageObject.injectionCallback) {\n\t\t\tmessageObject.injectionCallback(message);\n\n\t\t\treturn; // Do not continue after callback block...\n\t\t}\n\t}\n\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\t[client send:@\"PRIVMSG\", nickname, message, nil];\n\t} inRelationToAccountName:username];\n}\n\n- (void)otrKit:(OTRKit *)otrKit encodedMessage:(nullable NSString *)encodedMessage wasEncrypted:(BOOL)wasEncrypted username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol tag:(nullable id)tag error:(nullable NSError *)error\n{\n\tif (tag == nil || [tag isKindOfClass:[TLOEncryptionManagerEncodingDecodingObject class]] == NO) {\n\t\treturn;\n\t}\n\n\tTLOEncryptionManagerEncodingDecodingObject *messageObject = tag;\n\n\tif (messageObject.encodingCallback) {\n\t\tmessageObject.encodingCallback(messageObject.messageBody, wasEncrypted);\n\t}\n}\n\n- (void)otrKit:(OTRKit *)otrKit decodedMessage:(nullable NSString *)decodedMessage wasEncrypted:(BOOL)wasEncrypted tlvs:(NSArray<OTRTLV *> *)tlvs username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol tag:(nullable id)tag\n{\n\tif (decodedMessage == nil) {\n\t\treturn;\n\t}\n\n\tif (tag == nil || [tag isKindOfClass:[TLOEncryptionManagerEncodingDecodingObject class]] == NO) {\n\t\treturn;\n\t}\n\n\tTLOEncryptionManagerEncodingDecodingObject *messageObject = tag;\n\n\tif (messageObject.encodingCallback) {\n\t\tmessageObject.encodingCallback(decodedMessage, wasEncrypted);\n\t}\n}\n\n- (void)otrKit:(OTRKit *)otrKit updateMessageState:(OTRKitMessageState)messageState username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\t/* We do not force create window if it does not exist when updating encryption\n\t status because status changes are only important if one is open. When a new\n\t window is created, it will populate the latest state regardless of delegate. */\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[channel noteEncryptionStateDidChange];\n\t} inRelationToAccountName:username];\n\n\tif (messageState ==  OTRKitMessageStateEncrypted) {\n\t\tBOOL isVerified = [[OTRKit sharedInstance] activeFingerprintIsVerifiedForUsername:username\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  accountName:accountName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t protocol:[self otrKitProtocol]];\n\n\t\tif (isVerified) {\n\t\t\t[self presentMessage:TXTLS(@\"OffTheRecord[r3w-fj]\") withAccountName:username];\n\t\t} else {\n\t\t\t[self presentMessage:TXTLS(@\"OffTheRecord[l49-9y]\") withAccountName:username escapeMessage:NO];\n\t\t}\n\t} else if (messageState == OTRKitMessageStateFinished ||\n\t\t\t   messageState == OTRKitMessageStatePlaintext)\n\t{\n\t\t[self presentMessage:TXTLS(@\"OffTheRecord[m1z-eb]\") withAccountName:username];\n\n\t\t/* When policy is changed to never, all open conversations are\n\t\t closed. Because user probably wont intend to use authentication\n\t\t dialogs without encryption enabled, then let's cancel any that\n\t\t are open for this condition. */\n\t\tif ([TPCPreferences textEncryptionIsEnabled] == NO) {\n\t\t\t[OTRKitAuthenticationDialog cancelRequestForUsername:username\n\t\t\t\t\t\t\t\t\t\t\t\t\t accountName:accountName\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tprotocol:protocol];\n\t\t}\n\t}\n}\n\n- (BOOL)otrKit:(OTRKit *)otrKit isUsernameLoggedIn:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\t__block BOOL userIsActive = NO;\n\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tuserIsActive = channel.isActive;\n\t} inRelationToAccountName:username];\n\n\treturn userIsActive;\n}\n\n- (void)otrKit:(OTRKit *)otrKit showFingerprintConfirmationForTheirHash:(NSString *)theirHash ourHash:(NSString *)ourHash username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\t/* We print this message unescaped to include an anchor in the HTML\n\t\t that the user can click to authenticate the user.\n\t\t We are passing outside input to it, which we do escape. */\n\t\t[self printMessage:TXTLS(@\"OffTheRecord[67n-6j]\",\n\t\t\t\t\t\t\t\t [TVCLogRenderer escapeHTML:nickname],\n\t\t\t\t\t\t\t\t [TVCLogRenderer escapeHTML:theirHash])\n\t\t\t\t inChannel:channel\n\t\t\t\t  onClient:client\n\t\t\t escapeMessage:NO];\n\t}  inRelationToAccountName:username\n\t\t createWindowIfMissing:YES];\n}\n\n- (void)otrKit:(OTRKit *)otrKit handleSMPEvent:(OTRKitSMPEvent)event progress:(double)progress question:(nullable NSString *)question username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol error:(nullable NSError *)error\n{\n\t[OTRKitAuthenticationDialog handleAuthenticationRequest:event progress:progress question:question username:username accountName:accountName protocol:protocol];\n}\n\n- (void)otrKit:(OTRKit *)otrKit handleMessageEvent:(OTRKitMessageEvent)event message:(NSString *)message username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol tag:(nullable id)tag error:(nullable NSError *)error\n{\n\tif (event == OTRKitMessageEventReceivedMessageUnencrypted) {\n\t\t[self otrKit:otrKit decodedMessage:message wasEncrypted:NO tlvs:nil username:username accountName:accountName protocol:protocol tag:tag];\n\n\t\treturn;\n\t}\n\n\tif ([self eventIsErroneous:event]) {\n\t\tNSString *errorMessage = [self localizedStringForEvent:event];\n\n\t\t[self presentErrorMessage:errorMessage withAccountName:username];\n\t}\n}\n\n- (void)otrKit:(OTRKit *)otrKit receivedSymmetricKey:(NSData *)symmetricKey forUse:(NSUInteger)use useData:(NSData *)useData username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\n}\n\n- (void)otrKit:(OTRKit *)otrKit willStartGeneratingPrivateKeyForAccountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\n}\n\n- (void)otrKit:(OTRKit *)otrKit didFinishGeneratingPrivateKeyForAccountName:(NSString *)accountName protocol:(NSString *)protocol error:(nullable NSError *)error\n{\n\n}\n\n- (void)otrKit:(OTRKit *)otrKit fingerprintIsVerifiedStateChangedForUsername:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol verified:(BOOL)verified\n{\n\t[self authenticationStatusChangedForAccountName:username isVerified:verified];\n}\n\n- (void)otrKitFingerprintManagerDialogDidClose:(OTRKitFingerprintManagerDialog *)otrkitFingerprintManager\n{\n\tself.fingerprintManagerDialog = nil;\n}\n\n- (BOOL)otrKit:(OTRKit *)otrKit ignoreMessage:(NSString *)message messageType:(OTRKitMessageType)messageType username:(NSString *)username accountName:(NSString *)accountName protocol:(NSString *)protocol\n{\n\t__block BOOL ignoreMessage = NO;\n\n\t[self performBlock:^(NSString *nickname, IRCClient *client, IRCChannel * _Nullable channel) {\n\t\tif (messageType == OTRKitMessageTypeNotOTR) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityEchoMessage]) {\n\t\t\tignoreMessage = [client nicknameIsMyself:nickname];\n\t\t}\n\t} inRelationToAccountName:username];\n\n\treturn ignoreMessage;\n}\n\n#pragma mark -\n#pragma mark Menu Item Actions\n\n- (BOOL)validateMenuItem:(NSMenuItem *)menuItem withStateOf:(NSString *)messageTo from:(NSString *)messageFrom\n{\n\tNSParameterAssert(menuItem != nil);\n\tNSParameterAssert(messageTo != nil);\n\tNSParameterAssert(messageFrom != nil);\n\n\tNSUInteger menuItemTag = menuItem.tag;\n\n\tif (menuItemTag == MTOTRStatusButtonViewListOfFingerprints) {\n\t\treturn YES;\n\t}\n\n\tOTRKitMessageState currentMessageState = [[OTRKit sharedInstance] messageStateForUsername:messageTo\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  accountName:messageFrom\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t protocol:[self otrKitProtocol]];\n\n\tBOOL messageStateEncrypted = (currentMessageState == OTRKitMessageStateEncrypted);\n\n\tswitch (menuItemTag) {\n\t\tcase MTOTRStatusButtonStartPrivateConversation:\n\t\t{\n\t\t\tmenuItem.hidden = messageStateEncrypted;\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTOTRStatusButtonRefreshPrivateConversation:\n\t\t{\n\t\t\tmenuItem.hidden = (messageStateEncrypted == NO);\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase MTOTRStatusButtonEndPrivateConversation:\n\t\t{\n\t\t\treturn messageStateEncrypted;\n\t\t}\n\t\tcase MTOTRStatusButtonAuthenticateChatPartner:\n\t\t{\n\t\t\treturn messageStateEncrypted;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Dummy Class\n\n@implementation TLOEncryptionManagerEncodingDecodingObject\n@end\n#endif\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOFileLogger.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXGlobalModels.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOTimer.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TVCLogLinePrivate.h\"\n#import \"TLOFileLoggerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* How frequent to display alert for no disk space */\n#define _noSpaceLeftOnDeviceAlertInterval\t\t300 // 5 minutes\n\n/* How long a file handle is allowed to be idle */\n#define _fileHandleIdleLimit\t\t1200 // 20 minutes\n\n/* The frequency by which idle is checked for */\n#define _idleTimerInterval\t\t\t600 // 10 minutes\n\nNSString * const TLOFileLoggerConsoleDirectoryName\t\t\t\t= @\"Console\";\nNSString * const TLOFileLoggerChannelDirectoryName\t\t\t\t= @\"Channels\";\nNSString * const TLOFileLoggerPrivateMessageDirectoryName\t\t= @\"Queries\";\n\nNSString * const TLOFileLoggerUndefinedNicknameFormat\t= @\"<%@%n>\";\nNSString * const TLOFileLoggerActionNicknameFormat\t\t= @\"\\u2022 %n:\";\nNSString * const TLOFileLoggerNoticeNicknameFormat\t\t= @\"-%n-\";\n\nNSString * const TLOFileLoggerISOStandardClockFormat\t\t= @\"[%Y-%m-%dT%H:%M:%S%z]\"; // 2008-07-09T16:13:30+12:00\n\nNSString * const TLOFileLoggerIdleTimerNotification\t\t= @\"TLOFileLoggerIdleTimerNotification\";\n\n@interface TLOFileLogger ()\n@property (nonatomic, weak) IRCClient *client;\n@property (nonatomic, weak) IRCChannel *channel;\n@property (nonatomic, strong, nullable) NSFileHandle *fileHandle;\n@property (nonatomic, copy, readwrite, nullable) NSString *filePath;\n@property (readonly, copy, readonly, nullable) NSString *filePathComputed;\n@property (nonatomic, copy, nullable) NSDate *dateOpened;\n@property (nonatomic, assign) NSTimeInterval lastWriteTime;\n@property (readonly) BOOL fileHandleIdle;\n@property (readonly, class) TLOTimer *idleTimer;\n@end\n\nstatic NSUInteger _numberOfOpenFileHandles = 0;\n\n@implementation TLOFileLogger\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = client;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\tif ((self = [super init])) {\n\t\tself.client = channel.associatedClient;\n\t\tself.channel = channel;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark Plain Text API\n\n- (void)writeLogLine:(TVCLogLine *)logLine\n{\n\tNSParameterAssert(logLine != nil);\n\n\tNSString *stringToWrite = nil;\n\n\tif (self.channel) {\n\t\tstringToWrite = [logLine renderedBodyForTranscriptLogInChannel:self.channel];\n\t} else {\n\t\tstringToWrite = [logLine renderedBodyForTranscriptLog];\n\t}\n\n\t[self writePlainText:stringToWrite];\n}\n\n- (void)writePlainText:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\t[self reopenIfNeeded];\n\n\tif (self.fileHandle == nil) {\n\t\tLogToConsoleError(\"File handle is closed\");\n\n\t\treturn;\n\t}\n\n\tNSString *stringToWrite = [string stringByAppendingString:@\"\\n\"];\n\n\tNSData *dataToWrite = [stringToWrite dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];\n\n\tif (dataToWrite) {\n\t\t@try {\n\t\t\tself.lastWriteTime = [NSDate timeIntervalSince1970];\n\n\t\t\t[self.fileHandle writeData:dataToWrite];\n\t\t}\n\t\t@catch (NSException *exception) {\n\t\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\t\tLogStackTrace();\n\n\t\t\tif ([exception.reason contains:@\"No space left on device\"]) {\n\t\t\t\t[self failWithNoSpaceLeftOnDevice];\n\t\t\t}\n\n\t\t\t[self close];\n\t\t} // @catch\n\t}\n}\n\n#pragma mark -\n#pragma mark File Handle Management\n\n- (void)failWithNoSpaceLeftOnDevice\n{\n\tstatic BOOL alertVisible = NO;\n\n\tif (alertVisible) {\n\t\treturn;\n\t}\n\n\tstatic NSTimeInterval lastFailTime = 0;\n\n\tNSTimeInterval currentTime = [NSDate timeIntervalSince1970];\n\n\tif (lastFailTime > 0) {\n\t\tif ((currentTime - lastFailTime) < _noSpaceLeftOnDeviceAlertInterval) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tlastFailTime = currentTime;\n\n\talertVisible = YES;\n\n\t/* Present alert as non-blocking because there is no need for it to disrupt UI */\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[v9e-jy]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[bi7-ah]\")\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t   alternateButton:nil\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t   alertVisible = NO;\n\t\t\t   }];\n}\n\n- (void)reset\n{\n\tif (self.fileHandle == nil) {\n\t\treturn;\n\t}\n\n\t[self.fileHandle truncateFileAtOffset:0];\n}\n\n- (void)close\n{\n\tif (self.fileHandle == nil) {\n\t\treturn;\n\t}\n\n\t@try {\n\t\t[self.fileHandle synchronizeFile];\n\t}\n\t@catch (NSException *exception) {\n\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\tLogStackTrace();\n\t}\n\n\t[self.fileHandle closeFile];\n\n\tself.fileHandle = nil;\n\n\tself.filePath = nil;\n\n\tself.lastWriteTime = 0;\n\n\tself.dateOpened = nil;\n\n\t[self removeIdleTimerObserver];\n}\n\n- (void)reopenIfNeeded\n{\n\t/* Implementation discussion: we already have a notification called\n\tIRCWorldDateHasChangedNotification that is fired by IRCWorld when\n\tthe user changes the date of the system or after time has naturally\n\treached midnight. Do we rely on this? I chose not to and here is why:\n\tRace conditions. There is no guarantee we will receive notification\n\ton time to beat the current write. Of which there can be multiple. */\n\tif (self.fileHandle != nil && [self.dateOpened isInSameDayAsDate:[NSDate date]]) {\n\t\treturn;\n\t}\n\n\t[self reopen];\n}\n\n- (void)reopen\n{\n\t[self close];\n\n\t[self open];\n}\n\n- (void)open\n{\n\tif (self.fileHandle != nil) {\n\t\tLogToConsoleError(\"Tried to open log file when a file handle already exists\");\n\n\t\treturn;\n\t}\n\n\tif ([self buildFilePath] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *filePath = self.filePath;\n\n\tNSString *writePath = self.writePath;\n\n\tif ([RZFileManager() fileExistsAtPath:writePath] == NO) {\n\t\tNSError *createDirectoryError = nil;\n\n\t\tif ([RZFileManager() createDirectoryAtPath:writePath withIntermediateDirectories:YES attributes:nil error:&createDirectoryError] == NO) {\n\t\t\tLogToConsoleError(\"Error Creating Folder: %{public}@\",\n\t\t\t\t createDirectoryError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ([RZFileManager() fileExistsAtPath:filePath] == NO) {\n\t\tNSError *writeFileError = nil;\n\n\t\tif ([@\"\" writeToFile:filePath atomically:NO encoding:NSUTF8StringEncoding error:&writeFileError] == NO) {\n\t\t\tLogToConsoleError(\"Error Creating File: %{public}@\",\n\t\t\t\t  writeFileError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tNSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];\n\n\tif (fileHandle == nil) {\n\t\tLogToConsoleError(\"Failed to open file handle at path '%{public}@'\", filePath.standardizedTildePath);\n\n\t\treturn;\n\t}\n\n\t[fileHandle seekToEndOfFile];\n\n\tself.fileHandle = fileHandle;\n\n\tself.dateOpened = [NSDate date];\n\n\t[self addIdleTimerObserver];\n}\n\n#pragma mark -\n#pragma mark Idle Timer\n\n- (BOOL)fileHandleIdle\n{\n\tNSTimeInterval lastWriteTime = self.lastWriteTime;\n\n\tNSTimeInterval currentTime = [NSDate timeIntervalSince1970];\n\n\tif (lastWriteTime > 0) {\n\t\tif ((currentTime - lastWriteTime) > _fileHandleIdleLimit) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n+ (TLOTimer *)idleTimer\n{\n\tstatic TLOTimer *idleTimer = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tidleTimer = [TLOTimer timerWithActionBlock:^(TLOTimer *sender) {\n\t\t\t[self idleTimerFired];\n\t\t} onQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];\n\t});\n\n\treturn idleTimer;\n}\n\n+ (void)idleTimerFired\n{\n\tif (_numberOfOpenFileHandles == 0) {\n\t\t[self stopIdleTimer];\n\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() postNotificationName:TLOFileLoggerIdleTimerNotification object:nil];\n}\n\n+ (void)startIdleTimer\n{\n\tTLOTimer *idleTimer = self.idleTimer;\n\n\tif (idleTimer.timerIsActive) {\n\t\treturn;\n\t}\n\n\t[idleTimer start:_idleTimerInterval onRepeat:YES];\n}\n\n+ (void)stopIdleTimer\n{\n\tTLOTimer *idleTimer = self.idleTimer;\n\n\tif (idleTimer.timerIsActive == NO) {\n\t\treturn;\n\t}\n\n\t[idleTimer stop];\n}\n\n- (void)idleTimerFired:(NSNotification *)notification\n{\n\tif (self.fileHandleIdle == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Closing %{public}@ because it's idle\", self);\n\n\t[self close];\n}\n\n- (void)updateIdleTimer\n{\n\tif (_numberOfOpenFileHandles == 0) {\n\t\t[self.class stopIdleTimer];\n\t} else {\n\t\t[self.class startIdleTimer];\n\t}\n}\n\n- (void)addIdleTimerObserver\n{\n\t_numberOfOpenFileHandles += 1;\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(idleTimerFired:) name:TLOFileLoggerIdleTimerNotification object:nil];\n\n\t[self updateIdleTimer];\n}\n\n- (void)removeIdleTimerObserver\n{\n\t_numberOfOpenFileHandles -= 1;\n\n\t[RZNotificationCenter() removeObserver:self name:TLOFileLoggerIdleTimerNotification object:nil];\n\n\t[self updateIdleTimer];\n}\n\n#pragma mark -\n#pragma mark Paths\n\n- (nullable NSString *)writePath\n{\n\treturn self.filePath.stringByDeletingLastPathComponent;\n}\n\n- (nullable NSString *)fileName\n{\n\treturn self.filePath.lastPathComponent;\n}\n\n+ (nullable NSString *)writePathForItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\tNSString *sourcePath = [TPCPathInfo transcriptFolder];\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self writePathForItem:item relativeTo:sourcePath];\n}\n\n+ (nullable NSString *)writePathForItem:(IRCTreeItem *)item relativeTo:(NSString *)sourcePath\n{\n\tNSParameterAssert(sourcePath != nil);\n\tNSParameterAssert(item != nil);\n\n\tIRCChannel *channel = item.associatedChannel;\n\n\tif (channel && channel.isUtility) {\n\t\treturn nil;\n\t}\n\t\n\tIRCClient *client = item.associatedClient;\n\n\tNSString *clientIdentifier = [client.uniqueIdentifier substringToIndex:5];\n\t\n\tNSString *clientName = [NSString stringWithFormat:@\"%@ (%@)\", client.name, clientIdentifier];\n\n\tNSString *basePath = nil;\n\t\n\tif (channel == nil) {\n\t\tbasePath = [NSString stringWithFormat:@\"/%@/%@/\", clientName.safeFilename, TLOFileLoggerConsoleDirectoryName];\n\t} else if (channel.isChannel) {\n\t\tbasePath = [NSString stringWithFormat:@\"/%@/%@/%@/\", clientName.safeFilename, TLOFileLoggerChannelDirectoryName, channel.name.safeFilename];\n\t} else if (channel.isPrivateMessage) {\n\t\tbasePath = [NSString stringWithFormat:@\"/%@/%@/%@/\", clientName.safeFilename, TLOFileLoggerPrivateMessageDirectoryName, channel.name.safeFilename];\n\t}\n\t\n\treturn [sourcePath stringByAppendingPathComponent:basePath];\n}\n\n- (nullable NSString *)writePathRelativeTo:(NSString *)sourcePath\n{\n\tNSParameterAssert(sourcePath != nil);\n\n\tIRCClient *client = self.client;\n\tIRCChannel *channel = self.channel;\n\n\tIRCTreeItem *item = ((channel) ?: client);\n\n\treturn [self.class writePathForItem:item relativeTo:sourcePath];\n}\n\n- (BOOL)buildFilePath\n{\n\tNSString *sourcePath = [TPCPathInfo transcriptFolder];\n\n\tif (sourcePath == nil) {\n\t\treturn NO;\n\t}\n\n\tNSString *writePath = [self writePathRelativeTo:sourcePath];\n\n\tif (writePath == nil) {\n\t\treturn NO;\n\t}\n\n\tNSString *dateTime = TXFormattedTimestamp([NSDate date], @\"%Y-%m-%d\");\n\n\tNSString *fileName = [NSString stringWithFormat:@\"%@.txt\", dateTime];\n\n\tNSString *filePath = [writePath stringByAppendingPathComponent:fileName];\n\n\tself.filePath = filePath;\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOInputHistory.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCWorld.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowTextView.h\"\n#import \"TLOInputHistoryPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Private Interface\n\n#define _inputHistoryMax\t\t\t\t\t\t100\n\nNSString * const _inputHistoryGlobalObjectKey\t= @\"TLOInputHistoryDefaultObject\";\n\n@interface TLOInputHistory ()\n@property (nonatomic, weak) TVCMainWindow *window;\n@property (nonatomic, strong) NSMutableDictionary *historyObjects;\n@property (nonatomic, copy, nullable) NSString *currentTreeItem;\n@end\n\n@interface TLOInputHistoryObject : NSObject <NSCopying>\n@property (nonatomic, assign) NSInteger historyBufferPosition;\n@property (nonatomic, strong) NSMutableArray *historyBuffer;\n@property (nonatomic, copy, nullable) NSAttributedString *lastHistoryItem;\n\n- (void)add:(NSAttributedString *)string;\n\n- (nullable NSAttributedString *)up:(NSAttributedString *)string;\n- (nullable NSAttributedString *)down:(NSAttributedString *)string;\n@end\n\n#pragma mark -\n#pragma mark Input History Manager\n\n@implementation TLOInputHistory\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(mainWindow != nil);\n\n\tif ((self = [super init])) {\n\t\tself.window = mainWindow;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.historyObjects = [NSMutableDictionary dictionary];\n}\n\n- (void)destroy:(IRCTreeItem *)treeItem\n{\n\tNSParameterAssert(treeItem != nil);\n\n\tif ([TPCPreferences inputHistoryIsChannelSpecific] == NO) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.historyObjects) {\n\t\tif (treeItem.isClient) {\n\t\t\tfor (IRCChannel *treeItemChild in ((IRCClient *)treeItem).channelList) {\n\t\t\t\t[self destroy:treeItemChild];\n\t\t\t}\n\t\t}\n\n\t\tNSString *itemId = treeItem.uniqueIdentifier;\n\n\t\t[self.historyObjects removeObjectForKey:itemId];\n\n\t\tif ([self.currentTreeItem isEqualToString:itemId]) {\n\t\t\tself.currentTreeItem = nil;\n\t\t}\n\t}\n}\n\n- (void)moveFocusTo:(IRCTreeItem *)treeItem\n{\n\tNSParameterAssert(treeItem != nil);\n\n\tif ([TPCPreferences inputHistoryIsChannelSpecific] == NO) {\n\t\treturn;\n\t}\n\n\tTVCMainWindowTextView *textView = self.window.inputTextField;\n\n\t/* Set current text field value to current object. */\n\tTLOInputHistoryObject *oldObject = [self currentObjectForFocusedTreeView];\n\n\tif (oldObject) {\n\t\toldObject.lastHistoryItem = textView.attributedStringValue;\n\t}\n\n\t/* Change to new view */\n\tself.currentTreeItem = treeItem.uniqueIdentifier;\n\n\t/* Does new selection have a history item? */\n\tTLOInputHistoryObject *newObject = [self currentObjectForFocusedTreeView];\n\n\tNSAttributedString *lastHistoryItem = newObject.lastHistoryItem;\n\n\tif (lastHistoryItem) {\n\t\ttextView.attributedStringValue = lastHistoryItem;\n\t} else {\n\t\ttextView.stringValue = @\"\";\n\t}\n}\n\n- (void)noteInputHistoryObjectScopeDidChange\n{\n\t@synchronized(self.historyObjects) {\n\t\t/* If the input history was made channel specific, then we copy the current\n\t\t value of the global input history to all tree items. */\n\t\tif ([TPCPreferences inputHistoryIsChannelSpecific])\n\t\t{\n\t\t\tfor (IRCClient *u in worldController().clientList) {\n\t\t\t\t[self inputHistoryObjectScopeDidChangeApplyToItem:u.uniqueIdentifier];\n\n\t\t\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t\t\t[self inputHistoryObjectScopeDidChangeApplyToItem:c.uniqueIdentifier];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[self.historyObjects removeObjectForKey:_inputHistoryGlobalObjectKey];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t[self.historyObjects removeAllObjects];\n\n\t\t\tself.currentTreeItem = nil;\n\t\t}\n\t}\n}\n\n- (void)inputHistoryObjectScopeDidChangeApplyToItem:(NSString *)itemId\n{\n\tNSParameterAssert(itemId != nil);\n\n\tTLOInputHistoryObject *globalObject = self.historyObjects[_inputHistoryGlobalObjectKey];\n\n\tif (globalObject) {\n\t\tTLOInputHistoryObject *newObject = [globalObject copy];\n\n\t\tnewObject.lastHistoryItem = nil;\n\n\t\tself.historyObjects[itemId] = newObject;\n\t}\n}\n\n- (nullable TLOInputHistoryObject *)currentObjectForFocusedTreeView\n{\n\t@synchronized(self.historyObjects) {\n\t\tNSString *currentObjectKey = nil;\n\n\t\tif ([TPCPreferences inputHistoryIsChannelSpecific]) {\n\t\t\tcurrentObjectKey = self.currentTreeItem;\n\t\t} else {\n\t\t\tcurrentObjectKey = _inputHistoryGlobalObjectKey;\n\t\t}\n\n\t\tif (currentObjectKey == nil) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tTLOInputHistoryObject *currentObject = self.historyObjects[currentObjectKey];\n\n\t\tif (currentObject == nil) {\n\t\t\tcurrentObject = [TLOInputHistoryObject new];\n\n\t\t\tself.historyObjects[currentObjectKey] = currentObject;\n\t\t}\n\n\t\treturn currentObject;\n\t}\n}\n\n- (void)add:(NSAttributedString *)string\n{\n\tTLOInputHistoryObject *object = [self currentObjectForFocusedTreeView];\n\n\tif (object == nil) {\n\t\treturn;\n\t}\n\n\t[object add:string];\n}\n\n- (nullable NSAttributedString *)up:(NSAttributedString *)string\n{\n\tTLOInputHistoryObject *object = [self currentObjectForFocusedTreeView];\n\n\tif (object == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [object up:string];\n}\n\n- (nullable NSAttributedString *)down:(NSAttributedString *)string\n{\n\tTLOInputHistoryObject *object = [self currentObjectForFocusedTreeView];\n\n\tif (object == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [object down:string];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Input History Objects\n\n@implementation TLOInputHistoryObject\n\n- (id)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.historyBuffer = [NSMutableArray new];\n}\n\n- (void)add:(NSAttributedString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tif (string.length == 0) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.historyBuffer) {\n\t\tNSAttributedString *lastEntry = self.historyBuffer.lastObject;\n\n\t\tif (lastEntry != nil || [lastEntry.string isEqualToString:string.string] == NO) {\n\t\t\t[self addToBuffer:string];\n\t\t}\n\n\t\tself.historyBufferPosition = self.historyBuffer.count;\n\t}\n}\n\n- (void)addToBuffer:(NSAttributedString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\t[self.historyBuffer addObject:string];\n\n\tif (self.historyBuffer.count > _inputHistoryMax) {\n\t\t[self.historyBuffer removeObjectAtIndex:0];\n\t}\n}\n\n- (nullable NSAttributedString *)up:(NSAttributedString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\t@synchronized(self.historyBuffer) {\n\t\tif (string.length > 0) {\n\t\t\tNSAttributedString *lastEntry = [self entryAtBufferPosition];\n\n\t\t\tif (lastEntry == nil || [lastEntry.string isEqualToString:string.string] == NO) {\n\t\t\t\t[self addToBuffer:string];\n\t\t\t}\n\t\t}\n\n\t\tself.historyBufferPosition -= 1;\n\n\t\tif (self.historyBufferPosition < 0) {\n\t\t\tself.historyBufferPosition = 0;\n\t\t} else if (self.historyBufferPosition < self.historyBuffer.count) {\n\t\t\treturn self.historyBuffer[self.historyBufferPosition];\n\t\t}\n\n\t\treturn nil;\n\t}\n}\n\n- (nullable NSAttributedString *)down:(NSAttributedString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\t@synchronized(self.historyBuffer) {\n\t\tif (string.length == 0) {\n\t\t\tself.historyBufferPosition = self.historyBuffer.count;\n\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSAttributedString *lastEntry = [self entryAtBufferPosition];\n\n\t\tif (lastEntry == nil || [lastEntry.string isEqualToString:string.string] == NO) {\n\t\t\t[self addToBuffer:string];\n\n\t\t\treturn [NSAttributedString attributedString];\n\t\t}\n\n\t\tself.historyBufferPosition += 1;\n\n\t\tlastEntry = [self entryAtBufferPosition];\n\n\t\tif (lastEntry) {\n\t\t\treturn lastEntry;\n\t\t}\n\n\t\treturn [NSAttributedString attributedString];\n\t}\n}\n\n- (BOOL)bufferPositionIsInRange\n{\n\treturn (self.historyBufferPosition >= 0 &&\n\t\t\tself.historyBufferPosition < self.historyBuffer.count);\n}\n\n- (nullable NSAttributedString *)entryAtBufferPosition\n{\n\tif ([self bufferPositionIsInRange] == NO) {\n\t\treturn nil;\n\t}\n\n\treturn self.historyBuffer[self.historyBufferPosition];\n}\n\n- (id)copyWithZone:(nullable NSZone *)zone\n{\n\tTLOInputHistoryObject *newObject = [TLOInputHistoryObject new];\n\n\t[newObject->_historyBuffer addObjectsFromArray:self->_historyBuffer];\n\n\tnewObject->_historyBufferPosition = self->_historyBufferPosition;\n\tnewObject->_lastHistoryItem = self->_lastHistoryItem;\n\n\treturn newObject;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOInternetAddressLookup.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOInternetAddressLookup.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _requestTimeoutInterval\t\t\t30.0\n\n@interface TLOInternetAddressLookup ()\n@property (nonatomic, weak) id requestDelegate;\n@property (nonatomic, strong) NSURLConnection *connection;\n@property (nonatomic, strong) NSURLResponse *connectionResponse;\n@property (nonatomic, strong) NSMutableData *connectionResponseData;\n@property (nonatomic, copy, nullable) NSString *address;\n@end\n\n@implementation TLOInternetAddressLookup\n\n#pragma mark -\n#pragma mark Public API\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithDelegate:(id <TLOInternetAddressLookupDelegate>)delegate\n{\n\tNSParameterAssert(delegate != nil);\n\n\tif ((self = [super init])) {\n\t\tself.IPv4AddressIsValid = YES;\n\t\tself.IPv6AddressIsValid = YES;\n\n\t\tself.requestDelegate = delegate;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)performLookup\n{\n\t[self setupConnectionRequest];\n}\n\n- (void)cancelLookup\n{\n\t[self _teardownConnectionRequest];\n}\n\n- (void)setupConnectionRequest\n{\n\tNSAssert((self.connection == nil),\n\t\t@\"A lookup is already in progress\");\n\n\tself.connectionResponseData = [NSMutableData data];\n\n\tNSURL *requestURL = [NSURL URLWithString:[self addressSourceURL]];\n\n\tNSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t   cachePolicy:NSURLRequestReloadIgnoringCacheData\n\t\t\t\t\t\t\t\t\t\t\t\t\t   timeoutInterval:_requestTimeoutInterval];\n\n\trequest.HTTPMethod = @\"GET\";\n\n\tself.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];\n}\n\n- (void)_teardownConnectionRequest\n{\n\tif (self.connection) {\n\t\t[self.connection cancel];\n\t}\n\n\tself.connection = nil;\n\tself.connectionResponse = nil;\n\tself.connectionResponseData = nil;\n}\n\n- (void)teardownConnectionRequest\n{\n\t[self _teardownConnectionRequest];\n\n\t[self informDelegate];\n\n\tself.address = nil;\n}\n\n- (NSString *)addressSourceURL\n{\n\tif ([TPCPreferences fileTransferIPAddressDetectionMethod] == TXFileTransferIPAddressMethodRouterAndThirdParty) {\n\t\treturn [self thirdPartySourceURL];\n\t}\n\t\n\treturn @\"https://myip.codeux.com/\";\n}\n\n- (NSString *)thirdPartySourceURL\n{\n\tNSArray *services = @[\n\t  @\"https://wtfismyip.com/text\",\n\t  @\"https://canhazip.com/\",\n\t  @\"http://ifconfig.me/ip\",\n\t  @\"http://v4.ipv6-test.com/api/myip.php\",\n\t];\n\n\tNSUInteger randomIndex = (arc4random() % services.count);\n\n\treturn services[randomIndex];\n}\n\n#pragma mark -\n#pragma mark Connection Delegate\n\n- (void)informDelegate\n{\n\tNSString *address = self.address;\n\n\tif (address) {\n\t\t[self informDelegateLookupReturnedAddress:address];\n\t} else {\n\t\t[self informDelegateLookupFailed];\n\t}\n}\n\n- (void)informDelegateLookupReturnedAddress:(NSString *)address\n{\n\tif ([self.requestDelegate respondsToSelector:@selector(internetAddressLookupReturnedAddress:)]) {\n\t\t[self.requestDelegate internetAddressLookupReturnedAddress:address];\n\t}\n}\n\n- (void)informDelegateLookupFailed\n{\n\tif ([self.requestDelegate respondsToSelector:@selector(internetAddressLookupFailed)]) {\n\t\t[self.requestDelegate internetAddressLookupFailed];\n\t}\n}\n\n- (void)connectionDidFinishLoading:(NSURLConnection *)connection\n{\n\tid connectionResponse = self.connectionResponse;\n\n\t// connectionResponse may not be NSHTTPURLResponse if the website\n\t// requested performs a location redirect to a data resource.\n\tif ([connectionResponse isKindOfClass:[NSHTTPURLResponse class]]) {\n\t\tBOOL isValidResponse = ([connectionResponse statusCode] == 200);\n\n\t\tif (isValidResponse) {\n\t\t\tNSData *addressData = self.connectionResponseData;\n\n\t\t\tNSString *address = [NSString stringWithData:addressData encoding:NSUTF8StringEncoding];\n\n\t\t\taddress = [address stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];\n\n\t\t\tif ((address.isIPv4Address && self.IPv4AddressIsValid) ||\n\t\t\t\t(address.isIPv6Address && self.IPv6AddressIsValid))\n\t\t\t{\n\t\t\t\tself.address = address;\n\t\t\t}\n\t\t}\n\t}\n\n\t[self teardownConnectionRequest];\n}\n\n- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error\n{\n\tLogToConsole(\"Lookup failed with error: %{public}@\", error.localizedDescription);\n\n\t[self teardownConnectionRequest];\n}\n\n- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data\n{\n\t[self.connectionResponseData appendData:data];\n\n\t// There is no reasonable explanation for the content of a request,\n\t// without headers, to exceed this length when it's sent in plain text.\n\tif (self.connectionResponseData.length > 1024) {\n\t\tLogToConsoleError(\"Too much data has been received for this to be a valid request\");\n\n\t\t[self teardownConnectionRequest];\n\t}\n}\n\n- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response\n{\n\tself.connectionResponse = response;\n}\n\n- (nullable NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse\n{\n\treturn nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOKeyEventHandler.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <objc/objc-runtime.h>\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOKeyEventHandler.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOKeyEventHandler ()\n@property (nonatomic, unsafe_unretained) id target;\n@property (nonatomic, strong) NSMutableDictionary *codeHandlerMap;\n@property (nonatomic, strong) NSMutableDictionary *characterHandlerMap;\n@end\n\n@implementation TLOKeyEventHandler\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithTarget:(id)target\n{\n\tif ((self = [super init])) {\n\t\t[self setKeyHandlerTarget:target];\n\n\t\t[self prepareInitialState];\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\tself.characterHandlerMap = [NSMutableDictionary new];\n\n\tself.codeHandlerMap = [NSMutableDictionary new];\n}\n\n- (void)dealloc\n{\n\tself.target = nil;\n}\n\n- (void)setKeyHandlerTarget:(id)target\n{\n\tNSParameterAssert(target != nil);\n\n\tself.target = target;\n}\n\n- (void)registerSelector:(SEL)selector key:(NSUInteger)keyCode modifiers:(NSUInteger)modifiers\n{\n\tNSParameterAssert(selector != NULL);\n\tNSParameterAssert(keyCode != 0);\n\n\tNSNumber *modifierKeys = @(modifiers);\n\n\tNSMutableDictionary *map = self.codeHandlerMap[modifierKeys];\n\n\tif (map == nil) {\n\t\tmap = [NSMutableDictionary dictionary];\n\n\t\tself.codeHandlerMap[modifierKeys] = map;\n\t}\n\n\tmap[@(keyCode)] = NSStringFromSelector(selector);\n}\n\n- (void)registerSelector:(SEL)selector character:(UniChar)character modifiers:(NSUInteger)modifiers\n{\n\tNSParameterAssert(selector != NULL);\n\tNSParameterAssert(character != 0);\n\n\tNSNumber *modifierKeys = @(modifiers);\n\n\tNSMutableDictionary *map = self.characterHandlerMap[modifierKeys];\n\n\tif (map == nil) {\n\t\tmap = [NSMutableDictionary dictionary];\n\n\t\tself.characterHandlerMap[modifierKeys] = map;\n\t}\n\n\tmap[@(character)] = NSStringFromSelector(selector);\n}\n\n- (void)registerSelector:(SEL)selector characters:(NSRange)characterRange modifiers:(NSUInteger)modifiers\n{\n\tNSParameterAssert(selector != NULL);\n\n\tNSNumber *modifierKeys = @(modifiers);\n\n\tNSMutableDictionary *map = self.characterHandlerMap[modifierKeys];\n\n\tif (map == nil) {\n\t\tmap = [NSMutableDictionary dictionary];\n\n\t\tself.characterHandlerMap[modifierKeys] = map;\n\t}\n\n\tNSUInteger from = characterRange.location;\n\n\tNSUInteger to = NSMaxRange(characterRange);\n\n\tfor (NSInteger i = from; i < to; ++i) {\n\t\tmap[@(i)] = NSStringFromSelector(selector);\n\t}\n}\n\n- (BOOL)processKeyEvent:(NSEvent *)e\n{\n\tNSParameterAssert(e != nil);\n\n\tNSTextInputContext *inputContext = [NSTextInputContext currentInputContext];\n\n\tif (inputContext && [inputContext.client markedRange].length > 0) {\n\t\treturn NO;\n\t}\n\n\tNSUInteger modifiers = (e.modifierFlags & (NSEventModifierFlagShift | NSEventModifierFlagControl | NSEventModifierFlagOption | NSEventModifierFlagCommand));\n\n\tNSNumber *modifierKeys = @(modifiers);\n\n\tNSMutableDictionary *codeMap = self.codeHandlerMap[modifierKeys];\n\n\tif (codeMap) {\n\t\tNSString *selectorName = codeMap[@(e.keyCode)];\n\n\t\tif (selectorName) {\n\t\t\tSEL selector = NSSelectorFromString(selectorName);\n\n\t\t\tNSMethodSignature *signature = [self.target methodSignatureForSelector:selector];\n\n\t\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t\t[invocation setTarget:self.target];\n\t\t\t[invocation setSelector:selector];\n\n\t\t\t[invocation setArgument:&e atIndex:2];\n\n\t\t\t[invocation invoke];\n\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\tNSMutableDictionary *characterMap = self.characterHandlerMap[modifierKeys];\n\n\tif (characterMap) {\n\t\tNSString *characterString = e.charactersIgnoringModifiers.lowercaseString;\n\n\t\tif (characterString.length > 0) {\n\t\t\tNSString *selectorName = characterMap[@([characterString characterAtIndex:0])];\n\n\t\t\tif (selectorName) {\n\t\t\t\tSEL selector = NSSelectorFromString(selectorName);\n\n\t\t\t\tNSMethodSignature *signature = [self.target methodSignatureForSelector:selector];\n\n\t\t\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t\t\t[invocation setTarget:self.target];\n\t\t\t\t[invocation setSelector:selector];\n\n\t\t\t\t[invocation setArgument:&e atIndex:2];\n\n\t\t\t\t[invocation invoke];\n\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOLinkParser.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n*    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n@objc(TLOLinkParser)\npublic class LinkParser: NSObject\n{\n\t@objc(locateLinksInString:)\n\tpublic static func locateLinks(in string: String) -> [AHHyperlinkScannerResult]\n\t{\n\t\treturn AHHyperlinkScanner.matches(in: string, strictMatching: false)\n\t}\n\n\t@objc\n\tpublic static let bannedLineTypes =\n\t[\n\t\tTVCLogLine.string(for: .mode),\n\t\tTVCLogLine.string(for: .join),\n\t\tTVCLogLine.string(for: .nick),\n\t\tTVCLogLine.string(for: .invite)\n\t].compactMap { $0 }\n}\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLONicknameCompletionStatus.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCChannelUser.h\"\n#import \"IRCCommandIndex.h\"\n#import \"IRCISupportInfo.h\"\n#import \"IRCUser.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowTextView.h\"\n#import \"TLONicknameCompletionStatusPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLONicknameCompletionStatus ()\n@property (nonatomic, weak) TVCMainWindow *window;\n@property (nonatomic, copy, nullable) NSString *completedValue;\n@property (nonatomic, copy, nullable) NSString *completedValueCompletionSuffix;\n@property (nonatomic, copy, nullable) NSString *currentTextViewStringValue;\n@property (nonatomic, copy, nullable) NSString *cachedSearchPattern;\n@property (nonatomic, copy, nullable) NSString *cachedSearchPatternPrefixCharacter;\n@property (nonatomic, copy, nullable) NSString *cachedCompletionSuffix;\n@property (nonatomic, assign) NSRange selectionRangeAfterLastCompletion;\n@property (nonatomic, assign) NSRange rangeOfTextSelection;\n@property (nonatomic, assign) NSRange rangeOfSearchPattern;\n@property (nonatomic, assign) NSRange rangeOfCompletionSuffix;\n@property (nonatomic, assign) NSInteger selectionIndexOfLastCompletion;\n@property (nonatomic, assign) BOOL completionIsMovingForward;\n@property (nonatomic, assign) BOOL isCompletingChannelName;\n@property (nonatomic, assign) BOOL isCompletingCommand;\n@property (nonatomic, assign) BOOL isCompletingNickname;\n@property (nonatomic, assign) BOOL searchPatternIsAtStart;\n@property (nonatomic, assign) BOOL searchPatternIsAtEnd;\n@property (nonatomic, assign) BOOL completionCacheIsConstructed;\n@end\n\n@implementation TLONicknameCompletionStatus\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithWindow:(TVCMainWindow *)mainWindow\n{\n\tif ((self = [super init])) {\n\t\tself.window = mainWindow;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[self clear];\n}\n\n- (void)completeNickname:(BOOL)movingForward\n{\n\t[self performCompletion:movingForward];\n}\n\n#pragma mark -\n#pragma mark Completion Management\n\n- (void)performCompletion:(BOOL)movingForward\n{\n\tBOOL canContinuePreviousScan = YES;\n\n\tTVCMainWindowTextView *textView = self.window.inputTextField;\n\n\t/* Focus text field so if the insertion point we not already\n\t in it, its there now so we can get selected range. */\n\t[textView focus];\n\n\t/* Get the selected range. Length may be zero in which\n\t case the insertion point is just sitting idle. */\n\tNSRange selectedRange = [textView selectedRange];\n\n\tif (selectedRange.location == NSNotFound) {\n\t\treturn;\n\t}\n\n\t/* Perform various comparisons to determine whether the\n\t cache has to be rebuilt. */\n\tif ( self.selectionIndexOfLastCompletion == NSNotFound ||\n\t\tself.selectionRangeAfterLastCompletion.location == NSNotFound ||\n\t\t(self.rangeOfTextSelection.location == NSNotFound &&\n\t\t self.rangeOfSearchPattern.location == 0 && self.rangeOfSearchPattern.length == 0) ||\n\t\tselectedRange.location != self.selectionRangeAfterLastCompletion.location ||\n\t\tselectedRange.length != self.selectionRangeAfterLastCompletion.length)\n\t{\n\t\tcanContinuePreviousScan = NO;\n\t}\n\n\tNSString *currentTextViewStringValue = textView.string;\n\n\tif (self.currentTextViewStringValue.length == 0) {\n\t\tcanContinuePreviousScan = NO;\n\t} else if ([self.currentTextViewStringValue isEqualToString:currentTextViewStringValue] == NO) {\n\t\tcanContinuePreviousScan = NO;\n\t}\n\n\tself.currentTextViewStringValue = currentTextViewStringValue;\n\n\tself.completionIsMovingForward = movingForward;\n\n\t/* Move onto stage two of the completion */\n\tif (canContinuePreviousScan == NO) {\n\t\tself.rangeOfTextSelection = selectedRange;\n\n\t\t[self constructCache];\n\t}\n\n\tif (self.completionCacheIsConstructed) {\n\t\tif ([self performCompletion_step1] == NO)\n\t\t\treturn;\n\n\t\t[self performCompletion_step2];\n\t\t[self performCompletion_step3];\n\t\t[self performCompletion_step4];\n\t}\n}\n\n- (BOOL)performCompletion_step1\n{\n\t/* Only blindly complete nicknames */\n\tBOOL searchPatternIsEmpty = (self.cachedSearchPattern.length == 0);\n\n\tif (searchPatternIsEmpty && self.isCompletingNickname == NO) {\n\t\treturn NO;\n\t}\n\n\t/* Define our choices for the completion. The choicesUppercase array\n\t holds all the case-sensitive representations of the completions while\n\t the choicesLowercase array holds each completion as a lowercase string.\n\t The lowercase string is compared against the lowercase backward cut. If\n\t they match, then the actual case is requested from choicesUppercase. */\n\tNSMutableArray *choicesUppercase = [NSMutableArray array];\n\tNSMutableArray *choicesLowercase = [NSMutableArray array];\n\n\tif (self.isCompletingCommand)\n\t{\n\t\tfor (NSString *command in [IRCCommandIndex localCommandList]) {\n\t\t\t[choicesUppercase addObject:command.lowercaseString];\n\t\t}\n\n\t\t[choicesUppercase addObjectsFromArray:sharedPluginManager().supportedUserInputCommands];\n\t\t[choicesUppercase addObjectsFromArray:sharedPluginManager().supportedAppleScriptCommands];\n\n\t\t/* complete commands in alphabetical order */\n\t\t[choicesUppercase sortUsingSelector:@selector(localizedCompare:)];\n\t}\n\telse if (self.isCompletingChannelName)\n\t{\n\t\tIRCClient *client = self.window.selectedClient;\n\t\tIRCChannel *channel = self.window.selectedChannel;\n\n\t\tif (channel) {\n\t\t\t[choicesUppercase addObject:channel.name];\n\t\t}\n\n\t\tfor (IRCChannel *cc in client.channelList) {\n\t\t\tif (cc == channel) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[choicesUppercase addObject:cc.name];\n\t\t}\n\t}\n\telse if (self.isCompletingNickname)\n\t{\n\t\t/* Complete the entire user list. */\n\t\tIRCClient *client = self.window.selectedClient;\n\t\tIRCChannel *channel = self.window.selectedChannel;\n\n\t\tif (channel == nil) {\n\t\t\treturn NO; // Umm, where to get channels?...\n\t\t}\n\n\t\t/* When the search pattern is empty, then special consideration is taken for how\n\t\t the human brain may expect the result. When there is a search pattern, the list\n\t\t is sorted using member weight, but that information is not really relevant when\n\t\t you are targeting all. When the search pattern is empty, the member list is sorted\n\t\t alphabetically and only the single most highly weighted user is placed at the top\n\t\t of the list and that only occurs if there is a user with a different weight. */\n\t\t__block IRCChannelUser *userWithGreatestWeight = nil;\n\n\t\t__block BOOL noUserHadGreaterWeightThanOriginal = YES;\n\n\t\tNSArray *memberList = nil;\n\n\t\tif (searchPatternIsEmpty == NO) {\n\t\t\tmemberList = [channel.memberList sortedArrayUsingSelector:@selector(compareUsingWeights:)];\n\n\t\t\tuserWithGreatestWeight = memberList.firstObject;\n\t\t} else {\n\t\t\tmemberList = [channel.memberList sortedArrayUsingComparator:^NSComparisonResult(IRCChannelUser *user1, IRCChannelUser *user2) {\n\t\t\t\tif (userWithGreatestWeight == nil) {\n\t\t\t\t\tuserWithGreatestWeight = user1;\n\t\t\t\t}\n\n\t\t\t\tif (userWithGreatestWeight.totalWeight < user2.totalWeight) {\n\t\t\t\t\tuserWithGreatestWeight = user2;\n\n\t\t\t\t\tnoUserHadGreaterWeightThanOriginal = NO;\n\t\t\t\t}\n\n\t\t\t\treturn [user1.user.nickname caseInsensitiveCompare:user2.user.nickname];\n\t\t\t}];\n\t\t}\n\n\t\t/* Add nicknames to list */\n\t\tNSCharacterSet *nonAlphaCharacters = [NSCharacterSet characterSetWithCharactersInString:@\"^[]-_`{}\\\\\"];\n\n\t\tvoid (^addNickname)(NSString *, BOOL) = ^(NSString *nickname, BOOL addTrimmedVariant)\n\t\t{\n\t\t\t/* Add unmodified version of nickname */\n\t\t\t[choicesUppercase addObject:nickname];\n\n\t\t\t[choicesLowercase addObject:nickname.lowercaseString];\n\n\t\t\t/* Add choice after it has been trimmed of special characters as well. */\n\t\t\tif (addTrimmedVariant == NO)\n\t\t\t\treturn;\n\n\t\t\tNSString *nicknameTrimmed = [self trimNickname:nickname usingCharacterSet:nonAlphaCharacters];\n\n\t\t\tif (nicknameTrimmed.length > 0 && [nickname isNotEqualTo:nicknameTrimmed]) {\n\t\t\t\tNSString *nicknameTrimmedLowercase = nicknameTrimmed.lowercaseString;\n\n\t\t\t\tif ([choicesLowercase containsObject:nicknameTrimmedLowercase] == NO) {\n\t\t\t\t\t[choicesUppercase addObject:nickname];\n\n\t\t\t\t\t[choicesLowercase addObject:nicknameTrimmedLowercase];\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tBOOL includeTrimmedNicknames = (searchPatternIsEmpty == NO);\n\n\t\tif (noUserHadGreaterWeightThanOriginal == NO) {\n\t\t\taddNickname(userWithGreatestWeight.user.nickname, includeTrimmedNicknames);\n\t\t}\n\n\t\tfor (IRCChannelUser *m in memberList) {\n\t\t\tif (noUserHadGreaterWeightThanOriginal == NO && m == userWithGreatestWeight) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\taddNickname(m.user.nickname, includeTrimmedNicknames);\n\t\t}\n\n\t\t/* Complete static names, including application name. */\n\t\taddNickname(@\"NickServ\", NO);\n\t\taddNickname(@\"RootServ\", NO);\n\t\taddNickname(@\"OperServ\", NO);\n\t\taddNickname(@\"HostServ\", NO);\n\t\taddNickname(@\"ChanServ\", NO);\n\t\taddNickname(@\"MemoServ\", NO);\n\n\t\taddNickname([TPCApplicationInfo applicationNameWithoutVersion], NO);\n\n\t\t/* Complete network name. */\n\t\tNSString *networkName = client.supportInfo.networkName;\n\n\t\tif (networkName) {\n\t\t\taddNickname(networkName, NO);\n\t\t}\n\t}\n\n\t/* Quick method for replacing the value of each array\n\t object based on a provided selector. */\n\tif (self.isCompletingChannelName || self.isCompletingCommand) {\n\t\t[choicesLowercase addObjectsFromArray:choicesUppercase];\n\n\t\t[choicesLowercase performSelectorOnObjectValueAndReplace:@selector(lowercaseString)];\n\t}\n\n\t/* Now that we know the possible matches, we find all values\n\t that has our search pattern as its prefix. */\n\tNSMutableArray *choicesLowercaseMatched = nil;\n\tNSMutableArray *choicesUppercaseMatched = nil;\n\n\tif (searchPatternIsEmpty) {\n\t\tchoicesLowercaseMatched = choicesLowercase;\n\t\tchoicesUppercaseMatched = choicesUppercase;\n\t}\n\telse\n\t{\n\t\tchoicesUppercaseMatched = [NSMutableArray array];\n\t\tchoicesLowercaseMatched = [NSMutableArray array];\n\n\t\tNSString *searchPatternLowercase = self.cachedSearchPattern.lowercaseString;\n\n\t\t[choicesLowercase enumerateObjectsUsingBlock:^(NSString *choice, NSUInteger choiceIndex, BOOL *stop) {\n\t\t\tif ([choice hasPrefix:searchPatternLowercase]) {\n\t\t\t\t[choicesLowercaseMatched addObject:choice];\n\n\t\t\t\t[choicesUppercaseMatched addObject:choicesUppercase[choiceIndex]];\n\t\t\t}\n\t\t}];\n\t}\n\n\tNSUInteger choicesLowercaseMatchedCount = choicesLowercaseMatched.count;\n\n\tif (choicesLowercaseMatchedCount == 0) {\n\t\treturn NO;\n\t}\n\n\t/* Now that we know the choices that are actually available to the\n\t string being completed; we can filter through each going backwards\n\t or forward depending on the call to this method. */\n\tNSString *valueMatchedBySearchPattern = nil;\n\n\tNSUInteger indexOfMatchedValue = self.selectionIndexOfLastCompletion;\n\n\tif (choicesLowercaseMatchedCount <= indexOfMatchedValue || indexOfMatchedValue == NSNotFound) {\n\t\tvalueMatchedBySearchPattern = choicesUppercaseMatched[0];\n\n\t\tself.selectionIndexOfLastCompletion = 0;\n\t} else {\n\t\tif (self.completionIsMovingForward) {\n\t\t\tindexOfMatchedValue += 1;\n\n\t\t\tif (choicesLowercaseMatchedCount <= indexOfMatchedValue) {\n\t\t\t\tindexOfMatchedValue = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tif (indexOfMatchedValue == 0) {\n\t\t\t\tindexOfMatchedValue = (choicesLowercaseMatchedCount - 1);\n\t\t\t} else {\n\t\t\t\tindexOfMatchedValue -= 1;\n\t\t\t}\n\t\t}\n\n\t\tvalueMatchedBySearchPattern = choicesUppercaseMatched[indexOfMatchedValue];\n\n\t\tself.selectionIndexOfLastCompletion = indexOfMatchedValue;\n\t}\n\n\tif (self.cachedSearchPatternPrefixCharacter.length > 0) {\n\t\tvalueMatchedBySearchPattern = [self.cachedSearchPatternPrefixCharacter stringByAppendingString:valueMatchedBySearchPattern];\n\t}\n\n\tself.completedValue = valueMatchedBySearchPattern;\n\n\treturn YES;\n}\n\n- (void)performCompletion_step2\n{\n\t/* Add the completed string to the spell checker so that a nickname\n\t wont show up as spelled incorrectly. The spell checker is cleared\n\t of these ignores between channel changes. */\n\tTVCMainWindowTextView *textView = self.window.inputTextField;\n\n\t[RZSpellChecker() ignoreWord:self.completedValue inSpellDocumentWithTag:textView.spellCheckerDocumentTag];\n}\n\n- (void)performCompletion_step3\n{\n\tNSString *newCompletionSuffix = nil;\n\n\tBOOL whitespaceAlreadyInPosition = NO;\n\tBOOL whitespaceContainedByCachedSuffix = NO;\n\n\tif ([self.cachedCompletionSuffix hasSuffixWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]) {\n\t\twhitespaceAlreadyInPosition = YES;\n\t\twhitespaceContainedByCachedSuffix = YES;\n\t}\n\n\tif (whitespaceAlreadyInPosition == NO) {\n\t\tNSInteger maximumCompletionSuffixEndPoint = (self.currentTextViewStringValue.length - 1);\n\n\t\tNSInteger nextCharacterInRange = NSMaxRange(self.rangeOfCompletionSuffix);\n\n\t\tif (nextCharacterInRange < maximumCompletionSuffixEndPoint) {\n\t\t\tUniChar nextChar = [self.currentTextViewStringValue characterAtIndex:nextCharacterInRange];\n\n\t\t\tif ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:nextChar]) {\n\t\t\t\twhitespaceAlreadyInPosition = YES;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (self.isCompletingNickname && self.searchPatternIsAtStart)\n\t{\n\t\tNSString *userCompletionSuffix = [TPCPreferences tabCompletionSuffix];\n\n\t\tNSInteger userCompletionSuffixLength = userCompletionSuffix.length;\n\n\t\tif (whitespaceAlreadyInPosition) {\n\t\t\tif ([userCompletionSuffix hasSuffixWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]]) {\n\t\t\t\tif (whitespaceContainedByCachedSuffix == NO && userCompletionSuffixLength > 1) {\n\t\t\t\t\tnewCompletionSuffix = [userCompletionSuffix substringToIndex:(userCompletionSuffixLength - 1)];\n\t\t\t\t} else if (whitespaceContainedByCachedSuffix) {\n\t\t\t\t\tnewCompletionSuffix = userCompletionSuffix;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewCompletionSuffix = userCompletionSuffix;\n\t\t\t}\n\t\t} else {\n\t\t\tif (userCompletionSuffixLength == 0) {\n\t\t\t\tBOOL doNotAppendWhitespace = [TPCPreferences tabCompletionDoNotAppendWhitespace];\n\n\t\t\t\tif (doNotAppendWhitespace == NO) {\n\t\t\t\t\tnewCompletionSuffix = @\" \";\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewCompletionSuffix = userCompletionSuffix;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (whitespaceAlreadyInPosition == NO) {\n\t\t\tnewCompletionSuffix = @\" \";\n\t\t}\n\t}\n\n\tself.completedValueCompletionSuffix = newCompletionSuffix;\n}\n\n- (void)performCompletion_step4\n{\n\t/* Calculate range of the section that will be replaced. */\n\tNSRange completeReplacementRange;\n\n\tcompleteReplacementRange.location = self.rangeOfSearchPattern.location;\n\tcompleteReplacementRange.length = (self.rangeOfSearchPattern.length + self.rangeOfCompletionSuffix.length);\n\n\t/* Create the replacement value */\n\tNSString *combinedCompletedValue = nil;\n\n\tif (self.completedValueCompletionSuffix) {\n\t\tcombinedCompletedValue = [self.completedValue stringByAppendingString:self.completedValueCompletionSuffix];\n\t} else {\n\t\tcombinedCompletedValue =  self.completedValue;\n\t}\n\n\t/* Perform replacement of selection with the new value */\n\tTVCMainWindowTextView *textView = self.window.inputTextField;\n\n\tif ([textView shouldChangeTextInRange:completeReplacementRange replacementString:combinedCompletedValue]) {\n\t\t[textView replaceCharactersInRange:completeReplacementRange withString:combinedCompletedValue];\n\n\t\t[textView didChangeText];\n\t}\n\n\t/* Modify range to account for new length */\n\tcompleteReplacementRange.length = combinedCompletedValue.length;\n\n\t/* Scroll new selection into view and select it */\n\tNSRange newSelectionRange = NSMakeRange((completeReplacementRange.location + completeReplacementRange.length), 0);\n\n\t[textView scrollRangeToVisible:newSelectionRange];\n\n\t[textView setSelectedRange:newSelectionRange];\n\n\tself.selectionRangeAfterLastCompletion = newSelectionRange;\n\n\t/* Calculate range for new suffix */\n\tNSRange completeCompletionSuffixRange;\n\n\tcompleteCompletionSuffixRange.location = (self.rangeOfSearchPattern.location + self.rangeOfSearchPattern.length);\n\tcompleteCompletionSuffixRange.length = (completeReplacementRange.length - self.rangeOfSearchPattern.length);\n\n\tself.rangeOfCompletionSuffix = completeCompletionSuffixRange;\n\n\t/* Finish operation by updating cache */\n\tself.currentTextViewStringValue = textView.string;\n\n\tself.completedValue = nil;\n\tself.completedValueCompletionSuffix = nil;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (NSUInteger)textViewMaximumRange\n{\n\tTVCMainWindowTextView *textView = self.window.inputTextField;\n\n\treturn textView.stringLength;\n}\n\n- (nullable NSString *)trimNickname:(NSString *)nickname usingCharacterSet:(NSCharacterSet *)charset\n{\n\tfor (NSUInteger i = 0; i < nickname.length; i++) {\n\t\tUniChar c = [nickname characterAtIndex:i];\n\n\t\tif ([charset characterIsMember:c]) {\n\t\t\tcontinue;\n\t\t} else {\n\t\t\treturn [nickname substringFromIndex:i];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark Cache Construction\n\n- (void)constructCache\n{\n\t[self clearCache];\n\n\tif ([self constructCachedSearchPattern] == NO)\n\t\treturn;\n\n\tif ([self constructCachedSearchPatternPrefixCharacter] == NO)\n\t\treturn;\n\n\tif ([self constructCachedCompletionSuffix] == NO)\n\t\treturn;\n\n\tself.completionCacheIsConstructed = YES;\n}\n\n- (BOOL)constructCachedSearchPattern\n{\n\t/* Given string and a starting point, we move backwards\n\t from that starting point until we reach a comma (,) or\n\t a localized space character. */\n\tNSRange selectedRange = self.rangeOfTextSelection;\n\n\tNSInteger searchPatternStartingPoint = 0;\n\n\tif (selectedRange.location > 0) {\n\t\tfor (NSInteger i = (selectedRange.location - 1); i >= 0; i--) {\n\t\t\tUniChar cc = [self.currentTextViewStringValue characterAtIndex:i];\n\n\t\t\tif ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:cc] || cc == '\\x02c') {\n\t\t\t\tsearchPatternStartingPoint = (i + 1); // Starting point is plus one to\n\t\t\t\t\t\t\t\t\t\t\t\t\t  // position the starting index as\n\t\t\t\t\t\t\t\t\t\t\t\t\t  // character after separator\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Now that we know the starting point, we can extract the search string. */\n\tNSInteger searchPatternLength = (selectedRange.location - searchPatternStartingPoint);\n\n\tself.rangeOfSearchPattern = NSMakeRange(searchPatternStartingPoint, searchPatternLength);\n\n\tif (searchPatternLength == 0) {\n\t\tself.cachedSearchPattern = @\"\";\n\t} else {\n\t\tself.cachedSearchPattern = [self.currentTextViewStringValue substringWithRange:self.rangeOfSearchPattern];\n\t}\n\n\tself.searchPatternIsAtStart = (searchPatternStartingPoint == 0);\n\n\treturn YES;\n}\n\n- (BOOL)constructCachedSearchPatternPrefixCharacter\n{\n\tUniChar searchPatternFirstCharacter = 0; // null\n\n\tif (self.cachedSearchPattern.length > 0) {\n\t\tsearchPatternFirstCharacter = [self.cachedSearchPattern characterAtIndex:0];\n\t}\n\n\tif (self.searchPatternIsAtStart && searchPatternFirstCharacter == '\\x02f')\n\t{\n\t\tself.isCompletingCommand = YES;\n\n\t\tself.cachedSearchPattern = [self.cachedSearchPattern substringFromIndex:1];\n\t\tself.cachedSearchPatternPrefixCharacter = @\"\\x02f\";\n\t}\n\telse if (searchPatternFirstCharacter == '\\x040')\n\t{\n\t\tself.isCompletingNickname = YES;\n\n\t\tself.cachedSearchPattern = [self.cachedSearchPattern substringFromIndex:1];\n\t\tself.cachedSearchPatternPrefixCharacter = @\"\\x040\";\n\t}\n\telse if (searchPatternFirstCharacter == '\\x023')\n\t{\n\t\tself.isCompletingChannelName = YES;\n\t}\n\telse\n\t{\n\t\tself.isCompletingNickname = YES;\n\t}\n\n\tif (self.cachedSearchPattern == nil) {\n\t\treturn NO;\n\t} else {\n\t\treturn YES;\n\t}\n}\n\n- (BOOL)constructCachedCompletionSuffix\n{\n\t/* Given string and a starting point, we move forward until the\n\t user's configured completion prefix is found. If its not found,\n\t then we look for a localized space, colon (:), or comma (,) */\n\tNSUInteger totalTextLength = (self.currentTextViewStringValue).length;\n\n\tNSRange selectedRange = self.rangeOfTextSelection;\n\n\tNSUInteger selectedRangeStartPoint = selectedRange.location;\n\n\tNSRange completionSuffixRange;\n\n\t/* If the user has a selection in the text field, then we\n\t will be happy to use that as our completion suffix. */\n\tif (selectedRange.length > 0) {\n\t\tcompletionSuffixRange = selectedRange;\n\n\t\tgoto complete_operation;\n\t} else {\n\t\tcompletionSuffixRange = NSMakeRange(selectedRangeStartPoint, 0);\n\t}\n\n\t/* Create search pattern for the user configured completion suffix and\n\t search for it. If its found within range, we return that. */\n\t/* If the range from start of our search to the beginning of the user's\n\t completion suffix contains a whitespace or exceeds 30 characters, then\n\t we do not use that range. */\n\tif (self.isCompletingNickname) {\n\t\tNSString *userCompletionSuffix = [TPCPreferences tabCompletionSuffix];\n\n\t\tif (userCompletionSuffix.length > 0) {\n\t\t\tNSRange completionSearchRange = NSMakeRange(selectedRange.location,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t(totalTextLength - selectedRange.location));\n\n\t\t\tNSRange completionRangePosition = [self.currentTextViewStringValue rangeOfString:userCompletionSuffix options:0 range:completionSearchRange];\n\n\t\t\tif (NSRangeIsValid(completionRangePosition) && completionRangePosition.length < 30) {\n\t\t\t\tNSRange whitespaceSearchRange = NSMakeRange(selectedRange.location,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcompletionRangePosition.location - selectedRange.location);\n\n\t\t\t\tNSRange whitespaceSearchResult =\n\t\t\t\t[self.currentTextViewStringValue rangeOfCharacterFromSet:[NSCharacterSet whitespaceCharacterSet] options:0 range:whitespaceSearchRange];\n\n\t\t\t\tif (whitespaceSearchResult.location == NSNotFound) {\n\t\t\t\t\tcompletionSuffixRange.length = (NSMaxRange(completionRangePosition) - selectedRangeStartPoint);\n\n\t\t\t\t\tgoto complete_operation;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Search for interesting characters. */\n\tBOOL cutNextWord = [TPCPreferences tabCompletionCutForwardToFirstWhitespace];\n\n\tif (cutNextWord) {\n\t\tNSInteger maximumCompletionSuffixEndPoint = (totalTextLength - 1);\n\n\t\tfor (NSInteger i = selectedRangeStartPoint; i <= maximumCompletionSuffixEndPoint; i++) {\n\t\t\tUniChar cc = [self.currentTextViewStringValue characterAtIndex:i];\n\n\t\t\tif ([[NSCharacterSet whitespaceCharacterSet] characterIsMember:cc]\n\t\t\t\t|| cc == '\\x03a'\n\t\t\t\t|| cc == '\\x02c')\n\t\t\t{\n\t\t\t\tcompletionSuffixRange.length = (i - selectedRangeStartPoint);\n\n\t\t\t\tgoto complete_operation;\n\t\t\t}\n\t\t}\n\n\t\t// Fallback when we never found a character\n\t\tcompletionSuffixRange.length = (totalTextLength - selectedRangeStartPoint);\n\t}\n\n\t/* Cache relevant information */\ncomplete_operation:\n\tself.rangeOfCompletionSuffix = completionSuffixRange;\n\n\tif (self.rangeOfCompletionSuffix.length == 0) {\n\t\tself.cachedCompletionSuffix = @\"\";\n\t} else {\n\t\tself.cachedCompletionSuffix = [self.currentTextViewStringValue substringWithRange:self.rangeOfCompletionSuffix];\n\t}\n\n\tself.searchPatternIsAtEnd = (NSMaxRange(self.rangeOfCompletionSuffix) == totalTextLength);\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Cache Management\n\n- (void)clearCache\n{\n\tself.completedValue = nil;\n\tself.completedValueCompletionSuffix = nil;\n\n\tself.cachedSearchPattern = nil;\n\tself.cachedSearchPatternPrefixCharacter = nil;\n\n\tself.selectionIndexOfLastCompletion = NSNotFound;\n\n\tself.cachedCompletionSuffix = nil;\n\n\tself.rangeOfCompletionSuffix = NSMakeRange(0, 0);\n\tself.rangeOfSearchPattern = NSMakeRange(0, 0);\n\n\tself.completionCacheIsConstructed = NO;\n\n\tself.isCompletingChannelName = NO;\n\tself.isCompletingCommand = NO;\n\tself.isCompletingNickname = NO;\n\n\tself.searchPatternIsAtEnd = NO;\n\tself.searchPatternIsAtStart = NO;\n}\n\n- (void)clear\n{\n\t[self clearCache];\n\n\tself.currentTextViewStringValue = nil;\n\n\tself.rangeOfTextSelection = NSEmptyRange();\n\n\tself.selectionRangeAfterLastCompletion = NSEmptyRange();\n\n\tself.completionIsMovingForward = NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLONotificationConfiguration.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLONotificationConfigurationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TXDefaultAlertSoundPreferenceValue = @\"Default\";\nNSString * const TXNoAlertSoundPreferenceValue = @\"None\";\n\n@interface TLONotificationConfiguration ()\n@property (nonatomic, assign, readwrite) TXNotificationType eventType;\n@end\n\n@implementation TLONotificationConfiguration\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithEventType:(TXNotificationType)aEventType\n{\n\tif ((self = [super init])) {\n\t\tself.eventType = aEventType;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (instancetype)configurationWithEventType:(TXNotificationType)eventType\n{\n\treturn [[self alloc] initWithEventType:eventType];\n}\n\n+ (NSString *)localizedAlertDefaultSoundTitle\n{\n\treturn TXTLS(@\"TVCNotificationConfigurationView[0rs-8l]\");\n}\n\n+ (NSString *)localizedAlertNoSoundTitle\n{\n\treturn TXTLS(@\"TVCNotificationConfigurationView[vje-9n]\");\n}\n\n- (NSString *)displayName\n{\n\treturn [sharedNotificationController() titleForEvent:self.eventType];\n}\n\n- (nullable NSString *)alertSound\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (void)setAlertSound:(nullable NSString *)alertSound\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (NSUInteger)pushNotification\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn NSControlStateValueOff;\n}\n\n- (void)setPushNotification:(NSUInteger)pushNotification\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (NSUInteger)speakEvent\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn NSControlStateValueOff;\n}\n\n- (void)setSpeakEvent:(NSUInteger)speakEvent\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (NSUInteger)disabledWhileAway\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn NSControlStateValueOff;\n}\n\n- (void)setDisabledWhileAway:(NSUInteger)disabledWhileAway\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (NSUInteger)bounceDockIcon\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn NSControlStateValueOff;\n}\n\n- (void)setBounceDockIcon:(NSUInteger)bounceDockIcon\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (NSUInteger)bounceDockIconRepeatedly\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn NSControlStateValueOff;\n}\n\n- (void)setBounceDockIconRepeatedly:(NSUInteger)bounceDockIconRepeatedly\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLONotificationController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TVCMainWindow.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TLOLocalization.h\"\n#import \"TDCFileTransferDialogPrivate.h\"\n#import \"TDCFileTransferDialogTransferControllerPrivate.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannel.h\"\n#import \"IRCWorld.h\"\n#import \"TLONotificationControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TXNotificationUserInfoClientIdentifierKey\t\t= @\"clientId\";\nNSString * const TXNotificationUserInfoChannelIdentifierKey\t\t= @\"channelId\";\n\nNSString * const TXNotificationDialogStandardNicknameFormat\t\t= @\"%@ %@\";\nNSString * const TXNotificationDialogActionNicknameFormat\t\t= @\"\\u2022 %@: %@\";\n\nNSString * const TXNotificationHighlightLogStandardActionFormat\t\t\t= @\"\\u2022 %@: %@\";\nNSString * const TXNotificationHighlightLogStandardMessageFormat\t\t= @\"%@ %@\";\n\nNSString * const TXNotificationCategoryIdentifierFileTransfer = @\"TXNotificationCategoryIdentifierFileTransfer\";\nNSString * const TXNotificationActionIdentifierFileTransferAccept = @\"TXNotificationActionIdentifierFileTransferAccept\";\n\nNSString * const TXNotificationCategoryIdentifierPrivateMessage = @\"TXNotificationCategoryIdentifierPrivateMessage\";\nNSString * const TXNotificationActionIdentifierPrivateMessageReply = @\"TXNotificationActionIdentifierPrivateMessageReply\";\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\nNSString * const TXNotificationCategoryIdentifierLicenseManager = @\"TXNotificationCategoryIdentifierLicenseManager\";\nNSString * const TXNotificationActionIdentifierLicenseManagerMoreInfo = @\"TXNotificationActionIdentifierLicenseManagerMoreInfo\";\n#endif\n\n@interface TLONotificationController () <UNUserNotificationCenterDelegate>\n@end\n\n@implementation TLONotificationController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\tRZUserNotificationCenter().delegate = (id)self;\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(mainWindowSelectionChanged:) name:TVCMainWindowSelectionChangedNotification object:nil];\n\n\t[RZUserNotificationCenter() requestAuthorizationWithOptions:(UNAuthorizationOptionAlert |\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t UNAuthorizationOptionProvidesAppNotificationSettings)\n\t\t\t\t\t\t\t\t\t\t\t  completionHandler:^(BOOL granted, NSError * _Nullable error) {\n\t\tif (error) {\n\t\t\tLogToConsoleError(\"Notifications failed to authorize: %{public}@\", error.localizedDescription);\n\t\t}\n\n\t\tLogToConsoleInfo(\"Notification permission: %{public}@\", StringFromBOOL(granted));\n\t}];\n\n\t[self registerCategories];\n}\n\n- (NSSet<UNNotificationCategory *> *)categoriesToRegister\n{\n\t/* File Transfers */\n\tUNNotificationAction *ftAcceptAction =\n\t[UNNotificationAction actionWithIdentifier:TXNotificationActionIdentifierFileTransferAccept\n\t\t\t\t\t\t\t\t\t\t title:TXTLS(@\"Prompts[qpv-go]\")\n\t\t\t\t\t\t\t\t\t   options:0];\n\n\tUNNotificationCategory *ftCategory =\n\t[UNNotificationCategory categoryWithIdentifier:TXNotificationCategoryIdentifierFileTransfer\n\t\t\t\t\t\t\t\t\t\t   actions:@[ftAcceptAction]\n\t\t\t\t\t\t\t\t intentIdentifiers:@[]\n\t\t\t\t\t\t\t\t\t\t   options:UNNotificationCategoryOptionCustomDismissAction];\n\n\t/* Private Message */\n\tUNTextInputNotificationAction *pmReplyAction =\n\t[UNTextInputNotificationAction actionWithIdentifier:TXNotificationActionIdentifierPrivateMessageReply\n\t\t\t\t\t\t\t\t\t\t\t\t  title:TXTLS(@\"Notifications[3t4-kl]\")\n\t\t\t\t\t\t\t\t\t\t\t\toptions:0\n\t\t\t\t\t\t\t\t   textInputButtonTitle:TXTLS(@\"Notifications[bhn-uo]\")\n\t\t\t\t\t\t\t\t   textInputPlaceholder:TXTLS(@\"Notifications[do4-2e]\")];\n\n\tUNNotificationCategory *pmCategory =\n\t[UNNotificationCategory categoryWithIdentifier:TXNotificationCategoryIdentifierPrivateMessage\n\t\t\t\t\t\t\t\t\t\t   actions:@[pmReplyAction]\n\t\t\t\t\t\t\t\t intentIdentifiers:@[]\n\t\t\t\t\t\t\t\t\t\t   options:UNNotificationCategoryOptionCustomDismissAction];\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\tUNNotificationAction *lmMoreInfoAction =\n\t[UNNotificationAction actionWithIdentifier:TXNotificationActionIdentifierLicenseManagerMoreInfo\n\t\t\t\t\t\t\t\t\t\t title:TXTLS(@\"TLOLicenseManager[b8b-sg]\")\n\t\t\t\t\t\t\t\t\t   options:0];\n\n\tUNNotificationCategory *lmCategory =\n\t[UNNotificationCategory categoryWithIdentifier:TXNotificationCategoryIdentifierLicenseManager\n\t\t\t\t\t\t\t\t\t\t   actions:@[lmMoreInfoAction]\n\t\t\t\t\t\t\t\t intentIdentifiers:@[]\n\t\t\t\t\t\t\t\t\t\t   options:UNNotificationCategoryOptionCustomDismissAction];\n\n\tNSSet *categories = [NSSet setWithObjects:ftCategory, pmCategory, lmCategory, nil];\n#else\n\tNSSet *categories = [NSSet setWithObjects:ftCategory, pmCategory, nil];\n#endif\n\n\treturn categories;\n}\n\n- (void)registerCategories\n{\n\tNSSet *categories = [self categoriesToRegister];\n\n\t[RZUserNotificationCenter() setNotificationCategories:categories];\n}\n\n- (void)mainWindowSelectionChanged:(NSNotification *)notification\n{\n\tTVCMainWindow *mainWindow = mainWindow();\n\n\t[self dismissNotificationsForChannel:mainWindow.selectedChannel\n\t\t\t\t\t\t\t\tonClient:mainWindow.selectedClient];\n}\n\n- (NSString *)titleForEvent:(TXNotificationType)event\n{\n#define _df(key, num)\t\t\tcase (key): { return TXTLS((num)); }\n\n\tswitch (event) {\n\t\t\t_df(TXNotificationTypeAddressBookMatch, @\"Notifications[kx3-xk]\")\n\t\t\t_df(TXNotificationTypeChannelMessage, @\"Notifications[qnz-k4]\")\n\t\t\t_df(TXNotificationTypeChannelNotice, @\"Notifications[vuq-jp]\")\n\t\t\t_df(TXNotificationTypeConnect, @\"Notifications[4lr-ej]\")\n\t\t\t_df(TXNotificationTypeDisconnect, @\"Notifications[wjv-yb]\")\n\t\t\t_df(TXNotificationTypeInvite, @\"Notifications[eiu-8q]\")\n\t\t\t_df(TXNotificationTypeKick, @\"Notifications[2nk-lg]\")\n\t\t\t_df(TXNotificationTypeNewPrivateMessage, @\"Notifications[5yi-gu]\")\n\t\t\t_df(TXNotificationTypePrivateMessage, @\"Notifications[00b-nx]\")\n\t\t\t_df(TXNotificationTypePrivateNotice, @\"Notifications[nhz-io]\")\n\t\t\t_df(TXNotificationTypeHighlight, @\"Notifications[cs4-x9]\")\n\t\t\t_df(TXNotificationTypeFileTransferSendSuccessful, @\"Notifications[0x2-3h]\")\n\t\t\t_df(TXNotificationTypeFileTransferReceiveSuccessful, @\"Notifications[qle-7v]\")\n\t\t\t_df(TXNotificationTypeFileTransferSendFailed, @\"Notifications[sc0-1n]\")\n\t\t\t_df(TXNotificationTypeFileTransferReceiveFailed, @\"Notifications[we9-1b]\")\n\t\t\t_df(TXNotificationTypeFileTransferReceiveRequested, @\"Notifications[st5-0n]\")\n\t\t\t_df(TXNotificationTypeUserJoined, @\"Notifications[25q-af]\")\n\t\t\t_df(TXNotificationTypeUserParted, @\"Notifications[k3s-by]\")\n\t\t\t_df(TXNotificationTypeUserDisconnected, @\"Notifications[0fo-bt]\")\n\t}\n\n#undef _df\n\n\treturn nil;\n}\n\n- (void)notify:(TXNotificationType)eventType title:(nullable NSString *)eventTitle description:(nullable NSString *)eventDescription userInfo:(nullable NSDictionary<NSString *,id> *)eventContext\n{\n\tswitch (eventType) {\n\t\tcase TXNotificationTypeHighlight:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[qka-f3]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeNewPrivateMessage:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[ltn-hf]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeChannelMessage:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[ep5-de]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeChannelNotice:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[chi-km]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypePrivateMessage:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[69i-dy]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypePrivateNotice:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[7hn-dg]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeKick:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[u30-ia]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeInvite:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[g4s-cq]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeConnect:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[mo1-vn]\", eventTitle);\n\n\t\t\teventDescription = TXTLS(@\"Notifications[88k-kl]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeDisconnect:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[7xe-ig]\", eventTitle);\n\n\t\t\teventDescription = TXTLS(@\"Notifications[bif-2c]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeAddressBookMatch:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[niq-32]\");\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferSendSuccessful:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[l5y-sx]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveSuccessful:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[hc9-7n]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferSendFailed:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[het-vh]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveFailed:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[hm4-ze]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeFileTransferReceiveRequested:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[nqz-7v]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserJoined:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[keq-ts]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserParted:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[im4-p0]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNotificationTypeUserDisconnected:\n\t\t{\n\t\t\teventTitle = TXTLS(@\"Notifications[20x-32]\", eventTitle);\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif ([TPCPreferences removeAllFormatting] == NO) {\n\t\teventDescription = eventDescription.stripIRCEffects;\n\t}\n\n\tNSString *categoryIdentifier = nil;\n\n\tif (eventType == TXNotificationTypeFileTransferReceiveRequested) {\n\t\tcategoryIdentifier = TXNotificationCategoryIdentifierFileTransfer;\n\t} else if (eventType == TXNotificationTypeNewPrivateMessage ||\n\t\t\t   eventType == TXNotificationTypePrivateMessage)\n\t{\n\t\tcategoryIdentifier = TXNotificationCategoryIdentifierPrivateMessage;\n\t}\n\n\tNSString *clientId = eventContext[TXNotificationUserInfoClientIdentifierKey];\n\tNSString *channelId = eventContext[TXNotificationUserInfoChannelIdentifierKey];\n\n\tNSString *threadIdentifier = [self threadIdentifierForClient:clientId channel:channelId];\n\n\t[self scheduleNotificationWithTitle:eventTitle\n\t\t\t\t\t\t\t\tmessage:eventDescription\n\t\t\t\t\t\t\t   userInfo:eventContext\n\t\t\t\t notificationIdentifier:nil\n\t\t\t\t\t   threadIdentifier:threadIdentifier\n\t\t\t\t\t categoryIdentifier:categoryIdentifier];\n}\n\n- (nullable NSString *)threadIdentifierForClient:(nullable NSString *)clientIdentifier channel:(nullable NSString *)channelIdentifier\n{\n\tif (clientIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\tif (channelIdentifier) {\n\t\treturn [clientIdentifier stringByAppendingFormat:@\"-%@\", channelIdentifier];\n\t}\n\n\treturn clientIdentifier;\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t userInfo:(nullable NSDictionary<NSString *, id> *)userInfo\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t   userInfo:userInfo\n\t\t\t\t notificationIdentifier:nil\n\t\t\t\t\t   threadIdentifier:nil\n\t\t\t\t\t categoryIdentifier:nil];\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t userInfo:(nullable NSDictionary<NSString *, id> *)userInfo\n\t\t\t\t\t threadIdentifier:(NSString *)threadIdentifier\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(threadIdentifier != nil);\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t   userInfo:userInfo\n\t\t\t\t notificationIdentifier:nil\n\t\t\t\t\t   threadIdentifier:threadIdentifier\n\t\t\t\t\t categoryIdentifier:nil];\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t   forChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(channel != nil);\n\n\tIRCClient *client = channel.associatedClient;\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t forChannel:channel\n\t\t\t\t\t\t\t   onClient:client];\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t onClient:(IRCClient *)client\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(client != nil);\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t forChannel:nil\n\t\t\t\t\t\t\t   onClient:client];\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t   forChannel:(nullable IRCChannel *)channel\n\t\t\t\t\t\t\t onClient:(IRCClient *)client\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(client != nil);\n\n\tNSString *clientId = client.uniqueIdentifier;\n\tNSString *channelId = channel.uniqueIdentifier;\n\n\tNSString *threadIdentifier = [self threadIdentifierForClient:clientId channel:channelId];\n\n\tNSDictionary *userInfo = nil;\n\n\tif (channelId) {\n\t\tuserInfo = @{TXNotificationUserInfoClientIdentifierKey : clientId,\n\t\t\t\t\t TXNotificationUserInfoChannelIdentifierKey : channelId};\n\t} else {\n\t\tuserInfo = @{TXNotificationUserInfoClientIdentifierKey : clientId};\n\t}\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t   userInfo:userInfo\n\t\t\t\t notificationIdentifier:nil\n\t\t\t\t\t   threadIdentifier:threadIdentifier\n\t\t\t\t\t categoryIdentifier:nil];\n}\n\n- (void)scheduleNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t  message:(NSString *)message\n\t\t\t\t\t\t\t userInfo:(nullable NSDictionary<NSString *, id> *)userInfo\n\t\t\t   notificationIdentifier:(nullable NSString *)notificationIdentifier\n\t\t\t\t\t threadIdentifier:(nullable NSString *)threadIdentifier\n\t\t\t\t   categoryIdentifier:(nullable NSString *)categoryIdentifier\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\n\tUNMutableNotificationContent *notificationContent = [UNMutableNotificationContent new];\n\n\tnotificationContent.title = title;\n\tnotificationContent.body = message;\n\n\tif (userInfo) {\n\t\tnotificationContent.userInfo = userInfo;\n\t}\n\n\tif (categoryIdentifier) {\n\t\tnotificationContent.categoryIdentifier = categoryIdentifier;\n\t}\n\n\tif (threadIdentifier) {\n\t\tnotificationContent.threadIdentifier = threadIdentifier;\n\t}\n\n\t/* The notification identifier should be unique to the specific notification\n\t because otherwise the system will replace existing notifications of the\n\t same identifier. That's not a bad behavior. Just not one we want. */\n\t/* Textual will format the identifier as such:\n\t TXNotification[-<clientID>[-<channelId>]]-<eventTitle hash>-<eventDescription hash> */\n\tif (notificationIdentifier == nil) {\n\t\tnotificationIdentifier = [NSString stringWithFormat:@\"TXNotification-%@-%ld-%ld\",\n\t\t\t((threadIdentifier) ?: @\"<No Thread>\"), title.hash, message.hash];;\n\t}\n\n\t[self scheduleNotificationWithContent:notificationContent\n\t\t\t\t\t\t\t   identifier:notificationIdentifier];\n}\n\n- (void)scheduleNotificationWithContent:(UNNotificationContent *)notificationContent identifier:(nullable NSString *)notificationIdentifier\n{\n\tNSParameterAssert(notificationContent != nil);\n\tNSParameterAssert(notificationIdentifier != nil);\n\n\tUNNotificationRequest *notificationRequest =\n\t[UNNotificationRequest requestWithIdentifier:notificationIdentifier\n\t\t\t\t\t\t\t\t\t\t content:notificationContent\n\t\t\t\t\t\t\t\t\t\t trigger:nil];\n\n\t[self scheduleNotificationRequest:notificationRequest];\n}\n\n- (void)scheduleNotificationRequest:(UNNotificationRequest *)request\n{\n\tNSParameterAssert(request != nil);\n\n\t[RZUserNotificationCenter() addNotificationRequest:request\n\t\t\t\t\t\t\t\t withCompletionHandler:^(NSError * _Nullable error) {\n\t\tif (error) {\n\t\t\tLogToConsoleError(\"Failed to post notification '%{private}@': %{public}@\",\n\t\t\t\trequest.content.title, error.localizedDescription);\n\t\t}\n\t}];\n}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)scheduleLicenseManagerNotificationWithTitle:(NSString *)title\n\t\t\t\t\t\t\t\t\t\t\tmessage:(NSString *)message\n{\n\tNSParameterAssert(title != nil);\n\tNSParameterAssert(message != nil);\n\n\t[self scheduleNotificationWithTitle:title\n\t\t\t\t\t\t\t\tmessage:message\n\t\t\t\t\t\t\t   userInfo:nil\n\t\t\t\t notificationIdentifier:nil\n\t\t\t\t\t   threadIdentifier:nil\n\t\t\t\t\t categoryIdentifier:TXNotificationCategoryIdentifierLicenseManager];\n}\n#endif\n\n#pragma mark -\n#pragma mark Notification Center Delegate\n\n- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification\n{\n\t[menuController() showNotificationPreferences:nil];\n}\n\n- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler\n{\n\tcompletionHandler(UNNotificationPresentationOptionList |\n\t\t\t\t\t  UNNotificationPresentationOptionBanner);\n}\n\n- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler\n{\n\tNSString *message = nil;\n\n\tif ([response isKindOfClass:[UNTextInputNotificationResponse class]]) {\n\t\tmessage = [((UNTextInputNotificationResponse *)response) userText];\n\t}\n\n\t/* Now that is what you call chaining... */\n\tNSDictionary *userInfo = response.notification.request.content.userInfo;\n\n\t[self notificationResponseReceived:response context:userInfo withReplyMessage:message];\n}\n\n- (void)dismissNotificationsForChannel:(nullable IRCChannel *)channel onClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\tNSString *clientId = client.uniqueIdentifier;\n\tNSString *channelId = channel.uniqueIdentifier;\n\n\tLogToConsoleDebug(\"Dismissing notifications for '%{public}@' on '%{public}@'\",\n\t\t((channelId) ?: @\"<No Channel>\"), clientId);\n\n\t/* Pending Notifications */\n\t[RZUserNotificationCenter() getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> *requests) {\n\t\tNSMutableArray<NSString *> *notificationIdentifiers = [NSMutableArray array];\n\n\t\t[requests enumerateObjectsUsingBlock:^(UNNotificationRequest *request, NSUInteger index, BOOL *stop) {\n\t\t\tif ([self isNotificationRequest:request inScopeOfChannel:channel onClient:client]) {\n\t\t\t\t[notificationIdentifiers addObject:request.identifier];\n\t\t\t}\n\t\t}];\n\n\t\tif (notificationIdentifiers.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t[RZUserNotificationCenter() removePendingNotificationRequestsWithIdentifiers:notificationIdentifiers];\n\n\t\tLogToConsoleDebug(\"Dismissed %{public}ld pending notifications\",\n\t\t\tnotificationIdentifiers.count);\n\t}];\n\n\t/* Delivered Notifications */\n\t[RZUserNotificationCenter() getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> *notifications) {\n\t\tNSMutableArray<NSString *> *notificationIdentifiers = [NSMutableArray array];\n\n\t\t[notifications enumerateObjectsUsingBlock:^(UNNotification *notification, NSUInteger index, BOOL *stop) {\n\t\t\tUNNotificationRequest *request = notification.request;\n\n\t\t\tif ([self isNotificationRequest:request inScopeOfChannel:channel onClient:client]) {\n\t\t\t\t[notificationIdentifiers addObject:request.identifier];\n\t\t\t}\n\t\t}];\n\n\t\tif (notificationIdentifiers.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t[RZUserNotificationCenter() removeDeliveredNotificationsWithIdentifiers:notificationIdentifiers];\n\n\t\tLogToConsoleDebug(\"Dismissed %{public}ld delivered notifications\",\n\t\t\tnotificationIdentifiers.count);\n\t}];\n}\n\n- (BOOL)isNotificationRequest:(UNNotificationRequest *)request inScopeOfChannel:(nullable IRCChannel *)channel onClient:(IRCClient *)client\n{\n\tNSParameterAssert(request != nil);\n\tNSParameterAssert(client != nil);\n\n\tNSString *clientIdLeft = client.uniqueIdentifier;\n\tNSString *channelIdLeft = channel.uniqueIdentifier;\n\n\tNSDictionary *userInfo = request.content.userInfo;\n\n\tNSString *clientIdRight = userInfo[TXNotificationUserInfoClientIdentifierKey];\n\tNSString *channelIdRight = userInfo[TXNotificationUserInfoChannelIdentifierKey];\n\n\t/* NSObjectsAreEqual() checks for equality of nil so it is valid\n\t if channel ID left and right are both nil. */\n\treturn (NSObjectsAreEqual(clientIdLeft, clientIdRight) &&\n\t\t\tNSObjectsAreEqual(channelIdLeft, channelIdRight));\n}\n\n#pragma mark -\n#pragma mark Notification Callback\n\n- (void)notificationResponseReceived:(UNNotificationResponse *)response context:(NSDictionary<NSString *, id> *)context withReplyMessage:(nullable NSString *)message\n{\n\tNSParameterAssert(context != nil);\n\n\tNSString *actionIdentifier = [response actionIdentifier];\n\n\tif ([actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier]) {\n\t\tLogToConsoleDebug(\"Dismissed notification: '%{private}@'\", response);\n\n\t\treturn;\n\t}\n\n\t/* If we ever expand beyond a few different actions, then revisit\n\t this so that we aren't just declaring a bunch of booleans.\n\t This was just the easier solution at the time. */\n\tBOOL isFileTransferAction = [actionIdentifier isEqualToString:TXNotificationActionIdentifierFileTransferAccept];\n\tBOOL isPrivateMessageAction = [actionIdentifier isEqualToString:TXNotificationActionIdentifierPrivateMessageReply];\n\tBOOL isLicenseManagerAction = NO;\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\tif ([actionIdentifier isEqualToString:TXNotificationActionIdentifierLicenseManagerMoreInfo]) {\n\t\tisLicenseManagerAction = YES;\n\t}\n#endif\n\n\tBOOL activateApp \t= (isPrivateMessageAction == NO);\n\tBOOL keyMainWindow \t= (isPrivateMessageAction == NO &&\n\t\t\t\t\t\t   isFileTransferAction == NO &&\n\t\t\t\t\t\t   isLicenseManagerAction == NO);\n\n\tif (activateApp) {\n\t\t[NSApp activateIgnoringOtherApps:YES];\n\t}\n\n\tif (keyMainWindow) {\n\t\t[mainWindow() makeKeyAndOrderFront:nil];\n\t}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\t/* Handle a notification that was clicked related to a warnings about\n\t the trial of Textual preparing to expire. */\n\tif (isLicenseManagerAction)\n\t{\n\t\t[menuController() manageLicense:nil];\n\t}\n\telse\n#endif\n\n\t/* Handle file transfer notifications allowing the user to start a\n\t file transfer directly through the notification's action button. */\n\tif (isFileTransferAction)\n\t{\n\t\t[[TXSharedApplication sharedFileTransferDialog] show:YES restorePosition:NO];\n\n\t\tNSInteger alertType = [context integerForKey:@\"fileTransferNotificationType\"];\n\n\t\tif (alertType != TXNotificationTypeFileTransferReceiveRequested) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *uniqueIdentifier = context[@\"fileTransferUniqueIdentifier\"];\n\n\t\tTDCFileTransferDialogTransferController *fileTransfer = [[TXSharedApplication sharedFileTransferDialog] fileTransferWithUniqueIdentifier:uniqueIdentifier];\n\n\t\tif (fileTransfer == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tTDCFileTransferDialogTransferStatus transferStatus = fileTransfer.transferStatus;\n\n\t\tif (transferStatus != TDCFileTransferDialogTransferStatusStopped) {\n\t\t\treturn;\n\t\t}\n\n\t\t[fileTransfer openWithPathOrUserDownloads];\n\t}\n\n\t/* Handle all other IRC related notifications. */\n\telse\n\t{\n\t\tNSString *clientId = context[TXNotificationUserInfoClientIdentifierKey];\n\t\tNSString *channelId = context[TXNotificationUserInfoChannelIdentifierKey];\n\n\t\tif (clientId == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tIRCClient *client = nil;\n\t\tIRCChannel *channel = nil;\n\n\t\tif (channelId) {\n\t\t\tchannel = [worldController() findChannelWithId:channelId onClientWithId:clientId];\n\t\t} else {\n\t\t\tclient = [worldController() findClientWithId:clientId];\n\t\t}\n\n\t\tif (channel) {\n\t\t\t[mainWindow() select:channel];\n\t\t} else if (client) {\n\t\t\t[mainWindow() select:client];\n\t\t}\n\n\t\tif (channel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (message.length == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t[channel.associatedClient inputText:message destination:channel];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TLONotificationController (Preferences)\n\n- (nullable NSString *)soundForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSString *channelValue = [channel.config soundForEvent:event];\n\n\t\tif (channelValue != nil) {\n\t\t\treturn channelValue;\n\t\t}\n\t}\n\n\treturn [TPCPreferences soundForEvent:event];\n}\n\n- (BOOL)speakEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSUInteger channelValue = [channel.config speakEvent:event];\n\n\t\tif (channelValue != NSControlStateValueMixed) {\n\t\t\treturn (channelValue == NSControlStateValueOn);\n\t\t}\n\t}\n\n\treturn [TPCPreferences speakEvent:event];\n}\n\n- (BOOL)notificationEnabledForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSUInteger channelValue = [channel.config notificationEnabledForEvent:event];\n\n\t\tif (channelValue != NSControlStateValueMixed) {\n\t\t\treturn (channelValue == NSControlStateValueOn);\n\t\t}\n\t}\n\n\treturn [TPCPreferences notificationEnabledForEvent:event];\n}\n\n- (BOOL)disabledWhileAwayForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSUInteger channelValue = [channel.config disabledWhileAwayForEvent:event];\n\n\t\tif (channelValue != NSControlStateValueMixed) {\n\t\t\treturn (channelValue == NSControlStateValueOn);\n\t\t}\n\t}\n\n\treturn [TPCPreferences disabledWhileAwayForEvent:event];\n}\n\n- (BOOL)bounceDockIconForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSUInteger channelValue = [channel.config bounceDockIconForEvent:event];\n\n\t\tif (channelValue != NSControlStateValueMixed) {\n\t\t\treturn (channelValue == NSControlStateValueOn);\n\t\t}\n\t}\n\n\treturn [TPCPreferences bounceDockIconForEvent:event];\n}\n\n- (BOOL)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event inChannel:(nullable IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSUInteger channelValue = [channel.config bounceDockIconRepeatedlyForEvent:event];\n\n\t\tif (channelValue != NSControlStateValueMixed) {\n\t\t\treturn (channelValue == NSControlStateValueOn);\n\t\t}\n\t}\n\n\treturn [TPCPreferences bounceDockIconRepeatedlyForEvent:event];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOSoundPlayer.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <AudioToolbox/AudioToolbox.h>\n\n#import \"TLONotificationConfigurationPrivate.h\"\n#import \"TLOSoundPlayer.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TLOSoundPlayer\n\n+ (NSDictionary<NSString *, NSString *> *)soundFilesAtPath:(NSString *)path\n{\n\tNSMutableDictionary<NSString *, NSString *> *resultData = [NSMutableDictionary dictionary];\n\n\tNSArray *files = [RZFileManager() contentsOfDirectoryAtPath:path error:NULL];\n\n\tfor (NSString *file in files) {\n\t\tNSString *filePath = [path stringByAppendingPathComponent:file];\n\n\t\tNSString *fileWithoutExtension = file.stringByDeletingPathExtension;\n\n\t\tresultData[fileWithoutExtension] = filePath;\n\t}\n\n\treturn resultData;\n}\n\n+ (nullable NSDictionary<NSString *, NSString *> *)systemAlertSoundFiles\n{\n\tNSArray *folders = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES);\n\n\tif (folders.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *folder = [folders[0] stringByAppendingPathComponent:@\"/Sounds/\"];\n\n\treturn [self soundFilesAtPath:folder];\n}\n\n+ (nullable NSDictionary<NSString *, NSString *> *)systemLibrarySoundFiles\n{\n\tNSArray *folders = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSLocalDomainMask, YES);\n\n\tif (folders.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *folder = [folders[0] stringByAppendingPathComponent:@\"/Sounds/\"];\n\n\treturn [self soundFilesAtPath:folder];\n}\n\n+ (nullable NSDictionary<NSString *, NSString *> *)userLibrarySoundFiles\n{\n\tNSArray *folders = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);\n\n\tif (folders.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *folder = [folders[0] stringByAppendingPathComponent:@\"/Sounds/\"];\n\n\treturn [self soundFilesAtPath:folder];\n}\n\n+ (void)doesSoundFileDictionary:(NSDictionary<NSString *, NSString *> *)fileList containName:(NSString *)name returnedPath:(NSString **)path\n{\n\tNSString *filePath = fileList[name];\n\n\tif (filePath == nil) {\n\t\treturn;\n\t}\n\n\tNSString *fileExtension = filePath.pathExtension;\n\n\tCFStringRef fileUTI = UTTypeCreatePreferredIdentifierForTag(\n\t\tkUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);\n\n\tif (UTTypeConformsTo(fileUTI, kUTTypeAudio) == false) {\n\t\tLogToConsoleDebug(\"File is not audio file: '%{public}@'\", filePath.standardizedTildePath);\n\n\t\tCFRelease(fileUTI);\n\n\t\treturn;\n\t}\n\n\tCFRelease(fileUTI);\n\n\tif ( path) {\n\t\t*path = filePath;\n\t}\n}\n\n+ (SystemSoundID)alertSoundNamed:(NSString *)name\n{\n\tNSString *soundPath = nil;\n\n\tNSDictionary *soundFiles = [self userLibrarySoundFiles];\n\n\t[self doesSoundFileDictionary:soundFiles containName:name returnedPath:&soundPath];\n\n\tif (soundPath == nil) {\n\t\tsoundFiles = [self systemLibrarySoundFiles];\n\n\t\t[self doesSoundFileDictionary:soundFiles containName:name returnedPath:&soundPath];\n\t}\n\n\tif (soundPath == nil) {\n\t\tsoundFiles = [self systemAlertSoundFiles];\n\n\t\t[self doesSoundFileDictionary:soundFiles containName:name returnedPath:&soundPath];\n\t}\n\n\tif (soundPath == nil) {\n\t\treturn 0;\n\t}\n\n\tNSURL *soundPathURL = [NSURL fileURLWithPath:soundPath];\n\n\tSystemSoundID soundID;\n\n\tOSStatus soundLoadError = AudioServicesCreateSystemSoundID((__bridge CFURLRef)(soundPathURL), &soundID);\n\n\tif (soundLoadError == noErr) {\n\t\treturn soundID;\n\t}\n\n\tLogToConsoleError(\"Returned error code %{public}i when loading file at path: %{public}@\",\n\t\tsoundLoadError, soundPathURL.standardizedTildePath);\n\n\treturn 0;\n}\n\n+ (void)playAlertSound:(NSString *)name\n{\n\tNSParameterAssert(name != nil);\n\n\tif ([name isEqualToString:TXNoAlertSoundPreferenceValue]) {\n\t\treturn;\n\t}\n\n\tif ([name isEqualToString:@\"Beep\"]) {\n\t\tNSBeep();\n\n\t\treturn;\n\t}\n\n\tSystemSoundID soundID = [self alertSoundNamed:name];\n\n\tif (soundID) {\n\t\tAudioServicesPlayAlertSound(soundID);\n\n\t\t// AudioServicesDisposeSystemSoundID(soundID);\n\t} else {\n\t\tLogToConsoleError(\"Error: Unable to locate sound '%{public}@'\", name);\n\t}\n}\n\n+ (NSArray<NSString *> *)uniqueListOfSounds\n{\n\tNSMutableArray<NSString *> *sounds = [NSMutableArray array];\n\n\t[sounds addObject:@\"Beep\"]; // For NSBeep()\n\n\tfor (NSString *sound in [self systemAlertSoundFiles]) {\n\t\tif ([sounds containsObject:sound] == NO) {\n\t\t\t[sounds addObject:sound];\n\t\t}\n\t}\n\n\tfor (NSString *sound in [self systemLibrarySoundFiles]) {\n\t\tif ([sounds containsObject:sound] == NO) {\n\t\t\t[sounds addObject:sound];\n\t\t}\n\t}\n\n\tfor (NSString *sound in [self userLibrarySoundFiles]) {\n\t\tif ([sounds containsObject:sound] == NO) {\n\t\t\t[sounds addObject:sound];\n\t\t}\n\t}\n\n\t[sounds sortUsingSelector:@selector(caseInsensitiveCompare:)];\n\n\treturn [sounds copy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOSpeechSynthesizer.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientPrivate.h\"\n#import \"TLOSpokenNotificationPrivate.h\"\n#import \"TLOSpeechSynthesizerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOSpeechSynthesizer ()\n@property (nonatomic, strong) NSSpeechSynthesizer *speechSynthesizer;\n@property (nonatomic, strong) NSMutableArray *itemsToBeSpoken;\n@property (nonatomic, assign) BOOL isWaitingForSystemToStopSpeaking;\n@end\n\n@implementation TLOSpeechSynthesizer\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.itemsToBeSpoken = [NSMutableArray array];\n\n\tself.speechSynthesizer = [NSSpeechSynthesizer new];\n\tself.speechSynthesizer.delegate = (id)self;\n\n\tself.isStopped = NO;\n}\n\n- (void)dealloc\n{\n\tself.speechSynthesizer.delegate = nil;\n}\n\n#pragma mark -\n#pragma mark Public API\n\n- (void)speak:(id)object\n{\n\tNSParameterAssert(object != nil);\n\n\tif (self.isStopped) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.itemsToBeSpoken) {\n\t\t[self.itemsToBeSpoken addObject:object];\n\t}\n\n\tif (self.isSpeaking == NO) {\n\t\t[self speakNextItem];\n\t}\n}\n\n- (void)speakNextItemWhenSystemFinishes\n{\n\t/* This method sleeps the thread for one second each pass then\n\t to check if another application on the system is speaking. */\n\twhile ([NSSpeechSynthesizer isAnyApplicationSpeaking]) {\n\t\t[NSThread sleepForTimeInterval:1.0];\n\t}\n\n\tself.isWaitingForSystemToStopSpeaking = NO;\n\n\t[self speakNextItem];\n}\n\n- (void)speakNextItem\n{\n\tif (self.isStopped) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.itemsToBeSpoken) {\n\t\tid nextMessage = self.itemsToBeSpoken.firstObject;\n\n\t\tif (nextMessage == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ([NSSpeechSynthesizer isAnyApplicationSpeaking]) {\n\t\t\tif (self.isWaitingForSystemToStopSpeaking == NO) {\n\t\t\t\tself.isWaitingForSystemToStopSpeaking = YES;\n\n\t\t\t\tXRPerformBlockAsynchronouslyOnGlobalQueueWithPriority(^{\n\t\t\t\t\t[self speakNextItemWhenSystemFinishes];\n\t\t\t\t}, DISPATCH_QUEUE_PRIORITY_LOW);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t[self.itemsToBeSpoken removeObjectAtIndex:0];\n\n\t\tif ([nextMessage isKindOfClass:[TLOSpokenNotification class]]) {\n\t\t\tnextMessage = [(IRCClient *)[nextMessage client] formatNotificationToSpeak:nextMessage];\n\n\t\t\t// Returning nil does not throw an assert so that the client can chose\n\t\t\t// to reject specific events for whatever reason it wants.\n\t\t\tif (nextMessage == nil) {\n\t\t\t\t[self speakNextItem];\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t[self.speechSynthesizer startSpeakingString:nextMessage];\n\t}\n}\n\n- (void)stopSpeakingAndMoveForward\n{\n\tif (self.isSpeaking == NO) {\n\t\treturn;\n\t}\n\n\t[self.speechSynthesizer stopSpeaking]; // Will call delegate to do next item\n}\n\n- (void)stopSpeakingIfSet\n{\n\tif (self.isSpeaking == NO || self.isStopped == NO) {\n\t\treturn;\n\t}\n\n\t[self.speechSynthesizer stopSpeaking];\n}\n\n- (BOOL)isSpeaking\n{\n\treturn self.speechSynthesizer.isSpeaking;\n}\n\n- (void)setIsStopped:(BOOL)isStopped\n{\n\tif (self->_isStopped != isStopped) {\n\t\tself->_isStopped = isStopped;\n\n\t\t[self stopSpeakingIfSet];\n\t}\n}\n\n- (void)clearQueue\n{\n\t@synchronized(self.itemsToBeSpoken) {\n\t\t[self.itemsToBeSpoken removeAllObjects];\n\t}\n}\n\n- (void)clearQueueForClient:(IRCClient *)client\n{\n\t@synchronized(self.itemsToBeSpoken) {\n\t\tNSIndexSet *indexesToRemove = [self.itemsToBeSpoken indexesOfObjectsPassingTest:^BOOL(id object, NSUInteger index, BOOL *stop) {\n\t\t\tif ([object isKindOfClass:[TLOSpokenNotification class]]) {\n\t\t\t\treturn ((IRCClient *)[object client] == client);\n\t\t\t}\n\n\t\t\treturn NO;\n\t\t}];\n\n\t\tif (indexesToRemove.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t[self.itemsToBeSpoken removeObjectsAtIndexes:indexesToRemove];\n\t}\n}\n\n#pragma mark -\n#pragma mark Delegate Callback\n\n- (void)speechSynthesizer:(NSSpeechSynthesizer *)sender didFinishSpeaking:(BOOL)finishedSpeaking\n{\n\t[self speakNextItem];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOSpokenNotification.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TLOSpokenNotificationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOSpokenNotification ()\n@property (nonatomic, weak, null_unspecified, readwrite) IRCClient *client;\n@property (nonatomic, weak, null_unspecified, readwrite) IRCChannel *channel;\n@property (nonatomic, copy, null_unspecified, readwrite) NSString *nickname;\n@property (nonatomic, copy, null_unspecified, readwrite) NSString *text;\n@property (nonatomic, readwrite) TVCLogLineType lineType;\n@property (nonatomic, readwrite) TXNotificationType notificationType;\n@end\n\n@implementation TLOSpokenNotification\n\n- (instancetype)initWithNotification:(TXNotificationType)notificationType\n\t\t\t\t\t\t\tlineType:(TVCLogLineType)lineType\n\t\t\t\t\t\t\t  target:(null_unspecified IRCTreeItem *)target\n\t\t\t\t\t\t\tnickname:(null_unspecified NSString *)nickname\n\t\t\t\t\t\t\t\ttext:(null_unspecified NSString *)text\n{\n\tif ((self = [super init])) {\n\t\tself.notificationType = notificationType;\n\n\t\tself.lineType = lineType;\n\n\t\tif (target.isClient) {\n\t\t\tself.client = (IRCClient *)target;\n\t\t} else {\n\t\t\tself.client = (IRCClient *)target.associatedClient;\n\t\t\tself.channel = (IRCChannel *)target;\n\t\t}\n\n\t\tself.nickname = nickname;\n\n\t\tself.text = text;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Library/TLOpenLink.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n* Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n@objc(TLOpenLink)\npublic class OpenLink: NSObject\n{\n\t@objc(open:inBackground:)\n\tpublic static func open(url: URL, inBackground: Bool = TPCPreferences.openBrowserInBackground())\n\t{\n\t\tif inBackground {\n\t\t\t/* User should not be clicking links frequently enough that\n\t\t\t we need to worry about making the configuration static. */\n\t\t\tlet configuration = NSWorkspace.OpenConfiguration();\n\t\t\tconfiguration.activates = false\n\n\t\t\tNSWorkspace.shared.open(url, configuration: configuration)\n\n\t\t\treturn\n\t\t}\n\n\t\tNSWorkspace.shared.open(url)\n\t}\n\n\t@objc(openWithString:inBackground:)\n\tpublic static func open(string: String, inBackground: Bool = TPCPreferences.openBrowserInBackground())\n\t{\n\t\tguard let urlToOpen = URL(string: string) else {\n\t\t\treturn\n\t\t}\n\n\t\topen(url: urlToOpen, inBackground: inBackground)\n\t}\n}\n\nextension OpenLink {\n\t@objc(open:)\n\tpublic static func openBridged(url: URL)\n\t{\n\t\topen(url: url)\n\t}\n\n\t@objc(openWithString:)\n\tpublic static func openBridged(string: String)\n\t{\n\t\topen(string: string)\n\t}\n}\n"
  },
  {
    "path": "Sources/App/Classes/Others/main.m",
    "content": "\n#import \"TXApplicationPrivate.h\"\n\nint main(int argc, const char *argv[])\n{\n\t@autoreleasepool {\n#ifndef DEBUG\n\t\tif ([TXApplication checkForOtherCopiesOfTextualRunning] == NO) {\n\t\t\texit(0);\n\t\t}\n#endif\n\n\t\tNSApplicationMain(argc, argv);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCApplicationInfo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BuildConfig.h\"\n\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCApplicationInfoPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPCApplicationInfo\n\n+ (NSString *)applicationName\n{\n\treturn TXBundleBuildProductName;\n}\n\n+ (NSString *)applicationNameWithoutVersion\n{\n\tNSString *applicationName = TXBundleBuildProductName;\n\n\tNSInteger spacePosition = [applicationName stringPosition:@\" \"];\n\n\tif (spacePosition > 0) {\n\t\treturn [applicationName substringToIndex:spacePosition];\n\t} else {\n\t\treturn applicationName;\n\t}\n}\n\n+ (NSString *)applicationVersion\n{\n\treturn TXBundleBuildVersion;\n}\n\n+ (NSString *)applicationVersionShort\n{\n\treturn TXBundleBuildVersionShort;\n}\n\n+ (int)applicationProcessID\n{\n\treturn RZProcessInfo().processIdentifier;\n}\n\n+ (NSString *)applicationBundleIdentifier\n{\n\treturn TXBundleBuildProductIdentifier;\n}\n\n+ (NSString *)applicationBuildScheme\n{\n\treturn TXBundleBuildScheme;\n}\n\n+ (NSDictionary<NSString *, id> *)applicationInfoPlist\n{\n\treturn RZMainBundle().infoDictionary;\n}\n\n+ (BOOL)sandboxEnabled\n{\n#if TEXTUAL_BUILT_INSIDE_SANDBOX == 1\n\treturn YES;\n#else\n\treturn NO;\n#endif\n}\n\n+ (nullable NSDate *)applicationLaunchDate\n{\n\tNSRunningApplication *runningApp = [NSRunningApplication currentApplication];\n\n\treturn runningApp.launchDate;\n}\n\n+ (NSTimeInterval)timeIntervalSinceApplicationLaunch\n{\n\tNSDate *launchDate = [self applicationLaunchDate];\n\n\tif (launchDate == nil) {\n\t\treturn 0;\n\t}\n\n\treturn (launchDate.timeIntervalSinceNow * (-1));\n}\n\n+ (NSTimeInterval)timeIntervalSinceApplicationInstall\n{\n\tNSTimeInterval runTime = [self timeIntervalSinceApplicationLaunch];\n\n\tNSTimeInterval runTimeTotal = [RZUserDefaults() doubleForKey:@\"TXRunTime\"];\n\n\treturn (runTimeTotal + runTime);\n}\n\n+ (void)saveTimeIntervalSinceApplicationInstall\n{\n\tNSTimeInterval timeInterval = [self timeIntervalSinceApplicationInstall];\n\n\t[RZUserDefaults() setDouble:timeInterval forKey:@\"TXRunTime\"];\n}\n\n+ (NSUInteger)applicationRunCount\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"TXRunCount\"];\n}\n\n+ (void)incrementApplicationRunCount\n{\n\tNSUInteger runCount = ([self applicationRunCount] + 1);\n\n\t[RZUserDefaults() setUnsignedInteger:runCount forKey:@\"TXRunCount\"];\n}\n\n+ (NSTimeInterval)applicationBirthday\n{\n\t/* The reference date is the date & time of the first commit to the\n\t Textual repo. Textual existed before then, of course, but the date\n\t will remain as the official reference date for its birthday. */\n\t/* The date decodes to July 23, 2010 03:53:00 AM */\n\n\treturn 1279871580.000000;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCPathInfo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BuildConfig.h\"\n\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCPathInfoPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPCPathInfo\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (void)_createDirectoryAtPath:(NSString *)directoryPath\n{\n\tNSParameterAssert(directoryPath != nil);\n\n\tif ([RZFileManager() fileExistsAtPath:directoryPath]) {\n\t\treturn;\n\t}\n\n\tNSError *createDirectoryError = nil;\n\n\tif ([RZFileManager() createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&createDirectoryError] == NO) {\n\t\tLogToConsoleError(\"Failed to create directory at path: '%{public}@' - %{public}@\",\n\t\t\tdirectoryPath.standardizedTildePath, createDirectoryError.localizedDescription);\n\t}\n}\n\n+ (void)_createDirectoryAtURL:(NSURL *)directoryURL\n{\n\tNSParameterAssert(directoryURL != nil);\n\n\tif ([RZFileManager() fileExistsAtURL:directoryURL]) {\n\t\treturn;\n\t}\n\n\tNSError *createDirectoryError = nil;\n\n\tif ([RZFileManager() createDirectoryAtURL:directoryURL withIntermediateDirectories:YES attributes:nil error:&createDirectoryError] == NO) {\n\t\tLogToConsoleError(\"Failed to create directory at path: '%{public}@' - %{public}@\",\n\t\t\tdirectoryURL.standardizedTildePath, createDirectoryError.localizedDescription);\n\t}\n}\n\n#pragma mark -\n#pragma mark Application Specific\n\n+ (NSString *)applicationBundle\n{\n\treturn RZMainBundle().bundlePath;\n}\n\n+ (NSURL *)applicationBundleURL\n{\n\treturn RZMainBundle().bundleURL;\n}\n\n+ (NSString *)applicationResources\n{\n\treturn RZMainBundle().resourcePath;\n}\n\n+ (NSURL *)applicationResourcesURL\n{\n\treturn RZMainBundle().resourceURL;\n}\n\n+ (nullable NSString *)applicationCaches\n{\n\tNSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);\n\n\tif (pathArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *endPath = [NSString stringWithFormat:@\"/%@/\", TXBundleBuildProductIdentifier];\n\n\tNSString *basePath = [pathArray.firstObject stringByAppendingPathComponent:endPath];\n\n\t[self _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n+ (nullable NSURL *)applicationCachesURL\n{\n\tNSString *sourcePath = self.applicationCaches;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (nullable NSString *)groupContainer\n{\n\tNSURL *sourceURL = self.groupContainerURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)groupContainerURL\n{\n\tNSURL *baseURL = [RZFileManager() containerURLForSecurityApplicationGroupIdentifier:TXBundleBuildGroupContainerIdentifier];\n\n\treturn baseURL;\n}\n\n+ (nullable NSString *)groupContainerApplicationCaches\n{\n\tNSURL *sourceURL = self.groupContainerApplicationCachesURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)groupContainerApplicationCachesURL\n{\n\tNSURL *sourceURL = self.groupContainerURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Library/Caches/\"];\n\n\t[self _createDirectoryAtURL:baseURL];\n\n\treturn baseURL;\n}\n\n+ (nullable NSString *)applicationSupport\n{\n\tNSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);\n\n\tif (pathArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *basePath = [pathArray.firstObject stringByAppendingPathComponent:@\"/Textual/\"];\n\n\t[self _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n+ (nullable NSURL *)applicationSupportURL\n{\n\tNSString *sourcePath = self.applicationSupport;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (nullable NSString *)groupContainerApplicationSupport\n{\n\tNSURL *sourceURL = self.groupContainerApplicationSupportURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)groupContainerApplicationSupportURL\n{\n\tNSURL *sourceURL = self.groupContainerURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Library/Application Support/Textual/\"];\n\n\t[self _createDirectoryAtURL:baseURL];\n\n\treturn baseURL;\n}\n\n+ (nullable NSString *)applicationLogs\n{\n\tNSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);\n\n\tif (pathArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *endPath = [NSString stringWithFormat:@\"/Logs/%@/\", TXBundleBuildProductIdentifier];\n\n\tNSString *basePath = [pathArray.firstObject stringByAppendingPathComponent:endPath];\n\n\t[self _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n+ (nullable NSURL *)applicationLogsURL\n{\n\tNSString *sourcePath = self.applicationLogs;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (NSString *)applicationTemporary\n{\n\tNSString *sourcePath = NSTemporaryDirectory();\n\n\tNSString *endPath = [NSString stringWithFormat:@\"/%@/\", TXBundleBuildProductIdentifier];\n\n\tNSString *basePath = [sourcePath stringByAppendingPathComponent:endPath];\n\n\t[self _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n+ (NSURL *)applicationTemporaryURL\n{\n\treturn [NSURL fileURLWithPath:self.applicationTemporary isDirectory:YES];\n}\n\n+ (NSString *)applicationTemporaryProcessSpecific\n{\n\tNSString *sourcePath = self.applicationTemporary;\n\n\tint processIdentifier = [[NSProcessInfo processInfo] processIdentifier];\n\n\tNSString *endPath = [NSString stringWithFormat:@\"/tmp-%i\", processIdentifier];\n\n\tNSString *basePath = [sourcePath stringByAppendingPathComponent:endPath];\n\n\t[self _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n+ (NSURL *)applicationTemporaryProcessSpecificURL\n{\n\treturn [NSURL fileURLWithPath:self.applicationTemporaryProcessSpecific isDirectory:YES];\n}\n\n+ (NSString *)bundledExtensions\n{\n\treturn self.bundledExtensionsURL.path;\n}\n\n+ (NSURL *)bundledExtensionsURL\n{\n\tNSURL *baseURL = self.applicationResourcesURL;\n\n\treturn [baseURL URLByAppendingPathComponent:@\"/Bundled Extensions/\"];\n}\n\n+ (NSString *)bundledScripts\n{\n\treturn self.bundledScriptsURL.path;\n}\n\n+ (NSURL *)bundledScriptsURL\n{\n\tNSURL *baseURL = self.applicationResourcesURL;\n\n\treturn [baseURL URLByAppendingPathComponent:@\"/Bundled Scripts/\"];\n}\n\n+ (NSString *)bundledThemes\n{\n\treturn self.bundledThemesURL.path;\n}\n\n+ (NSURL *)bundledThemesURL\n{\n\tNSURL *baseURL = self.applicationResourcesURL;\n\n\treturn [baseURL URLByAppendingPathComponent:@\"/Bundled Styles/\"];\n}\n\n+ (nullable NSString *)customExtensions\n{\n\tNSURL *sourceURL = self.customExtensionsURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)customExtensionsURL\n{\n\tNSURL *sourceURL = self.groupContainerApplicationSupportURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Extensions/\"];\n\n\t[self _createDirectoryAtURL:baseURL];\n\n\treturn baseURL;\n}\n\n+ (nullable NSString *)customScripts\n{\n\tNSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSApplicationScriptsDirectory, NSUserDomainMask, YES);\n\n\tif (pathArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *basePath = pathArray.firstObject;\n\n#if TEXTUAL_BUILT_INSIDE_SANDBOX == 0\n\t[self _createDirectoryAtPath:basePath];\n#endif\n\n\treturn basePath;\n}\n\n+ (nullable NSURL *)customScriptsURL\n{\n\tNSString *sourcePath = self.customScripts;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (nullable NSString *)customThemes\n{\n\tNSURL *sourceURL = self.customThemesURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)customThemesURL\n{\n\tNSURL *sourceURL = self.groupContainerApplicationSupportURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Styles/\"];\n\n\t[self _createDirectoryAtURL:baseURL];\n\n\treturn baseURL;\n}\n\n#pragma mark -\n#pragma mark System Specific\n\n+ (nullable NSString *)systemApplications\n{\n\tNSArray *searchArray = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSSystemDomainMask, YES);\n\n\tif (searchArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\treturn searchArray.firstObject;\n}\n\n+ (nullable NSURL *)systemApplicationsURL\n{\n\tNSString *sourcePath = self.systemApplications;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (NSString *)systemDiagnosticReports\n{\n\treturn @\"/Library/Logs/DiagnosticReports\";\n}\n\n+ (NSURL *)systemDiagnosticReportsURL\n{\n\treturn [NSURL fileURLWithPath:self.systemDiagnosticReports isDirectory:YES];\n}\n\n#pragma mark -\n#pragma mark User Specific\n\n+ (nullable NSString *)userApplicationScripts\n{\n\tNSURL *sourceURL = self.userApplicationScriptsURL;\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn sourceURL.path;\n}\n\n+ (nullable NSURL *)userApplicationScriptsURL\n{\n\tNSURL *sourceURL = self.customScriptsURL;\n\n\treturn [sourceURL URLByDeletingLastPathComponent];\n}\n\n+ (NSString *)userDiagnosticReports\n{\n\treturn self.userDiagnosticReportsURL.path;\n}\n\n+ (NSURL *)userDiagnosticReportsURL\n{\n\tNSURL *sourceURL = self.userHomeURL;\n\n\treturn [sourceURL URLByAppendingPathComponent:@\"/Library/Logs/DiagnosticReports\"];\n}\n\n+ (nullable NSString *)userDownloads\n{\n\tNSArray *searchArray = NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES);\n\n\tif (searchArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\treturn searchArray.firstObject;\n}\n\n+ (nullable NSURL *)userDownloadsURL\n{\n\tNSString *sourcePath = self.userDownloads;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n+ (NSString *)userHome\n{\n\treturn [NSFileManager pathOfHomeDirectoryOutsideSandbox];\n}\n\n+ (NSURL *)userHomeURL\n{\n\treturn [NSFileManager URLOfHomeDirectoryOutsideSandbox];\n}\n\n+ (nullable NSString *)userPreferences\n{\n\tNSArray *searchArray = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);\n\n\tif (searchArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\treturn [searchArray.firstObject stringByAppendingPathComponent:@\"/Preferences/\"];\n}\n\n+ (nullable NSURL *)userPreferencesURL\n{\n\tNSString *sourcePath = self.userPreferences;\n\n\tif (sourcePath == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [NSURL fileURLWithPath:sourcePath isDirectory:YES];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Transcript URL\n\n@implementation TPCPathInfo (TPCPathInfoTranscriptFolderExtension)\n\nstatic NSURL * _Nullable _transcriptFolderURL = nil;\n\n+ (nullable NSString *)transcriptFolder\n{\n\treturn _transcriptFolderURL.path;\n}\n\n+ (nullable NSURL *)transcriptFolderURL\n{\n\treturn _transcriptFolderURL;\n}\n\n+ (void)setTranscriptFolderURL:(nullable NSData *)transcriptFolderURL\n{\n\tif ( _transcriptFolderURL) {\n\t\t[_transcriptFolderURL stopAccessingSecurityScopedResource];\n\t\t _transcriptFolderURL = nil;\n\t}\n\n\t[RZUserDefaults() setObject:transcriptFolderURL forKey:@\"LogTranscriptDestinationSecurityBookmark_5\"];\n\n\t[self startUsingTranscriptFolderURL];\n}\n\n+ (void)warnUserAboutStaleTranscriptFolderURL\n{\n\t/* If logging isn't enabled, then we don't inform user of stale\n\t bookmarks because they probably aren't interested in that fact. */\n\tif ([TPCPreferences logToDisk] == NO) {\n\t\treturn;\n\t}\n\t\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[atn-1c]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[b7o-v4]\")\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t   alternateButton:nil];\n}\n\n+ (void)startUsingTranscriptFolderURL\n{\n\t/* Even if user has logging disabled, we still start using the bookmark\n\t so that we can present it in the Preferences window while the pop up\n\t for selecting a new location is disabled. */\n\tNSData *bookmark = [RZUserDefaults() dataForKey:@\"LogTranscriptDestinationSecurityBookmark_5\"];\n\n\tif (bookmark == nil) {\n\t\treturn;\n\t}\n\n\tBOOL resolvedBookmarkIsStale = YES;\n\n\tNSError *resolvedBookmarkError = nil;\n\n\tNSURL *resolvedBookmark =\n\t[NSURL URLByResolvingBookmarkData:bookmark\n\t\t\t\t\t\t\t  options:NSURLBookmarkResolutionWithSecurityScope\n\t\t\t\t\t\trelativeToURL:nil\n\t\t\t\t  bookmarkDataIsStale:&resolvedBookmarkIsStale\n\t\t\t\t\t\t\t\terror:&resolvedBookmarkError];\n\n\tif (resolvedBookmarkIsStale) {\n\t\t/* \"On return, if YES, the bookmark data is stale. \n\t\t Your app should create a new bookmark using the \n\t\t returned URL and use it in place of any stored \n\t\t copies of the existing bookmark.\" */\n\t\tNSData *newBookmark = [resolvedBookmark bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope\n\t\t\t\t\t\t\t\t\t\t includingResourceValuesForKeys:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  relativeToURL:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  error:NULL];\n\n\t\tif (newBookmark) {\n\t\t\t[self setTranscriptFolderURL:newBookmark];\n\t\t} else {\n\t\t\t[self warnUserAboutStaleTranscriptFolderURL];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (resolvedBookmark == nil) {\n\t\tLogToConsoleError(\"Error creating bookmark for URL: %{public}@\",\n\t\t\t  resolvedBookmarkError.localizedDescription);\n\n\t\t[self warnUserAboutStaleTranscriptFolderURL];\n\n\t\treturn;\n\t}\n\n\t_transcriptFolderURL = resolvedBookmark;\n\n\tif ([_transcriptFolderURL startAccessingSecurityScopedResource] == NO) {\n\t\tLogToConsoleError(\"Failed to access bookmark\");\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCPreferencesImportExport.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesReload.h\"\n#import \"TPCPreferencesUserDefaultsLocal.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowLoadingScreen.h\"\n#import \"TVCServerList.h\"\n#import \"TPCPreferencesImportExportPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferencesUserDefaults ()\n- (void)_migrateObject:(nullable id)value forKey:(NSString *)defaultName;\n@end\n\n@implementation TPCPreferencesImportExport\n\n+ (void)importInWindow:(NSWindow *)window\n{\n\tNSParameterAssert(window != nil);\n\n\t[TDCAlert alertSheetWithWindow:window\n\t\t\t\t\t\t\t  body:TXTLS(@\"Prompts[jsh-1a]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"Prompts[itb-3x]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[502-6h]\")\n\t\t\t\t   alternateButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t   [self importPreflight:buttonClicked];\n\t\t\t\t   }];\n}\n\n+ (void)importPreflight:(TDCAlertResponse)buttonPressed\n{\n\tif (buttonPressed != TDCAlertResponseDefault) {\n\t\treturn;\n\t}\n\n\tNSOpenPanel *d = [NSOpenPanel openPanel];\n\n\td.canChooseFiles = YES;\n\td.canChooseDirectories = NO;\n\td.canCreateDirectories = NO;\n\td.resolvesAliases = YES;\n\td.allowsMultipleSelection = NO;\n\n\t[d beginWithCompletionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode == NSModalResponseOK) {\n\t\t\tNSURL *pathURL = d.URLs[0];\n\n\t\t\t[self importPostflight:pathURL];\n\t\t}\n\t}];\n}\n\n+ (BOOL)importPostflightBackupPreferences\n{\n\tNSString *sourcePath = NSHomeDirectory();\n\n\tNSString *basePath = [NSString stringWithFormat:@\"/Textual-importBackup-%@.plist\", [NSString stringWithUUID]];\n\n\tNSString *backupPath = [sourcePath stringByAppendingPathComponent:basePath];\n\n\treturn [self exportPostflightForPath:backupPath filterJunk:NO];\n}\n\n+ (void)importPostflight:(NSURL *)pathURL\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _importPostflight:pathURL];\n\t});\n}\n\n+ (void)_importPostflight:(NSURL *)pathURL\n{\n\t/* Create a backup of the old configuration */\n\tif ([self importPostflightBackupPreferences] == NO) {\n\t\treturn;\n\t}\n\n\t/* Begin import */\n\tNSData *fileContents = [NSData dataWithContentsOfURL:pathURL];\n\n\tNSError *parseError = nil;\n\n\tNSDictionary *propertyList =\n\t[NSPropertyListSerialization propertyListWithData:fileContents options:NSPropertyListImmutable format:NULL error:&parseError];\n\n\t/* Perform actual import if we have the dictionary. */\n\tif (propertyList == nil) {\n\t\tif (parseError) {\n\t\t\tLogToConsoleError(\"Import failed: %{public}@\", parseError.localizedDescription);\n\t\t}\n\n\t\treturn;\n\t}\n\n\t/* The loading screen is a generic way to show something during import */\n\t[mainWindowLoadingScreen() showProgressViewWithReason:TXTLS(@\"TVCMainWindow[5g1-i9]\")];\n\n\t[worldController() setIsImportingConfiguration:YES];\n\n\t[mainWindowServerList() beginUpdates];\n\n\t/* Import data */\n\t[self importContentsOfDictionary:propertyList reloadPreferences:NO];\n\n\t/* Do not push the loading screen right away. Add a little delay to give everything\n\t a chance to settle down before presenting the changes to the user. */\n\t[self performSelectorInCommonModes:@selector(importPostflightCleanup:) withObject:propertyList.allKeys afterDelay:2.0];\n}\n\n+ (void)importContentsOfDictionary:(NSDictionary<NSString *, id> *)aDict\n{\n\t[self importContentsOfDictionary:aDict reloadPreferences:YES];\n}\n\n+ (void)importContentsOfDictionary:(NSDictionary<NSString *, id> *)aDict reloadPreferences:(BOOL)reloadPreferences\n{\n\tNSParameterAssert(aDict != nil);\n\n\t[aDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) {\n\t\t[self import:object withKey:key];\n\t}];\n\n\tif (reloadPreferences) {\n\t\t[TPCPreferences performReloadActionForKeys:aDict.allKeys];\n\t}\n}\n\n+ (void)import:(id)object withKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tif ([key isEqualToString:TPCPreferencesThemeNameDefaultsKey])\n\t{\n\t\tif ([object isKindOfClass:[NSString class]] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[TPCPreferences setThemeNameWithExistenceCheck:object];\n\t}\n\telse if ([key isEqualToString:TPCPreferencesThemeFontNameDefaultsKey])\n\t{\n\t\tif ([object isKindOfClass:[NSString class]] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[TPCPreferences setThemeChannelViewFontNameWithExistenceCheck:object];\n\t}\n\telse if ([key isEqualToString:IRCWorldClientListDefaultsKey])\n\t{\n\t\tif ([object isKindOfClass:[NSArray class]] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\t[object enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {\n\t\t\t[self importClientConfiguration:object];\n\t\t}];\n\t}\n\telse\n\t{\n\t\t[RZUserDefaults() _migrateObject:object forKey:key];\n\t}\n}\n\n+ (void)importClientConfiguration:(NSDictionary<NSString *, id> *)config\n{\n\tNSParameterAssert(config != nil);\n\n\tIRCClientConfig *clientConfig = [[IRCClientConfig alloc] initWithDictionary:config];\n\n\tIRCClient *client = [worldController() findClientWithId:clientConfig.uniqueIdentifier];\n\n\tif (client) {\n\t\t[client updateConfig:clientConfig];\n\t} else {\n\t\t[worldController() createClientWithConfig:clientConfig reload:YES];\n\t}\n}\n\n+ (void)importPostflightCleanup:(NSArray<NSString *> *)changedKeys\n{\n\t[TPCPreferences performReloadActionForKeys:changedKeys];\n\n\t[mainWindowServerList() endUpdates];\n\n\t[worldController() setIsImportingConfiguration:NO];\n\n\t[mainWindow() reloadLoadingScreen];\n}\n\n#pragma mark -\n#pragma mark Export\n\n+ (BOOL)isKeyNameSupposedToBeIgnored:(NSString *)key\n{\n\treturn [TPCPreferencesUserDefaults keyIsExcludedFromExportImport:key];\n}\n\n+ (NSDictionary<NSString *, id> *)exportedPreferencesDictionary\n{\n\treturn [self exportedPreferencesDictionary:YES filterDefaults:YES];\n}\n\n+ (NSDictionary<NSString *, id> *)exportedPreferencesDictionary:(BOOL)filterJunk\n{\n\treturn [self exportedPreferencesDictionary:filterJunk filterDefaults:filterJunk];\n}\n\n+ (NSDictionary<NSString *, id> *)exportedPreferencesDictionary:(BOOL)filterJunk filterDefaults:(BOOL)filterDefaults\n{\n\t/* Combine list of keys to strip */\n\tNSMutableArray *keysToStrip = [NSMutableArray array];\n\n\tNSDictionary *argumentsDomain = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSArgumentDomain];\n\n\t[keysToStrip addObjectsFromArray:argumentsDomain.allKeys];\n\n\tif (filterDefaults) {\n\t\tNSDictionary *defaultsDomain = [TPCPreferences defaultPreferences];\n\n\t\t[keysToStrip addObjectsFromArray:defaultsDomain.allKeys];\n\t}\n\n\tif (filterJunk) {\n\t\tNSDictionary *globalsDomain = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];\n\n\t\t[keysToStrip addObjectsFromArray:globalsDomain.allKeys];\n\t}\n\n\t/* Create mutable copy of preferences and strip keys */\n\tNSDictionary *exportedPreferences = [RZUserDefaults() dictionaryRepresentation];\n\n\tNSMutableDictionary<NSString *, id> *finalDictionary = [exportedPreferences mutableCopy];\n\n\t[finalDictionary removeObjectsForKeys:keysToStrip];\n\n\t/* Strip keys that must be checked dynamically */\n\tif (filterJunk) {\n\t\tNSSet *keysToStrip2 =\n\t\t[finalDictionary keysOfEntriesPassingTest:^BOOL(NSString *key, id object, BOOL *stop) {\n\t\t\treturn [self isKeyNameSupposedToBeIgnored:key];\n\t\t}];\n\n\t\t[finalDictionary removeObjectsForKeys:keysToStrip2.allObjects];\n\t}\n\n\treturn [finalDictionary copy];\n}\n\n+ (void)exportInWindow:(NSWindow *)window\n{\n\tNSParameterAssert(window != nil);\n\n\t[TDCAlert alertSheetWithWindow:window\n\t\t\t\t\t\t\t  body:TXTLS(@\"Prompts[syp-al]\")\n\t\t\t\t\t\t\t title:TXTLS(@\"Prompts[1fm-up]\")\n\t\t\t\t\t defaultButton:TXTLS(@\"Prompts[vun-f0]\")\n\t\t\t\t   alternateButton:TXTLS(@\"Prompts[qso-2g]\")\n\t\t\t\t\t   otherButton:nil\n\t\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t\t   [self exportPreflight:buttonClicked];\n\t\t\t\t   }];\n}\n\n+ (void)exportPreflight:(TDCAlertResponse)buttonPressed\n{\n\tif (buttonPressed != TDCAlertResponseDefault) {\n\t\treturn;\n\t}\n\n\tNSSavePanel *d = [NSSavePanel savePanel];\n\n\td.canCreateDirectories = YES;\n\n\td.nameFieldStringValue = TXLocalizationNotNeeded(@\"TextualPreferences.plist\");\n\n\t[d beginWithCompletionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode == NSModalResponseOK) {\n\t\t\tNSURL *pathURL = d.URL;\n\n\t\t\t[self exportPostflightForURL:pathURL filterJunk:YES];\n\t\t}\n\t}];\n}\n\n+ (BOOL)exportPostflightForPath:(NSString *)path\n{\n\treturn [self exportPostflightForPath:path filterJunk:YES];\n}\n\n+ (BOOL)exportPostflightForURL:(NSURL *)pathURL\n{\n\treturn [self exportPostflightForURL:pathURL filterJunk:YES];\n}\n\n+ (BOOL)exportPostflightForPath:(NSString *)path filterJunk:(BOOL)filterJunk\n{\n\tNSParameterAssert(path != nil);\n\n\tNSURL *pathURL = [NSURL fileURLWithPath:path];\n\n\treturn [self exportPostflightForURL:pathURL filterJunk:filterJunk];\n}\n\n+ (BOOL)exportPostflightForURL:(NSURL *)pathURL filterJunk:(BOOL)filterJunk\n{\n\tNSParameterAssert(pathURL != nil);\n\n\tNSDictionary *exportedPreferences = [self exportedPreferencesDictionary:filterJunk];\n\n\t/* The export will be saved as binary. Two reasons: 1) Discourages user from\n\t trying to tamper with stuff. 2) Smaller, faster. Mostly #1. */\n\tNSError *parseError = nil;\n\n\tNSData *propertyList =\n\t[NSPropertyListSerialization dataWithPropertyList:exportedPreferences format:NSPropertyListBinaryFormat_v1_0 options:0 error:&parseError];\n\n\tif (propertyList == nil) {\n\t\tif (parseError) {\n\t\t\tLogToConsoleError(\"Error Creating Property List: %{public}@\", parseError.localizedDescription);\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\tBOOL writeResult = [propertyList writeToURL:pathURL atomically:YES];\n\n\tif (writeResult == NO) {\n\t\tLogToConsoleError(\"Write failed\");\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCPreferencesLocal.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXGlobalModels.h\"\n#import \"IRCWorld.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n#import \"TPCApplicationInfoPrivate.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesUserDefaultsLocal.h\"\n#import \"TPCResourceManager.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TPCPreferencesThemeNameDefaultsKey\t= @\"Theme -> Name\";\n\nNSString * const TPCPreferencesThemeFontNameDefaultsKey\t= @\"Theme -> Font Name\";\nNSString * const TPCPreferencesThemeFontSizeDefaultsKey\t= @\"Theme -> Font Size\";\n\nNSString * const TPCPreferencesThemeNameMissingLocallyDefaultsKey = @\"Theme -> Name -> Did Not Exist During Last Sync\";\n\nNSString * const TPCPreferencesThemeFontNameMissingLocallyDefaultsKey = @\"Theme -> Font Name -> Did Not Exist During Last Sync\";\n\nNSUInteger const TPCPreferencesDictionaryVersion = 602;\n\n@implementation TPCPreferences (TPCPreferencesLocal)\n\n#pragma mark -\n#pragma mark Default Identity\n\n+ (NSString *)_defaultNicknamePrefix\n{\n\treturn [self defaultPreferences][@\"DefaultIdentity -> Nickname\"];\n}\n\n+ (void)_populateDefaultNickname\n{\n\t/* Using \"Guest\" as the default nickname may create conflicts as nickname guesses are \n\t exhausted while appending underscores. To fix this, a random number is appended to \n\t the end of the default nickname. */\n\tNSString *nicknamePrefix = [self _defaultNicknamePrefix];\n\n\tNSString *nickname = [nicknamePrefix stringByAppendingFormat:@\"%lu\", TXRandomNumber(100)];\n\n\t[RZUserDefaults() registerDefaults:@{@\"DefaultIdentity -> Nickname\" : nickname}];\n}\n\n+ (NSString *)defaultNickname\n{\n\treturn [RZUserDefaults() objectForKey:@\"DefaultIdentity -> Nickname\"];\n}\n\n+ (nullable NSString *)defaultAwayNickname\n{\n\treturn [RZUserDefaults() objectForKey:@\"DefaultIdentity -> AwayNickname\"];\n}\n\n+ (NSString *)defaultUsername\n{\n\treturn [RZUserDefaults() objectForKey:@\"DefaultIdentity -> Username\"];\n}\n\n+ (NSString *)defaultRealName\n{\n\treturn [RZUserDefaults() objectForKey:@\"DefaultIdentity -> Realname\"];\n}\n\n#pragma mark -\n#pragma mark General Preferences\n\n+ (NSUInteger)autojoinMaximumChannelJoins\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"AutojoinMaximumChannelJoinCount\"];\n}\n\n+ (NSTimeInterval)autojoinDelayBetweenChannelJoins\n{\n\treturn [RZUserDefaults() doubleForKey:@\"AutojoinDelayBetweenChannelJoins\"];\n}\n\n+ (NSTimeInterval)autojoinDelayAfterIdentification\n{\n\treturn [RZUserDefaults() doubleForKey:@\"AutojoinDelayAfterIdentification\"];\n}\n\n+ (NSString *)defaultKickMessage\n{\n\treturn [RZUserDefaults() objectForKey:@\"ChannelOperatorDefaultLocalization -> Kick Reason\"];\n}\n\n+ (NSString *)IRCopDefaultKillMessage\n{\n\treturn [RZUserDefaults() objectForKey:@\"IRCopDefaultLocalizaiton -> Kill Reason\"];\n}\n\n+ (NSString *)IRCopDefaultGlineMessage\n{\n\treturn [RZUserDefaults() objectForKey:@\"IRCopDefaultLocalizaiton -> G:Line Reason\"];\n}\n\n+ (NSString *)IRCopDefaultShunMessage\n{\n\treturn [RZUserDefaults() objectForKey:@\"IRCopDefaultLocalizaiton -> Shun Reason\"];\n}\n\n+ (nullable NSString *)masqueradeCTCPVersion\n{\n\treturn [RZUserDefaults() objectForKey:@\"ApplicationCTCPVersionMasquerade\"];\n}\n\n+ (BOOL)channelNavigationIsServerSpecific\n{\n\t/* TDCChannelSpotlightController is observing this key with it hard coded.\n\t If changed here, change there as well. */\n\n\treturn [RZUserDefaults() boolForKey:@\"ChannelNavigationIsServerSpecific\"];\n}\n\n+ (BOOL)setAwayOnScreenSleep\n{\n\treturn [RZUserDefaults() boolForKey:@\"SetAwayOnScreenSleep\"];\n}\n\n+ (BOOL)disconnectOnSleep\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutomaticallyDisconnectForSleepMode\"];\n}\n\n+ (BOOL)disableSidebarTranslucency\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisableSidebarTranslucency\"];\n}\n\n+ (BOOL)hideMainWindowSegmentedController\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisableMainWindowSegmentedController\"];\n}\n\n+ (BOOL)logHighlights\n{\n\treturn [RZUserDefaults() boolForKey:@\"LogHighlights\"];\n}\n\n+ (BOOL)clearAllConnections\n{\n\treturn [RZUserDefaults() boolForKey:@\"ApplyCommandToAllConnections -> clearall\"];\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n+ (void)setTextEncryptionIsOpportunistic:(BOOL)textEncryptionIsOpportunistic\n{\n\t[RZUserDefaults() setBool:textEncryptionIsOpportunistic forKey:@\"Off-the-Record Messaging -> Automatically Enable Service\"];\n}\n\n+ (BOOL)textEncryptionIsOpportunistic\n{\n\treturn [RZUserDefaults() boolForKey:@\"Off-the-Record Messaging -> Automatically Enable Service\"];\n}\n\n+ (void)setTextEncryptionIsRequired:(BOOL)textEncryptionIsRequired\n{\n\t[RZUserDefaults() setBool:textEncryptionIsRequired forKey:@\"Off-the-Record Messaging -> Require Encryption\"];\n}\n\n+ (BOOL)textEncryptionIsRequired\n{\n\treturn [RZUserDefaults() boolForKey:@\"Off-the-Record Messaging -> Require Encryption\"];\n}\n\n+ (void)setTextEncryptionIsEnabled:(BOOL)textEncryptionIsEnabled\n{\n\t[RZUserDefaults() setBool:textEncryptionIsEnabled forKey:@\"Off-the-Record Messaging -> Enable Encryption\"];\n}\n\n+ (BOOL)textEncryptionIsEnabled\n{\n\treturn [RZUserDefaults() boolForKey:@\"Off-the-Record Messaging -> Enable Encryption\"];\n}\n#endif\n\n+ (BOOL)enableEchoMessageCapability\n{\n//\treturn [RZUserDefaults() boolForKey:@\"IRC -> Enable echo-message Capability\"];\n\t\n\treturn NO;\n}\n\n+ (BOOL)displayServerMOTD\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayServerMessageOfTheDayOnConnect\"];\n}\n\n+ (BOOL)copyOnSelect\n{\n\treturn [RZUserDefaults() boolForKey:@\"CopyTextSelectionOnMouseUp\"];\n}\n\n+ (BOOL)replyToCTCPRequests\n{\n\treturn [RZUserDefaults() boolForKey:@\"ReplyUnignoredExternalCTCPRequests\"];\n}\n\n+ (BOOL)autoAddScrollbackMark\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutomaticallyAddScrollbackMarker\"];\n}\n\n+ (BOOL)removeAllFormatting\n{\n\treturn [RZUserDefaults() boolForKey:@\"RemoveIRCTextFormatting\"];\n}\n\n+ (BOOL)automaticallyDetectHighlightSpam\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutomaticallyDetectHighlightSpam\"];\n}\n\n+ (BOOL)disableNicknameColorHashing\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisableRemoteNicknameColorHashing\"];\n}\n\n+ (BOOL)conversationTrackingIncludesUserModeSymbol\n{\n\treturn [RZUserDefaults() boolForKey:@\"ConversationTrackingIncludesUserModeSymbol\"];\n}\n\n+ (BOOL)rightToLeftFormatting\n{\n\treturn [RZUserDefaults() boolForKey:@\"RightToLeftTextFormatting\"];\n}\n\n+ (BOOL)displayDockBadge\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayDockBadges\"];\n}\n\n+ (BOOL)amsgAllConnections\n{\n\treturn [RZUserDefaults() boolForKey:@\"ApplyCommandToAllConnections -> amsg\"];\n}\n\n+ (BOOL)awayAllConnections\n{\n\treturn [RZUserDefaults() boolForKey:@\"ApplyCommandToAllConnections -> away\"];\n}\n\n+ (BOOL)giveFocusOnMessageCommand\n{\n\treturn [RZUserDefaults() boolForKey:@\"FocusSelectionOnMessageCommandExecution\"];\n}\n\n+ (BOOL)memberListSortFavorsServerStaff\n{\n\treturn [RZUserDefaults() boolForKey:@\"MemberListSortFavorsServerStaff\"];\n}\n\n+ (BOOL)memberListUpdatesUserInfoPopoverOnScroll\n{\n\treturn [RZUserDefaults() boolForKey:@\"MemberListUpdatesUserInfoPopoverOnScroll\"];\n}\n\n+ (BOOL)memberListDisplayNoModeSymbol\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayUserListNoModeSymbol\"];\n}\n\n+ (BOOL)postNotificationsWhileInFocus\n{\n\treturn [RZUserDefaults() boolForKey:@\"PostNotificationsWhileInFocus\"];\n}\n\n+ (BOOL)automaticallyFilterUnicodeTextSpam\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutomaticallyFilterUnicodeTextSpam\"];\n}\n\n+ (BOOL)nickAllConnections\n{\n\treturn [RZUserDefaults() boolForKey:@\"ApplyCommandToAllConnections -> nick\"];\n}\n\n+ (BOOL)confirmQuit\n{\n\treturn [RZUserDefaults() boolForKey:@\"ConfirmApplicationQuit\"];\n}\n\n+ (BOOL)rememberServerListQueryStates\n{\n\treturn [RZUserDefaults() boolForKey:@\"ServerListRetainsQueriesBetweenRestarts\"];\n}\n\n+ (BOOL)rejoinOnKick\n{\n\treturn [RZUserDefaults() boolForKey:@\"RejoinChannelOnLocalKick\"];\n}\n\n+ (BOOL)reloadScrollbackOnLaunch\n{\n\treturn [RZUserDefaults() boolForKey:@\"ReloadScrollbackOnLaunch\"];\n}\n\n+ (BOOL)autoJoinOnInvite\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutojoinChannelOnInvite\"];\n}\n\n+ (BOOL)connectOnDoubleclick\n{\n\treturn [RZUserDefaults() boolForKey:@\"ServerListDoubleClickConnectServer\"];\n}\n\n+ (BOOL)disconnectOnDoubleclick\n{\n\treturn [RZUserDefaults() boolForKey:@\"ServerListDoubleClickDisconnectServer\"];\n}\n\n+ (BOOL)joinOnDoubleclick\n{\n\treturn [RZUserDefaults() boolForKey:@\"ServerListDoubleClickJoinChannel\"];\n}\n\n+ (BOOL)leaveOnDoubleclick\n{\n\treturn [RZUserDefaults() boolForKey:@\"ServerListDoubleClickLeaveChannel\"];\n}\n\n+ (BOOL)logToDisk\n{\n\treturn [RZUserDefaults() boolForKey:@\"LogTranscript\"];\n}\n\n+ (void)setLogToDisk:(BOOL)logToDisk\n{\n\t[RZUserDefaults() setBool:logToDisk forKey:@\"LogTranscript\"];\n}\n\n+ (BOOL)logToDiskIsEnabled\n{\n\treturn ([RZUserDefaults() boolForKey:@\"LogTranscript\"] &&\n\t\t\t[TPCPathInfo transcriptFolderURL] != nil);\n}\n\n+ (BOOL)openBrowserInBackground\n{\n\treturn [RZUserDefaults() boolForKey:@\"OpenClickedLinksInBackgroundBrowser\"];\n}\n\n+ (BOOL)showDateChanges\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayEventInLogView -> Date Changes\"];\n}\n\n+ (void)setShowInlineMedia:(BOOL)showInlineMedia\n{\n\t[RZUserDefaults() setBool:showInlineMedia forKey:@\"DisplayEventInLogView -> Inline Media\"];\n}\n\n+ (BOOL)showInlineMedia\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayEventInLogView -> Inline Media\"];\n}\n\n+ (BOOL)showJoinLeave\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayEventInLogView -> Join, Part, Quit\"];\n}\n\n+ (BOOL)commandReturnSendsMessageAsAction\n{\n\treturn [RZUserDefaults() boolForKey:@\"CommandReturnSendsMessageAsAction\"];\n}\n\n+ (BOOL)controlEnterSendsMessage\n{\n\treturn [RZUserDefaults() boolForKey:@\"ControlEnterSendsMessage\"];\n}\n\n+ (BOOL)displayPublicMessageCountOnDockBadge\n{\n\treturn [RZUserDefaults() boolForKey:@\"DisplayPublicMessageCountInDockBadge\"];\n}\n\n+ (void)setHighlightCurrentNickname:(BOOL)highlightCurrentNickname\n{\n\t[RZUserDefaults() setBool:highlightCurrentNickname forKey:@\"TrackNicknameHighlightsOfLocalUser\"];\n}\n\n+ (BOOL)highlightCurrentNickname\n{\n\treturn [RZUserDefaults() boolForKey:@\"TrackNicknameHighlightsOfLocalUser\"];\n}\n\n+ (BOOL)inputHistoryIsChannelSpecific\n{\n\treturn [RZUserDefaults() boolForKey:@\"SaveInputHistoryPerSelection\"];\n}\n\n+ (CGFloat)swipeMinimumLength\n{\n\treturn [RZUserDefaults() doubleForKey:@\"SwipeMinimumLength\"];\n}\n\n+ (NSUInteger)trackUserAwayStatusMaximumChannelSize\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"TrackUserAwayStatusMaximumChannelSize\"];\n}\n\n+ (TXTabKeyAction)tabKeyAction\n{\n\treturn (TXTabKeyAction)[RZUserDefaults() unsignedIntegerForKey:@\"Keyboard -> Tab Key Action\"];\n}\n\n+ (TXNicknameHighlightMatchType)highlightMatchingMethod\n{\n\treturn (TXNicknameHighlightMatchType)[RZUserDefaults() unsignedIntegerForKey:@\"NicknameHighlightMatchingType\"];\n}\n\n+ (TXUserDoubleClickAction)userDoubleClickOption\n{\n\treturn (TXUserDoubleClickAction)[RZUserDefaults() unsignedIntegerForKey:@\"UserListDoubleClickAction\"];\n}\n\n+ (TXNoticeSendLocation)locationToSendNotices\n{\n\treturn (TXNoticeSendLocation)[RZUserDefaults() unsignedIntegerForKey:@\"DestinationOfNonserverNotices\"];\n}\n\n+ (void)setLocationToSendNotices:(TXNoticeSendLocation)locationToSendNotices\n{\n\t[RZUserDefaults() setUnsignedInteger:locationToSendNotices forKey:@\"DestinationOfNonserverNotices\"];\n}\n\n+ (TXCommandWKeyAction)commandWKeyAction\n{\n\treturn (TXCommandWKeyAction)[RZUserDefaults() unsignedIntegerForKey:@\"Keyboard -> Command+W Key Action\"];\n}\n\n+ (TXHostmaskBanFormat)banFormat\n{\n\treturn (TXHostmaskBanFormat)[RZUserDefaults() unsignedIntegerForKey:@\"DefaultBanCommandHostmaskFormat\"];\n}\n\n+ (TVCMainWindowTextViewFontSize)mainTextViewFontSize\n{\n\treturn (TVCMainWindowTextViewFontSize)[RZUserDefaults() unsignedIntegerForKey:@\"Main Input Text Field -> Font Size\"];\n}\n\n+ (BOOL)focusMainTextViewOnSelectionChange\n{\n\treturn [RZUserDefaults() boolForKey:@\"Main Input Text Field -> Focus When Changing Views\"];\n}\n\n+ (BOOL)preferModernCiphers\n{\n\t/* The name of this preference is somewhat of a misnomer.\n\t Modern ciphers are always used, regardless of its value.\n\t This preference defines whether the \"deprecated\" ciphers\n\t are used as well. Whether we should prefer modern only. */\n\n\treturn [RZUserDefaults() boolForKey:@\"PreferModernCiphers\"];\n}\n\n+ (BOOL)preferModernSockets\n{\n\treturn [RZUserDefaults() boolForKey:@\"PreferModernSockets\"];\n}\n\n#pragma mark -\n#pragma mark App Nap \n\n+ (BOOL)appNapEnabled\n{\n\treturn ([[NSUserDefaults standardUserDefaults] boolForKey:@\"NSAppSleepDisabled\"] == NO);\n}\n\n+ (void)setAppNapEnabled:(BOOL)appNapEnabled\n{\n\t[[NSUserDefaults standardUserDefaults] setBool:(appNapEnabled == NO) forKey:@\"NSAppSleepDisabled\"];\n}\n\n#pragma mark -\n#pragma mark Updates\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n+ (BOOL)receiveBetaUpdates\n{\n\treturn [RZUserDefaults() boolForKey:@\"ReceiveBetaUpdates\"];\n}\n#endif\n\n#pragma mark -\n#pragma mark Developer Mode\n\n+ (void)setDeveloperModeEnabled:(BOOL)developerModeEnabled\n{\n\t[RZUserDefaults() setBool:developerModeEnabled forKey:@\"TextualDeveloperEnvironment\"];\n}\n\n+ (BOOL)developerModeEnabled\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextualDeveloperEnvironment\"];\n}\n\n#pragma mark -\n#pragma mark Theme\n\n+ (void)setAppearance:(TXPreferredAppearance)appearance\n{\n\t[RZUserDefaults() setUnsignedInteger:appearance forKey:@\"Appearance\"];\n}\n\n+ (TXPreferredAppearance)appearance\n{\n\treturn (TXPreferredAppearance)[RZUserDefaults() unsignedIntegerForKey:@\"Appearance\"];\n}\n\n+ (BOOL)invertSidebarColors\n{\n\treturn [RZUserDefaults() boolForKey:@\"InvertSidebarColors\"];\n}\n\n+ (NSString *)themeNameDefault\n{\n\treturn [self defaultPreferences][TPCPreferencesThemeNameDefaultsKey];\n}\n\n+ (NSString *)themeName\n{\n\treturn [RZUserDefaults() objectForKey:TPCPreferencesThemeNameDefaultsKey];\n}\n\n+ (void)setThemeName:(NSString *)value\n{\n\tNSParameterAssert(value != nil);\n\n\t[RZUserDefaults() setObject:value forKey:TPCPreferencesThemeNameDefaultsKey];\n\n\t[RZUserDefaults() removeObjectForKey:TPCPreferencesThemeNameMissingLocallyDefaultsKey];\n}\n\n+ (void)setThemeNameWithExistenceCheck:(NSString *)value\n{\n\tNSParameterAssert(value != nil);\n\n\tif ([themeController() themeExists:value]) {\n\t\t[self setThemeName:value];\n\t} else {\n\t\t[RZUserDefaults() setBool:YES forKey:TPCPreferencesThemeNameMissingLocallyDefaultsKey];\n\t}\n}\n\n+ (NSString *)themeChannelViewFontNameDefault\n{\n\treturn [self defaultPreferences][TPCPreferencesThemeFontNameDefaultsKey];\n}\n\n+ (NSString *)themeChannelViewFontName\n{\n\treturn [RZUserDefaults() objectForKey:TPCPreferencesThemeFontNameDefaultsKey];\n}\n\n+ (void)setThemeChannelViewFontName:(NSString *)value\n{\n\tNSParameterAssert(value != nil);\n\n\t[RZUserDefaults() setObject:value forKey:TPCPreferencesThemeFontNameDefaultsKey];\n\n\t[RZUserDefaults() removeObjectForKey:TPCPreferencesThemeFontNameMissingLocallyDefaultsKey];\n}\n\n+ (void)setThemeChannelViewFontNameWithExistenceCheck:(NSString *)value\n{\n\tNSParameterAssert(value != nil);\n\n\tif ([NSFont fontIsAvailable:value]) {\n\t\t[self setThemeChannelViewFontName:value];\n\t} else {\n\t\t[RZUserDefaults() setBool:YES forKey:TPCPreferencesThemeFontNameMissingLocallyDefaultsKey];\n\t}\n}\n\n+ (CGFloat)themeChannelViewFontSize\n{\n\treturn [RZUserDefaults() doubleForKey:@\"Theme -> Font Size\"];\n}\n\n+ (void)setThemeChannelViewFontSize:(CGFloat)value\n{\n\t[RZUserDefaults() setDouble:value forKey:@\"Theme -> Font Size\"];\n}\n\n+ (nullable NSFont *)themeChannelViewFont\n{\n\treturn [NSFont fontWithName:[self themeChannelViewFontName]\n\t\t\t\t\t\t   size:[self themeChannelViewFontSize]];\n}\n\n+ (BOOL)themeChannelViewFontPreferenceUserConfigurable\n{\n\treturn [RZUserDefaults() boolForKey:@\"Theme -> Channel Font Preference Enabled\"];\n}\n\n+ (void)setThemeChannelViewFontPreferenceUserConfigurable:(BOOL)themeChannelViewFontPreferenceUserConfigurable\n{\n\t[RZUserDefaults() registerDefault:@(themeChannelViewFontPreferenceUserConfigurable) forKey:@\"Theme -> Channel Font Preference Enabled\"];\n}\n\n+ (NSString *)themeNicknameFormatDefault\n{\n\treturn [self defaultPreferences][@\"Theme -> Nickname Format\"];\n}\n\n+ (NSString *)themeNicknameFormat\n{\n\treturn [RZUserDefaults() objectForKey:@\"Theme -> Nickname Format\"];\n}\n\n+ (BOOL)themeNicknameFormatPreferenceUserConfigurable\n{\n\treturn [RZUserDefaults() boolForKey:@\"Theme -> Nickname Format Preference Enabled\"];\n}\n\n+ (void)setThemeNicknameFormatPreferenceUserConfigurable:(BOOL)themeNicknameFormatPreferenceUserConfigurable\n{\n\t[RZUserDefaults() registerDefault:@(themeNicknameFormatPreferenceUserConfigurable) forKey:@\"Theme -> Nickname Format Preference Enabled\"];\n}\n\n+ (NSString *)themeTimestampFormatDefault\n{\n\treturn [self defaultPreferences][@\"Theme -> Timestamp Format\"];\n}\n\n+ (NSString *)themeTimestampFormat\n{\n\treturn [RZUserDefaults() objectForKey:@\"Theme -> Timestamp Format\"];\n}\n\n+ (BOOL)themeTimestampFormatPreferenceUserConfigurable\n{\n\treturn [RZUserDefaults() boolForKey:@\"Theme -> Timestamp Format Preference Enabled\"];\n}\n\n+ (void)setThemeTimestampFormatPreferenceUserConfigurable:(BOOL)themeTimestampFormatPreferenceUserConfigurable\n{\n\t[RZUserDefaults() registerDefault:@(themeTimestampFormatPreferenceUserConfigurable) forKey:@\"Theme -> Timestamp Format Preference Enabled\"];\n}\n\n+ (nullable NSString *)themeUserStyleSheetRules\n{\n\treturn [RZUserDefaults() objectForKey:@\"Theme -> User Style Sheet Rules\"];\n}\n\n+ (void)setThemeUserStyleSheetRules:(nullable NSString *)themeUserStyleSheetRules\n{\n\t[RZUserDefaults() setObject:themeUserStyleSheetRules forKey:@\"Theme -> User Style Sheet Rules\"];\n}\n\n+ (CGFloat)mainWindowTransparency\n{\n\treturn [RZUserDefaults() doubleForKey:@\"MainWindowTransparencyLevel\"];\n}\n\n+ (BOOL)automaticallyReloadCustomThemesWhenTheyChange\n{\n\treturn [RZUserDefaults() boolForKey:@\"AutomaticallyReloadCustomThemesWhenTheyChange\"];\n}\n\n+ (void)setWebKit2Enabled:(BOOL)webKit2Enabled\n{\n\t[RZUserDefaults() setBool:webKit2Enabled forKey:@\"UsesWebKit2WhenAvailable\"];\n}\n\n+ (BOOL)webKit2Enabled\n{\n\treturn [RZUserDefaults() boolForKey:@\"UsesWebKit2WhenAvailable\"];\n}\n\n+ (BOOL)webKit2ProcessPoolSizeLimited\n{\n\treturn [RZUserDefaults() boolForKey:@\"WebViewProcessPoolSizeIsLimited\"];\n}\n\n+ (BOOL)webKit2PreviewLinks\n{\n\treturn [RZUserDefaults() boolForKey:@\"WebViewPreviewLinks\"];\n}\n\n+ (BOOL)themeChannelViewUsesCustomScrollers\n{\n\treturn ([RZUserDefaults() boolForKey:@\"WebViewDoNotUsesCustomScrollers\"] == NO);\n}\n\n+ (TXChannelViewArrangement)channelViewArrangement\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"ChannelViewArrangement\"];\n}\n\n#pragma mark -\n#pragma mark Completion Suffix\n\n+ (nullable NSString *)tabCompletionSuffix\n{\n\treturn [RZUserDefaults() objectForKey:@\"Keyboard -> Tab Key Completion Suffix\"];\n}\n\n+ (void)setTabCompletionSuffix:(NSString *)value\n{\n\tNSParameterAssert(value != nil);\n\n\t[RZUserDefaults() setObject:value forKey:@\"Keyboard -> Tab Key Completion Suffix\"];\n}\n\n+ (BOOL)tabCompletionDoNotAppendWhitespace\n{\n\treturn [RZUserDefaults() boolForKey:@\"Tab Completion -> Do Not Use Whitespace for Missing Completion Suffix\"];\n}\n\n+ (BOOL)tabCompletionCutForwardToFirstWhitespace\n{\n\treturn [RZUserDefaults() boolForKey:@\"Tab Completion -> Completion Suffix Cut Forward Until Space\"];\n}\n\n#pragma mark -\n#pragma mark File Transfers\n\n+ (TXFileTransferRequestReply)fileTransferRequestReplyAction\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"File Transfers -> File Transfer Request Reply Action\"];\n}\n\n+ (TXFileTransferIPAddressMethodDetection)fileTransferIPAddressDetectionMethod\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"File Transfers -> File Transfer IP Address Detection Method\"];\n}\n\n+ (BOOL)fileTransferRequestsAreReversed\n{\n\treturn [RZUserDefaults() boolForKey:@\"File Transfers -> File Transfer Requests Use Reverse DCC\"];\n}\n\n+ (BOOL)fileTransfersPreventIdleSystemSleep\n{\n\treturn [RZUserDefaults() boolForKey:@\"File Transfers -> Idle System Sleep Prevented During File Transfer\"];\n}\n\n+ (uint16_t)fileTransferPortRangeStart\n{\n\treturn [RZUserDefaults() unsignedShortForKey:@\"File Transfers -> File Transfer Port Range Start\"];\n}\n\n+ (void)setFileTransferPortRangeStart:(uint16_t)value\n{\n\t[RZUserDefaults() setUnsignedShort:value forKey:@\"File Transfers -> File Transfer Port Range Start\"];\n}\n\n+ (uint16_t)fileTransferPortRangeEnd\n{\n\treturn [RZUserDefaults() unsignedShortForKey:@\"File Transfers -> File Transfer Port Range End\"];\n}\n\n+ (void)setFileTransferPortRangeEnd:(uint16_t)value\n{\n\t[RZUserDefaults() setUnsignedShort:value forKey:@\"File Transfers -> File Transfer Port Range End\"];\n}\n\n+ (nullable NSString *)fileTransferManuallyEnteredIPAddress\n{\n\treturn [RZUserDefaults() objectForKey:@\"File Transfers -> File Transfer Manually Entered IP Address\"];\n}\n\n+ (nullable NSString *)fileTransferIPAddressInterfaceName\n{\n\treturn [RZUserDefaults() objectForKey:@\"File Transfers -> File Transfer IP Address Interface Name\"];\n}\n\n#pragma mark -\n#pragma mark Max Log Lines\n\n+ (NSUInteger)scrollbackSaveLimit\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"ScrollbackMaximumSavedLineCount\"];\n}\n\n+ (void)setScrollbackSaveLimit:(NSUInteger)scrollbackSaveLimit\n{\n\t[RZUserDefaults() setUnsignedInteger:scrollbackSaveLimit forKey:@\"ScrollbackMaximumSavedLineCount\"];\n}\n\n+ (NSUInteger)scrollbackVisibleLimit\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"ScrollbackMaximumVisibleLineCount\"];\n}\n\n+ (void)setScrollbackVisibleLimit:(NSUInteger)scrollbackVisibleLimit\n{\n\t[RZUserDefaults() setUnsignedInteger:scrollbackVisibleLimit forKey:@\"ScrollbackMaximumVisibleLineCount\"];\n}\n\n#pragma mark -\n#pragma mark Notifications\n\n+ (BOOL)soundIsMuted\n{\n\treturn [RZUserDefaults() boolForKey:@\"Notification Sound Is Muted\"];\n}\n\n+ (void)setSoundIsMuted:(BOOL)soundIsMuted\n{\n\t[RZUserDefaults() setBool:soundIsMuted forKey:@\"Notification Sound Is Muted\"];\n}\n\n+ (nullable NSString *)keyForEvent:(TXNotificationType)event category:(NSString *)category\n{\n\tNSParameterAssert(category != nil);\n\n\tNSString *returnValue = nil;\n\n\tswitch (event) {\n#define _dv(key, value)\t\tcase (key): { returnValue = (value); break; }\n\n\t\t_dv(TXNotificationTypeAddressBookMatch, @\"NotificationType -> Address Book Match -> \")\n\t\t_dv(TXNotificationTypeChannelMessage, @\"NotificationType -> Public Message -> \")\n\t\t_dv(TXNotificationTypeChannelNotice, @\"NotificationType -> Public Notice -> \")\n\t\t_dv(TXNotificationTypeConnect, @\"NotificationType -> Connected -> \")\n\t\t_dv(TXNotificationTypeDisconnect, @\"NotificationType -> Disconnected -> \")\n\t\t_dv(TXNotificationTypeHighlight, @\"NotificationType -> Highlight -> \")\n\t\t_dv(TXNotificationTypeInvite, @\"NotificationType -> Channel Invitation -> \")\n\t\t_dv(TXNotificationTypeKick, @\"NotificationType -> Kicked from Channel -> \")\n\t\t_dv(TXNotificationTypeNewPrivateMessage, @\"NotificationType -> Private Message (New) -> \")\n\t\t_dv(TXNotificationTypePrivateMessage, @\"NotificationType -> Private Message -> \")\n\t\t_dv(TXNotificationTypePrivateNotice, @\"NotificationType -> Private Notice -> \")\n\t\t_dv(TXNotificationTypeFileTransferSendSuccessful, @\"NotificationType -> Successful File Transfer (Sending) -> \")\n\t\t_dv(TXNotificationTypeFileTransferReceiveSuccessful, @\"NotificationType -> Successful File Transfer (Receiving) -> \")\n\t\t_dv(TXNotificationTypeFileTransferSendFailed, @\"NotificationType -> Failed File Transfer (Sending) -> \")\n\t\t_dv(TXNotificationTypeFileTransferReceiveFailed, @\"NotificationType -> Failed File Transfer (Receiving) -> \")\n\t\t_dv(TXNotificationTypeFileTransferReceiveRequested, @\"NotificationType -> File Transfer Request -> \")\n\t\t_dv(TXNotificationTypeUserJoined, @\"NotificationType -> User Joined -> \")\n\t\t_dv(TXNotificationTypeUserParted, @\"NotificationType -> User Parted -> \")\n\t\t_dv(TXNotificationTypeUserDisconnected, @\"NotificationType -> User Disconnected -> \")\n\n#undef _dv\n\t}\n\n\tif (returnValue == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [returnValue stringByAppendingString:category];\n}\n\n+ (nullable NSString *)soundForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Sound\"];\n\n\tif (eventKey == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [RZUserDefaults() objectForKey:eventKey];\n}\n\n+ (void)setSound:(nullable NSString *)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Sound\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setObject:value forKey:eventKey];\n}\n\n+ (BOOL)notificationEnabledForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Enabled\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setNotificationEnabled:(BOOL)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Enabled\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setBool:value forKey:eventKey];\n}\n\n+ (BOOL)disabledWhileAwayForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Disable While Away\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setDisabledWhileAway:(BOOL)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Disable While Away\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setBool:value forKey:eventKey];\n}\n\n+ (BOOL)bounceDockIconForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Bounce Dock Icon\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setBounceDockIcon:(BOOL)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Bounce Dock Icon\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setBool:value forKey:eventKey];\n}\n\n+ (BOOL)bounceDockIconRepeatedlyForEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Bounce Dock Icon Repeatedly\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setBounceDockIconRepeatedly:(BOOL)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Bounce Dock Icon Repeatedly\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setBool:value forKey:eventKey];\n}\n\n+ (BOOL)speakEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Speak\"];\n\n\tif (eventKey == nil) {\n\t\treturn NO;\n\t}\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setEventIsSpoken:(BOOL)value forEvent:(TXNotificationType)event\n{\n\tNSString *eventKey = [self keyForEvent:event category:@\"Speak\"];\n\n\tif (eventKey == nil) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setBool:value forKey:eventKey];\n}\n\n+ (BOOL)onlySpeakEventsForSelection\n{\n\treturn [RZUserDefaults() boolForKey:@\"OnlySpeakNotificationsForSelection\"];\n}\n\n+ (void)setOnlySpeakEventsForSelection:(BOOL)onlySpeakEventsForSelection\n{\n\t[RZUserDefaults() setBool:onlySpeakEventsForSelection forKey:@\"OnlySpeakNotificationsForSelection\"];\n}\n\n+ (BOOL)channelMessageSpeakChannelName\n{\n\tNSString *eventKey = [self keyForEvent:TXNotificationTypeChannelMessage category:@\"Speak Channel Name\"];\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setChannelMessageSpeakChannelName:(BOOL)channelMessageSpeakChannelName\n{\n\tNSString *eventKey = [self keyForEvent:TXNotificationTypeChannelMessage category:@\"Speak Channel Name\"];\n\n\t[RZUserDefaults() setBool:channelMessageSpeakChannelName forKey:eventKey];\n}\n\n+ (BOOL)channelMessageSpeakNickname\n{\n\tNSString *eventKey = [self keyForEvent:TXNotificationTypeChannelMessage category:@\"Speak Nickname\"];\n\n\treturn [RZUserDefaults() boolForKey:eventKey];\n}\n\n+ (void)setChannelMessageSpeakNickname:(BOOL)channelMessageSpeakNickname\n{\n\tNSString *eventKey = [self keyForEvent:TXNotificationTypeChannelMessage category:@\"Speak Nickname\"];\n\n\t[RZUserDefaults() setBool:channelMessageSpeakNickname forKey:eventKey];\n}\n\n#pragma mark -\n#pragma mark World\n\n+ (nullable NSArray<NSDictionary *> *)clientList\n{\n\treturn [RZUserDefaults() objectForKey:IRCWorldClientListDefaultsKey];\n}\n\n+ (void)setClientList:(nullable NSArray<NSDictionary *> *)clientList\n{\n\t[RZUserDefaults() setObject:clientList forKey:IRCWorldClientListDefaultsKey];\n}\n\n#pragma mark -\n#pragma mark Keywords\n\nstatic NSArray<NSString *> *_excludeKeywords = nil;\nstatic NSArray<NSString *> *_matchKeywords = nil;\n\n+ (void)_loadExcludeKeywords\n{\n\tNSArray<NSDictionary *> *keywordArrayIn = [RZUserDefaults() arrayForKey:@\"Highlight List -> Excluded Matches\"];\n\n\tNSMutableArray<NSString *> *keywordArrayOut = [NSMutableArray array];\n\n\tfor (NSDictionary<NSString *, NSString *> *keyword in keywordArrayIn) {\n\t\tNSString *s = keyword[@\"string\"];\n\n\t\tif (s && s.length > 0) {\n\t\t\t[keywordArrayOut addObject:s];\n\t\t}\n\t}\n\n\t_excludeKeywords = [keywordArrayOut copy];\n}\n\n+ (void)_loadMatchKeywords\n{\n\tNSArray<NSDictionary *> *keywordArrayIn = [RZUserDefaults() arrayForKey:@\"Highlight List -> Primary Matches\"];\n\n\tNSMutableArray<NSString *> *keywordArrayOut = [NSMutableArray array];\n\n\tfor (NSDictionary<NSString *, NSString *> *keyword in keywordArrayIn) {\n\t\tNSString *s = keyword[@\"string\"];\n\n\t\tif (s && s.length > 0) {\n\t\t\t[keywordArrayOut addObject:s];\n\t\t}\n\t}\n\n\t_matchKeywords = [keywordArrayOut copy];\n}\n\n+ (void)_cleanUpKeywords:(NSString *)key\n{\n\tNSArray<NSDictionary *> *keywordArrayIn = [RZUserDefaults() arrayForKey:key];\n\n\tNSMutableArray<NSString *> *keywordArrayOut = [NSMutableArray array];\n\n\tfor (NSDictionary<NSString *, NSString *> *keyword in keywordArrayIn) {\n\t\tNSString *s = keyword[@\"string\"];\n\n\t\tif (s && s.length > 0) {\n\t\t\t[keywordArrayOut addObject:s];\n\t\t}\n\t}\n\n\t[keywordArrayOut sortUsingSelector:@selector(caseInsensitiveCompare:)];\n\n\tNSArray *arrayToSave = keywordArrayOut.stringArrayControllerObjects;\n\n\t[RZUserDefaults() setObject:arrayToSave forKey:key];\n}\n\n+ (void)cleanUpHighlightKeywords\n{\n\t[self _cleanUpKeywords:@\"Highlight List -> Primary Matches\"];\n\n\t[self _cleanUpKeywords:@\"Highlight List -> Excluded Matches\"];\n}\n\n+ (nullable NSArray<NSString *> *)highlightMatchKeywords\n{\n\treturn _matchKeywords;\n}\n\n+ (nullable NSArray<NSString *> *)highlightExcludeKeywords\n{\n\treturn _excludeKeywords;\n}\n\n#pragma mark -\n#pragma mark Key-Value Observing\n\n+ (void)observeValueForKeyPath:(NSString *)key ofObject:(id)object change:(NSDictionary *)change context:(void *)context\n{\n\tif ([key isEqualToString:@\"Highlight List -> Primary Matches\"]) {\n\t\t[self _loadMatchKeywords];\n\t} else if ([key isEqualToString:@\"Highlight List -> Excluded Matches\"]) {\n\t\t[self _loadExcludeKeywords];\n\t}\n}\n\n#pragma mark -\n#pragma mark Migration\n\n+ (void)_migrateWorldControllerToVersion600\n{\n#define _defaultsKey @\"TPCPreferences -> Migration -> World Controller Migrated (600)\"\n\n\tif ([RZUserDefaults() boolForKey:@\"World Controller Migrated (600)\"]) {\n\t\t[RZUserDefaults() removeObjectForKey:@\"World Controller Migrated (600)\"];\n\n\t\t[RZUserDefaults() setBool:YES forKey:_defaultsKey];\n\t}\n\n\tif ([RZUserDefaults() boolForKey:_defaultsKey]) {\n\t\treturn;\n\t}\n\n\tBOOL clientListMigrated = [RZUserDefaults() boolForKey:_defaultsKey];\n\n\tif (clientListMigrated) {\n\t\treturn;\n\t}\n\n\tNSDictionary *worldController = [RZUserDefaults() dictionaryForKey:@\"World Controller\"];\n\n\tNSArray<NSDictionary *> *clientList = [worldController arrayForKey:@\"clients\"];\n\n\tif (clientList.count > 0) {\n\t\t[self setClientList:clientList];\n\t}\n\n\tBOOL soundIsMuted = [worldController boolForKey:@\"soundIsMuted\"];\n\n\tif (soundIsMuted) {\n\t\t[self setSoundIsMuted:soundIsMuted];\n\t}\n\n\t[RZUserDefaults() setBool:YES forKey:_defaultsKey];\n\n#undef _defaultsKey\n}\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n+ (void)_migrateSparkleConfigurationToVersion601\n{\n\n#define _defaultsKey @\"TPCPreferences -> Migration -> Sparkle (601)\"\n\n\tBOOL sparkleMigrated = [RZUserDefaults() boolForKey:_defaultsKey];\n\n\tif (sparkleMigrated) {\n\t\treturn;\n\t}\n\n\t[[NSUserDefaults standardUserDefaults] removeObjectForKey:@\"SUEnableAutomaticChecks\"];\n\n\t[RZUserDefaults() setBool:YES forKey:_defaultsKey];\n\n#undef _defaultsKey\n\n}\n#endif\n\n+ (void)_migrateNicknameColorOverridesToVersion722\n{\n\t/* Migrate from database that used NSArchiver to one that uses NSKeyedArchiver. */\n\n#define _defaultsKey\t@\"TPCPreferences -> Migration -> Nickname Color Style Overrides\"\n\n\tBOOL overridesMigrated = [RZUserDefaults() boolForKey:_defaultsKey];\n\n\tif (overridesMigrated) {\n\t\treturn;\n\t}\n\n\t[IRCUserNicknameColorStyleGenerator migrateNicknameColorStyleOverrides];\n\n\t[RZUserDefaults() setBool:YES forKey:_defaultsKey];\n\n#undef _defaultsKey\n\n}\n\n+ (void)_migrateAppearanceToVersion7011 /* 7.0.11 turned into 7.1.0 */\n{\n\n#define _defaultsKey @\"TPCPreferences -> Migration -> Appearance (7011)\"\n\n\tBOOL appearanceMigrated = [RZUserDefaults() boolForKey:_defaultsKey];\n\n\tif (appearanceMigrated) {\n\t\treturn;\n\t}\n\n\tBOOL invertSidebarColors = [self invertSidebarColors];\n\n\tif (invertSidebarColors) {\n\t\t[self setAppearance:TXPreferredAppearanceDark];\n\t}\n\n\t[RZUserDefaults() setBool:YES forKey:_defaultsKey];\n\n#undef _defaultsKey\n\n}\n\n#pragma mark -\n#pragma mark Dynamic Defaults \n\n+ (void)registerWebKit2DynamicDefaults\n{\n\t/* The WebKit2 Web Inspector cannot work attached to Textual's main window.\n\t Whose fault this is isn't clear, but I do not have time to take a deep\n\t look at it at this time. To fix it temporarily, we always force it as\n\t window. To prevent the user breaking Textual by attaching it, we force\n\t reset the default here, every run. */\n\n\t[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@\"__WebInspectorPageGroupLevel1__.WebKit2InspectorStartsAttached\"];\n}\n\n+ (void)registerPreferencesDictionaryVersion\n{\n\t/* We do not allow Textual to register a version lower than what is \n\t already set so that if the user opens an older version, we do not\n\t perform migrations more than once. Probably would have been smart\n\t to do this from the beginning. */\n\tNSNumber *dictionaryVersion = [RZUserDefaults() objectForKey:@\"TPCPreferencesDictionaryVersion\"];\n\n\tif (dictionaryVersion.integerValue >= TPCPreferencesDictionaryVersion) {\n\t\treturn;\n\t}\n\n\t[RZUserDefaults() setUnsignedInteger:TPCPreferencesDictionaryVersion forKey:@\"TPCPreferencesDictionaryVersion\"];\n}\n\n#pragma mark -\n#pragma mark Initialization\n\n+ (NSDictionary<NSString *, id> *)defaultPreferences\n{\n\t/* Note added October 2017:\n\n\t I wrote this code a year ago and today (when the note was written),\n\t I took another look at it. 95% of defaults are registered with\n\t RZUserDefaults, not NSUserDefaults. So why has this code never\n\t created a problem?\n\n\t After performing more research, it turns out the registration domain\n\t is app wide. It doesn't care which instance of NSUserDefaults you\n\t set it on or read it from. It will be consistent app wide.\n\n\t This is nothing exciting. I documenting this more for my own sanity. */\n\n\treturn [RZUserDefaults() volatileDomainForName:NSRegistrationDomain];\n}\n\n+ (void)registerDynamicDefaults\n{\n\t[self _populateDefaultNickname];\n\n\t[self registerWebKit2DynamicDefaults];\n\n\tNSMutableDictionary *dynamicDefaults = [NSMutableDictionary dictionary];\n\n\t[dynamicDefaults setBool:[TPCApplicationInfo sandboxEnabled]\t\t\t\t\t\tforKey:@\"Security -> Sandbox Enabled\"];\n\n\t[dynamicDefaults setBool:NO\t\t\t\t\t\t\t\t\tforKey:@\"System -> Running Mac OS Mountain Lion Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_MAVERICKS\t\tforKey:@\"System -> Running Mac OS Mavericks Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_YOSEMITE\t\tforKey:@\"System -> Running Mac OS Yosemite Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_ELCAPITAN\t\tforKey:@\"System -> Running Mac OS El Capitan Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_SIERRA\t\t\tforKey:@\"System -> Running Mac OS Sierra Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_HIGHSIERRA\t\tforKey:@\"System -> Running Mac OS High Sierra Or Newer\"];\n\t[dynamicDefaults setBool:TEXTUAL_RUNNING_ON_MOJAVE\t\t\tforKey:@\"System -> Running Mac OS Mojave Or Newer\"];\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\t[dynamicDefaults setBool:YES forKey:@\"System -> 3rd-party Services -> Built with Sparkle Framework\"];\n#else\n\t[dynamicDefaults setBool:NO forKey:@\"System -> 3rd-party Services -> Built with Sparkle Framework\"];\n#endif\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t[dynamicDefaults setBool:YES forKey:@\"System -> Built with Off-the-Record Messaging Support\"];\n#else\n\t[dynamicDefaults setBool:NO forKey:@\"System -> Built with Off-the-Record Messaging Support\"];\n#endif\n\n\t[RZUserDefaults() registerDefaults:dynamicDefaults];\n\n\t[self registerPreferencesDictionaryVersion];\n}\n\n+ (void)registerDefaults\n{\n\tNSDictionary *localDefaults =\n\t[TPCResourceManager dictionaryFromResources:@\"RegisteredUserDefaults\" inDirectory:@\"Preferences\" cacheValue:NO];\n\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:localDefaults];\n\n\tNSDictionary *containerDefaults =\n\t[TPCResourceManager dictionaryFromResources:@\"RegisteredUserDefaultsInContainer\" inDirectory:@\"Preferences\" cacheValue:NO];\n\n\t[RZUserDefaults() registerDefaults:containerDefaults];\n\n\t[self registerDynamicDefaults];\n}\n\n+ (void)initPreferences\n{\n\t[TPCApplicationInfo incrementApplicationRunCount];\n\n\t// ====================================================== //\n\n\t[self registerDefaults];\n\n\t[self _migrateWorldControllerToVersion600];\n\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\t[self _migrateSparkleConfigurationToVersion601];\n#endif\n\n\t[self _migrateAppearanceToVersion7011];\n\n\t[self _migrateNicknameColorOverridesToVersion722];\n\n\t[TPCPathInfo startUsingTranscriptFolderURL];\n\n\t[RZUserDefaults() addObserver:(id)self forKeyPath:@\"Highlight List -> Excluded Matches\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[RZUserDefaults() addObserver:(id)self forKeyPath:@\"Highlight List -> Primary Matches\" options:NSKeyValueObservingOptionNew context:NULL];\n\n\t[self _loadExcludeKeywords];\n\t[self _loadMatchKeywords];\n}\n\n#pragma mark -\n#pragma mark NSTextView Preferences\n\n+ (BOOL)textFieldAutomaticSpellCheck\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldAutomaticSpellCheck\"];\n}\n\n+ (void)setTextFieldAutomaticSpellCheck:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldAutomaticSpellCheck\"];\n}\n\n+ (BOOL)textFieldAutomaticGrammarCheck\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldAutomaticGrammarCheck\"];\n}\n\n+ (void)setTextFieldAutomaticGrammarCheck:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldAutomaticGrammarCheck\"];\n}\n\n+ (BOOL)textFieldAutomaticSpellCorrection\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldAutomaticSpellCorrection\"];\n}\n\n+ (void)setTextFieldAutomaticSpellCorrection:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldAutomaticSpellCorrection\"];\n}\n\n+ (BOOL)textFieldSmartCopyPaste\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldSmartCopyPaste\"];\n}\n\n+ (void)setTextFieldSmartCopyPaste:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldSmartCopyPaste\"];\n}\n\n+ (BOOL)textFieldSmartQuotes\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldSmartQuotes\"];\n}\n\n+ (void)setTextFieldSmartQuotes:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldSmartQuotes\"];\n}\n\n+ (BOOL)textFieldSmartDashes\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldSmartDashes\"];\n}\n\n+ (void)setTextFieldSmartDashes:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldSmartDashes\"];\n}\n\n+ (BOOL)textFieldSmartLinks\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldSmartLinks\"];\n}\n\n+ (void)setTextFieldSmartLinks:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldSmartLinks\"];\n}\n\n+ (BOOL)textFieldDataDetectors\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldDataDetectors\"];\n}\n\n+ (void)setTextFieldDataDetectors:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldDataDetectors\"];\n}\n\n+ (BOOL)textFieldTextReplacement\n{\n\treturn [RZUserDefaults() boolForKey:@\"TextFieldTextReplacement\"];\n}\n\n+ (void)setTextFieldTextReplacement:(BOOL)value\n{\n\t[RZUserDefaults() setBool:value forKey:@\"TextFieldTextReplacement\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCPreferencesReload.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearancePrivate.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterControllerPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCThemeControllerPrivate.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCCommandIndexPrivate.h\"\n#import \"IRCWorld.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOInputHistoryPrivate.h\"\n#import \"TVCDockIconPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogControllerHistoricLogFilePrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowTextViewPrivate.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TVCMemberListPrivate.h\"\n#import \"TVCMemberListAppearance.h\"\n#import \"TPCPreferencesReload.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Public\n\n@implementation TPCPreferences (TPCPreferencesReload)\n\n+ (void)performReloadActionForKeys:(NSArray<NSString *> *)keys\n{\n\tNSParameterAssert(keys != nil);\n\n\tTPCPreferencesReloadAction reloadAction = 0;\n\n\t/* Style specific reloads... */\n\tif ([keys containsObject:@\"AutomaticallyFilterUnicodeTextSpam\"] ||\n\t\t[keys containsObject:@\"ConversationTrackingIncludesUserModeSymbol\"] ||\n\t\t[keys containsObject:@\"DisableRemoteNicknameColorHashing\"] ||\n\t\t[keys containsObject:@\"DisplayEventInLogView -> Date Changes\"] ||\n\t\t[keys containsObject:@\"DisplayEventInLogView -> Inline Media\"] ||\n\t\t[keys containsObject:@\"DisplayEventInLogView -> Join, Part, Quit\"] ||\n\t\t[keys containsObject:@\"Theme -> Nickname Format\"] ||\n\t\t[keys containsObject:@\"Theme -> Timestamp Format\"] ||\n\t\t[keys containsObject:@\"Theme -> Channel Font Preference Enabled\"] ||\n\t\t[keys containsObject:@\"Theme -> Nickname Format Preference Enabled\"] ||\n\t\t[keys containsObject:@\"Theme -> Timestamp Format Preference Enabled\"] ||\n\t\t[keys containsObject:TPCPreferencesThemeFontNameDefaultsKey] ||\n\t\t[keys containsObject:TPCPreferencesThemeFontSizeDefaultsKey] ||\n\t\t[keys containsObject:TPCPreferencesThemeNameDefaultsKey])\n\t{\n\t\treloadAction |= TPCPreferencesReloadActionStyle;\n\t}\n\n\t/* Highlight lists */\n\tif ([keys containsObject:@\"Highlight List -> Excluded Matches\"] ||\n\t\t[keys containsObject:@\"Highlight List -> Primary Matches\"])\n\t{\n\t\treloadAction |= TPCPreferencesReloadActionHighlightKeywords;\n\t}\n\n\t/* Highlight logging */\n\tif ([keys containsObject:@\"LogHighlights\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionHighlightLogging;\n\t}\n\n\t/* Text direction: right-to-left, left-to-right */\n\tif ([keys containsObject:@\"RightToLeftTextFormatting\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionTextDirection;\n\t}\n\n\t/* Text field font size */\n\tif ([keys containsObject:@\"Main Input Text Field -> Font Size\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionTextFieldFontSize;\n\t}\n\n\t/* Input history scope */\n\tif ([keys containsObject:@\"SaveInputHistoryPerSelection\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionInputHistoryScope;\n\t}\n\n\t/* Main window segmented controller */\n\tif ([keys containsObject:@\"DisableMainWindowSegmentedController\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionTextFieldSegmentedControllerOrigin;\n\t}\n\n\t/* Main window alpha level */\n\tif ([keys containsObject:@\"MainWindowTransparencyLevel\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionMainWindowTransparencyLevel;\n\t}\n\n\t/* Dock icon */\n\tif ([keys containsObject:@\"DisplayDockBadges\"] ||\n\t\t[keys containsObject:@\"DisplayPublicMessageCountInDockBadge\"])\n\t{\n\t\treloadAction |= TPCPreferencesReloadActionDockIconBadges;\n\t}\n\n\t/* Main window appearance */\n\tif ([keys containsObject:@\"Appearance\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionAppearance;\n\t}\n\n\t/* Member list sort order */\n\tif ([keys containsObject:@\"MemberListSortFavorsServerStaff\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionMemberListSortOrder;\n\t}\n\n\t/* Member list user badge colors */\n\tif ([keys containsObject:@\"DisplayUserListNoModeSymbol\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +y\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +q\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +a\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +o\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +h\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> +v\"] ||\n\t\t[keys containsObject:@\"User List Mode Badge Colors -> no mode\"])\n\t{\n\t\treloadAction |= TPCPreferencesReloadActionMemberList;\n\t\treloadAction |= TPCPreferencesReloadActionMemberListUserBadges;\n\t}\n\n\t/* Server list unread count badge colors */\n\tif ([keys containsObject:@\"Server List Unread Message Count Badge Colors -> Highlight\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionServerListUnreadBadges;\n\t}\n\n\t/* Sparkle framework update feed URL */\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tif ([keys containsObject:@\"ReceiveBetaUpdates\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionSparkleFrameworkFeedURL;\n\t}\n#endif\n\n\t/* Developer mode */\n\tif ([keys containsObject:@\"TextualDeveloperEnvironment\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionIRCCommandCache;\n\t}\n\n\t/* Scrollback limit */\n\tif ([keys containsObject:@\"ScrollbackMaximumSavedLineCount\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionScrollbackSaveLimit;\n\t}\n\n\tif ([keys containsObject:@\"ScrollbackMaximumVisibleLineCount\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionScrollbackVisibleLimit;\n\t}\n\n\t/* Channel view arrangement */\n\tif ([keys containsObject:@\"ChannelViewArrangement\"]) {\n\t\treloadAction |= TPCPreferencesReloadActionChannelViewArrangement;\n\t}\n\n\t/* Encryption policy */\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tif ([keys containsObject:@\"Off-the-Record Messaging -> Enable Encryption\"] ||\n\t\t[keys containsObject:@\"Off-the-Record Messaging -> Automatically Enable Service\"] ||\n\t\t[keys containsObject:@\"Off-the-Record Messaging -> Require Encryption\"])\n\t{\n\t\treloadAction |= TPCPreferencesReloadActionEncryptionPolicy;\n\t}\n#endif\n\n\t/* After this is all complete; we call -preferencesChanged just to take \n\t care of everything else that does not need specific reloads. */\n\treloadAction |= TPCPreferencesReloadActionPreferencesChanged;\n\n\t[self performReloadAction:reloadAction];\n}\n\n+ (void)performReloadAction:(TPCPreferencesReloadAction)reloadAction\n{\n\t[self performReloadAction:reloadAction forKey:nil];\n}\n\n+ (void)performReloadAction:(TPCPreferencesReloadAction)reloadAction forKey:(nullable NSString *)key\n{\n\t/* Update dock icon */\n\tif ((reloadAction & TPCPreferencesReloadActionDockIconBadges) == TPCPreferencesReloadActionDockIconBadges) {\n\t\t[TVCDockIcon updateDockIcon];\n\t}\n\n\t/* As reloading the theme will also reload the server and member list, we keep\n\t track of whether that happened so it is not performed more than one time. */\n\tBOOL didReloadActiveStyle = NO;\n\n\tBOOL didReloadUserInterface = NO;\n\n\t/* Member list appearance */\n\tif ((reloadAction & TPCPreferencesReloadActionMemberListUserBadges) == TPCPreferencesReloadActionMemberListUserBadges) {\n\t\t/* We invalidate this early because a separate action may\n\t\t which is attached to our mask may reload the drawings for\n\t\t us so until we know if that happened, we wait. */\n\n\t\t/* If we know FOR CERTAIN we only are ONLY reloading the user badges\n\t\t and we have a key for context, then be more efficient by only updating\n\t\t drawings related to this preference. The member list automatically\n\t\t invalidates its caches when passing a recognized key. */ \n\t\tif (reloadAction == TPCPreferencesReloadActionMemberListUserBadges && key != nil) {\n\t\t\t[mainWindowMemberList() refreshDrawingForChangesToPreference:key];\n\t\t} else {\n\t\t\t[mainWindowMemberList().userInterfaceObjects invalidateUserMarkBadgeCaches];\n\t\t}\n\t}\n\n\t/* Window appearance */\n\tif ((reloadAction & TPCPreferencesReloadActionAppearance) == TPCPreferencesReloadActionAppearance) {\n\t\t[[TXSharedApplication sharedAppearance] updateAppearance];\n\n\t\tdidReloadUserInterface = YES;\n\t}\n\n\t/* Active style */\n\tif ((reloadAction & TPCPreferencesReloadActionStyle) == TPCPreferencesReloadActionStyle) {\n\t\t[themeController() reload];\n\n\t\t[mainWindow() reloadTheme];\n\n\t\tdidReloadActiveStyle = YES;\n\t}\n\n\t/* Server list */\n\tif ((reloadAction & TPCPreferencesReloadActionServerList) == TPCPreferencesReloadActionServerList) {\n\t\tif (didReloadUserInterface == NO) {\n\t\t\t[mainWindowServerList() applicationAppearanceChanged];\n\t\t}\n\t} else if ((reloadAction & TPCPreferencesReloadActionServerListUnreadBadges) == TPCPreferencesReloadActionServerListUnreadBadges) {\n\t\tif (didReloadUserInterface == NO) {\n\t\t\t/* The color used for unread badges also apply to the text color so\n\t\t\t we must reload all drawings instead of only the badges themselves. */\n\t\t\t[mainWindowServerList() refreshAllDrawings];\n\t\t}\n\t}\n\n\t/* Member list appearance */\n\tif ((reloadAction & TPCPreferencesReloadActionMemberList) == TPCPreferencesReloadActionMemberList) {\n\t\tif (didReloadUserInterface == NO) {\n\t\t\t[mainWindowMemberList() applicationAppearanceChanged];\n\t\t}\n\t}\n\n\t/* Member list sort order */\n\tBOOL didReloadMemberListSortOrder = NO;\n\n\tif ((reloadAction & TPCPreferencesReloadActionMemberListSortOrder) == TPCPreferencesReloadActionMemberListSortOrder) {\n\t\tfor (IRCClient *u in worldController().clientList) {\n\t\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t\t[c sortMembers];\n\t\t\t}\n\t\t}\n\n\t\tdidReloadMemberListSortOrder = YES;\n\t}\n\n\t/* Member list appearance */\n\tif ((reloadAction & TPCPreferencesReloadActionMemberList) == TPCPreferencesReloadActionMemberList) {\n\t\t/* Sort order will redraw these for us */\n\t\tif (didReloadMemberListSortOrder == NO) {\n\t\t\t[mainWindowMemberList() refreshAllDrawings];\n\t\t}\n\t}\n\n\t/* Main window segmented controller */\n\tif ((reloadAction & TPCPreferencesReloadActionTextFieldSegmentedControllerOrigin) == TPCPreferencesReloadActionTextFieldSegmentedControllerOrigin) {\n\t\t[mainWindowTextField() reloadOriginPointsAndRecalculateSize];\n\t}\n\n\t/* Main window alpha level */\n\tif ((reloadAction & TPCPreferencesReloadActionMainWindowTransparencyLevel) == TPCPreferencesReloadActionMainWindowTransparencyLevel) {\n\t\t[mainWindow() updateAlphaValueToReflectPreferences];\n\t}\n\n\t/* Highlight keywords */\n\tif ((reloadAction & TPCPreferencesReloadActionHighlightKeywords) == TPCPreferencesReloadActionHighlightKeywords) {\n\t\t[self cleanUpHighlightKeywords];\n\t}\n\n\t/* Highlight logging */\n\tif ((reloadAction & TPCPreferencesReloadActionHighlightLogging) == TPCPreferencesReloadActionHighlightLogging) {\n\t\tif ([self logHighlights] == NO) {\n\t\t\tfor (IRCClient *u in worldController().clientList) {\n\t\t\t\t[u clearCachedHighlights];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Text direction: right-to-left, left-to-right */\n\tif ((reloadAction & TPCPreferencesReloadActionTextDirection) == TPCPreferencesReloadActionTextDirection) {\n\t\t[mainWindowTextField() updateTextDirection];\n\n\t\tif (didReloadActiveStyle == NO) {\n\t\t\t[mainWindow() reloadTheme];\n\t\t}\n\t}\n\n\t/* Text field font size */\n\tif ((reloadAction & TPCPreferencesReloadActionTextFieldFontSize) == TPCPreferencesReloadActionTextFieldFontSize) {\n\t\t[mainWindowTextField() updateTextBasedOnPreferredFontSize];\n\t}\n\n\t/* Input history scope */\n\tif ((reloadAction & TPCPreferencesReloadActionInputHistoryScope) == TPCPreferencesReloadActionInputHistoryScope) {\n\t\t[mainWindow().inputHistoryManager noteInputHistoryObjectScopeDidChange];\n\t}\n\n\t/* Sparkle framework update feed URL */\n#if TEXTUAL_BUILT_WITH_SPARKLE_ENABLED == 1\n\tif ((reloadAction & TPCPreferencesReloadActionSparkleFrameworkFeedURL) == TPCPreferencesReloadActionSparkleFrameworkFeedURL) {\n\t\t[masterController() prepareThirdPartyServiceSparkleFramework];\n\t}\n#endif\n\n\t/* Command index cache */\n\tif ((reloadAction & TPCPreferencesReloadActionIRCCommandCache) == TPCPreferencesReloadActionIRCCommandCache) {\n\t\t[IRCCommandIndex invalidateCaches];\n\t}\n\n\t/* Transcript folder URL */\n\tif ((reloadAction & TPCPreferencesReloadActionLogTranscripts) == TPCPreferencesReloadActionLogTranscripts) {\n\t\tfor (IRCClient *u in worldController().clientList) {\n\t\t\t[u reopenLogFileIfNeeded];\n\n\t\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t\t[c reopenLogFileIfNeeded];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Scrollback limit */\n\tif ((reloadAction & TPCPreferencesReloadActionScrollbackSaveLimit) == TPCPreferencesReloadActionScrollbackSaveLimit) {\n\t\t[TVCLogControllerHistoricLogSharedInstance() resetMaximumLineCount];\n\t}\n\n\tif ((reloadAction & TPCPreferencesReloadActionScrollbackVisibleLimit) == TPCPreferencesReloadActionScrollbackSaveLimit) {\n\t\tfor (IRCClient *u in worldController().clientList) {\n\t\t\t[u.viewController changeScrollbackLimit];\n\n\t\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t\t[c.viewController changeScrollbackLimit];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Channel view arrangement */\n\tif ((reloadAction & TPCPreferencesReloadActionChannelViewArrangement) == TPCPreferencesReloadActionChannelViewArrangement) {\n\t\t[mainWindow() updateChannelViewArrangement];\n\t}\n\n\t/* Encryption policy */\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tif ((reloadAction & TPCPreferencesReloadActionEncryptionPolicy) == TPCPreferencesReloadActionEncryptionPolicy) {\n\t\t[sharedEncryptionManager() updatePolicy];\n\n\t\t/* Maybe remove title bar accessory view if encryption is disabled. */\n\t\t[mainWindow() updateTitle];\n\t}\n#endif\n\n\t/* World controller preferences changed call */\n\tif ((reloadAction & TPCPreferencesReloadActionPreferencesChanged) == TPCPreferencesReloadActionPreferencesChanged) {\n\t\t[worldController() preferencesChanged];\n\n\t\t[mainWindow() preferencesChanged];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCPreferencesUserDefaultsLocal.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCResourceManager.h\"\n#import \"TPCPreferencesUserDefaultsLocal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Reading & Writing\n\ntypedef NS_ENUM(NSUInteger, TPCPreferencesComparator) {\n\tTPCPreferencesComparatorEqual \t\t\t= 0,\n\tTPCPreferencesComparatorAnchorFront\t\t= 1,\n\tTPCPreferencesComparatorAnchorBack\t\t= 2\n};\n\n@interface TPCPreferencesUserDefaults ()\n- (void)_setObject:(nullable id)value forKey:(NSString *)defaultName;\n@end\n\n@implementation TPCPreferencesUserDefaults (TPCPreferencesUserDefaultsLocal)\n\n+ (BOOL)key:(NSString *)defaultName1 matchesKey:(NSString *)defaultName2 usingComparator:(TPCPreferencesComparator)comparator\n{\n\tNSParameterAssert(defaultName1 != nil);\n\tNSParameterAssert(defaultName2 != nil);\n\n\tif (comparator == TPCPreferencesComparatorEqual) {\n\t\tif ([defaultName1 isEqualToString:defaultName2]) {\n\t\t\treturn YES;\n\t\t}\n\t} else if (comparator == TPCPreferencesComparatorAnchorFront) {\n\t\tif ([defaultName1 hasPrefix:defaultName2]) {\n\t\t\treturn YES;\n\t\t}\n\t} else if (comparator == TPCPreferencesComparatorAnchorBack) {\n\t\tif ([defaultName1 hasSuffix:defaultName2]) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n+ (BOOL)keyIsExcludedFromExportImport:(NSString *)defaultName\n{\n\tNSParameterAssert(defaultName != nil);\n\n\tNSDictionary<NSString *, NSNumber *> *cachedValues =\n\t[TPCResourceManager dictionaryFromResources:@\"KeysExcludedFromExport\" inDirectory:@\"Preferences\"];\n\n\t__block BOOL returnValue = NO;\n\n\t[cachedValues enumerateKeysAndObjectsUsingBlock:^(NSString *cachedKey, NSNumber *cachedObject, BOOL *stop) {\n\t\tif ([self key:defaultName matchesKey:cachedKey usingComparator:cachedObject.unsignedIntegerValue]) {\n\t\t\t*stop = YES;\n\n\t\t\treturnValue = YES;\n\t\t}\n\t}];\n\n\tif (returnValue) {\n\t\treturn YES;\n\t}\n\n\treturn ([self keyAppearsInMasterList:defaultName] == NO);\n}\n\n+ (BOOL)keyIsExcludedFromMigration:(NSString *)defaultName\n{\n\tNSParameterAssert(defaultName != nil);\n\n\tNSDictionary<NSString *, NSNumber *> *cachedValues =\n\t[TPCResourceManager dictionaryFromResources:@\"KeysExcludedFromMigrate\" inDirectory:@\"Preferences\"];\n\n\t__block BOOL returnValue = NO;\n\n\t[cachedValues enumerateKeysAndObjectsUsingBlock:^(NSString *cachedKey, NSNumber *cachedObject, BOOL *stop) {\n\t\tif ([self key:defaultName matchesKey:cachedKey usingComparator:cachedObject.unsignedIntegerValue]) {\n\t\t\t*stop = YES;\n\n\t\t\treturnValue = YES;\n\t\t}\n\t}];\n\n\tif (returnValue) {\n\t\treturn YES;\n\t}\n\n\treturn ([self keyAppearsInMasterList:defaultName] == NO);\n}\n\n+ (BOOL)keyAppearsInMasterList:(NSString *)defaultName\n{\n\tNSDictionary<NSString *, NSNumber *> *cachedValues =\n\t[TPCResourceManager dictionaryFromResources:@\"PreferenceKeyMasterList\" inDirectory:@\"Preferences\"];\n\n\t__block BOOL returnValue = NO;\n\n\t[cachedValues enumerateKeysAndObjectsUsingBlock:^(NSString *cachedKey, NSNumber *cachedObject, BOOL *stop) {\n\t\tif ([self key:defaultName matchesKey:cachedKey usingComparator:cachedObject.unsignedIntegerValue]) {\n\t\t\t*stop = YES;\n\n\t\t\treturnValue = YES;\n\t\t}\n\t}];\n\n\treturn returnValue;\n}\n\n+ (BOOL)keyIsExcludedFromContainer:(NSString *)defaultName\n{\n\tNSParameterAssert(defaultName != nil);\n\n\tNSDictionary<NSString *, NSNumber *> *cachedValues =\n\t[TPCResourceManager dictionaryFromResources:@\"KeysExcludedFromContainer\" inDirectory:@\"Preferences\"];\n\n\t__block BOOL returnValue = NO;\n\n\t[cachedValues enumerateKeysAndObjectsUsingBlock:^(NSString *cachedKey, NSNumber *cachedObject, BOOL *stop) {\n\t\tif ([self key:defaultName matchesKey:cachedKey usingComparator:cachedObject.unsignedIntegerValue]) {\n\t\t\t*stop = YES;\n\n\t\t\treturnValue = YES;\n\t\t}\n\t}];\n\n\treturn returnValue;\n}\n\n- (void)_migrateObject:(nullable id)value forKey:(NSString *)defaultName\n{\n\tif ([TPCPreferencesUserDefaults keyIsExcludedFromContainer:defaultName]) {\n\t\t[[NSUserDefaults standardUserDefaults] setObject:value forKey:defaultName];\n\n\t\treturn;\n\t}\n\n\t[self _setObject:value forKey:defaultName];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCResourceManager.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCAlert.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPathInfo.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCResourceManagerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TPCResourceManagerBundleDocumentTypeExtension\t\t\t\t\t= @\".bundle\";\nNSString * const TPCResourceManagerBundleDocumentTypeExtensionWithoutPeriod\t\t= @\"bundle\";\n\nNSString * const TPCResourceManagerScriptDocumentTypeExtension\t\t\t\t\t= @\".scpt\";\nNSString * const TPCResourceManagerScriptDocumentTypeExtensionWithoutPeriod\t\t= @\"scpt\";\n\n@implementation TPCResourceManager\n\n+ (void)copyResourcesToApplicationSupportFolder\n{\n\t/* Add a system link for the unsupervised scripts folder if it exists. */\n\tNSString *sourcePath = [TPCPathInfo customScripts];\n\n\tNSString *destinationPath = [[TPCPathInfo groupContainerApplicationSupport] stringByAppendingPathComponent:@\"/Custom Scripts/\"];\n\n\tif ([RZFileManager() fileExistsAtPath:sourcePath] &&\n\t\t[RZFileManager() fileExistsAtPath:destinationPath] == NO)\n\t{\n\t\t[RZFileManager() createSymbolicLinkAtPath:destinationPath withDestinationPath:sourcePath error:NULL];\n\t}\n}\n\n+ (NSCache *)sharedResourcesCache\n{\n\tstatic NSCache *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue = [NSCache new];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name\n{\n\treturn [self dictionaryFromResources:name inDirectory:nil key:nil cacheValue:YES];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath\n{\n\treturn [self dictionaryFromResources:name inDirectory:subpath key:nil cacheValue:YES];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath cacheValue:(BOOL)cacheValue\n{\n\treturn [self dictionaryFromResources:name inDirectory:subpath key:nil cacheValue:cacheValue];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name cacheValue:(BOOL)cacheValue\n{\n\treturn [self dictionaryFromResources:name inDirectory:nil key:nil cacheValue:cacheValue];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name key:(nullable NSString *)key\n{\n\treturn [self dictionaryFromResources:name inDirectory:nil key:key cacheValue:YES];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name key:(nullable NSString *)key cacheValue:(BOOL)cacheValue\n{\n\treturn [self dictionaryFromResources:name inDirectory:nil key:key cacheValue:cacheValue];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key\n{\n\treturn [self dictionaryFromResources:name inDirectory:subpath key:key cacheValue:YES];\n}\n\n+ (nullable NSDictionary<NSString *, id> *)dictionaryFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key cacheValue:(BOOL)cacheValue\n{\n\treturn [self objectFromResources:name inDirectory:subpath key:key kindOf:[NSDictionary class] cacheValue:cacheValue];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name\n{\n\treturn [self arrayFromResources:name inDirectory:nil key:nil cacheValue:YES];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath\n{\n\treturn [self arrayFromResources:name inDirectory:subpath key:nil cacheValue:YES];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath cacheValue:(BOOL)cacheValue\n{\n\treturn [self arrayFromResources:name inDirectory:subpath key:nil cacheValue:cacheValue];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name cacheValue:(BOOL)cacheValue\n{\n\treturn [self arrayFromResources:name inDirectory:nil key:nil cacheValue:cacheValue];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name key:(nullable NSString *)key\n{\n\treturn [self arrayFromResources:name inDirectory:nil key:key cacheValue:YES];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name key:(nullable NSString *)key cacheValue:(BOOL)cacheValue\n{\n\treturn [self arrayFromResources:name inDirectory:nil key:key cacheValue:cacheValue];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key\n{\n\treturn [self arrayFromResources:name inDirectory:subpath key:key cacheValue:YES];\n}\n\n+ (nullable NSArray *)arrayFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key cacheValue:(BOOL)cacheValue\n{\n\treturn [self objectFromResources:name inDirectory:subpath key:key kindOf:[NSArray class] cacheValue:cacheValue];\n}\n\n+ (nullable id)objectFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key kindOf:(Class)class cacheValue:(BOOL)cacheValue\n{\n\tNSParameterAssert(name != nil);\n\n\t/* Bypass cache? */\n\tif (cacheValue == NO) {\n\t\treturn [self _objectFromResources:name inDirectory:subpath key:key kindOf:class];\n\t}\n\n\t/* Cache hit? */\n\tNSString *cacheKey = [NSString stringWithFormat:@\"%@.plist / %@ / %@\",\n\t\tname, ((subpath) ?: @\"Root Folder\"), ((key) ?: @\"Root Object\")];\n\n\tNSCache *cache = self.sharedResourcesCache;\n\n\tid cachedValue = [cache objectForKey:cacheKey];\n\n\tif (cachedValue) {\n\t\treturn cachedValue;\n\t}\n\n\t/* No cache hit, generate */\n\tcachedValue = [self _objectFromResources:name inDirectory:subpath key:key kindOf:class];\n\n\tif (cachedValue) {\n\t\t[cache setObject:cachedValue forKey:cacheKey];\n\t}\n\n\treturn cachedValue;\n}\n\n+ (nullable id)_objectFromResources:(NSString *)name inDirectory:(nullable NSString *)subpath key:(nullable NSString *)key kindOf:(Class)class\n{\n\t/* Locate resource */\n\tNSURL *resourceURL = [RZMainBundle() URLForResource:name withExtension:@\"plist\" subdirectory:subpath];\n\n\tif (resourceURL == nil) {\n\t\tLogToConsoleError(\"Resource '%{public}@' in subpath '%{public}@' was not found.\",\n\t\t\tname, ((subpath) ?: @\"<No subpath>\"));\n\n\t\treturn nil;\n\t}\n\n\t/* Read resource */\n\tNSError *readError = nil;\n\n\tNSData *fileContents = [NSData dataWithContentsOfURL:resourceURL options:0 error:&readError];\n\n\tif (readError) {\n\t\tLogToConsoleError(\"Resource '%{public}@' could not be read with error: %{public}@\",\n\t\t\tresourceURL.standardizedTildePath, readError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\t/* Process as a property list */\n\tNSError *parseError = nil;\n\n\tid propertyList =\n\t[NSPropertyListSerialization propertyListWithData:fileContents\n\t\t\t\t\t\t\t\t\t\t\t  options:NSPropertyListImmutable\n\t\t\t\t\t\t\t\t\t\t\t   format:NULL\n\t\t\t\t\t\t\t\t\t\t\t\terror:&parseError];\n\n\tif (parseError) {\n\t\tLogToConsoleFault(\"Resource '%{public}@' could not be parsed as a property list with error: %{public}@\",\n\t\t\tresourceURL.standardizedTildePath, parseError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\t/* Locate object */\n\t/* Until we know otherwise, the value is the root object. */\n\tid objectValue = nil;\n\n\tif (key == nil) {\n\t\tobjectValue = propertyList;\n\t} else {\n\t\t/* Property list can be an array. */\n\t\tif ([propertyList isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\tLogToConsoleError(\"Contents of resource '%{public}@' is not a dictionary. \"\n\t\t\t\t\t\t\t  \"Cannot locate value of 'key' in other formats.\",\n\t\t\t\t\t\t\t  resourceURL.standardizedTildePath);\n\n\t\t\treturn nil;\n\t\t}\n\n\t\tobjectValue = [propertyList objectForKey:key];\n\t}\n\n\tif ([objectValue isKindOfClass:class] == NO) {\n\t\tLogToConsoleError(\"Contents of key '%{public}@' in resource '%{public}@' is not kind of class: %{public}@\",\n\t\t\t((key) ?: @\"<Root Object>\"), resourceURL.standardizedTildePath, NSStringFromClass(class));\n\n\t\treturn nil;\n\t}\n\n\treturn objectValue;\n}\n\n@end\n\n#pragma mark -\n\n@implementation TPCResourceManagerDocumentTypeImporter\n\n+ (BOOL)autosavesInPlace\n{\n\t/* We are read-only. This suppresses a warning in console. */\n\treturn YES;\n}\n\n- (BOOL)readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError\n{\n\tNSString *filePath = url.filePathURL.absoluteString;\n\n\tif ([filePath hasSuffix:TPCResourceManagerScriptDocumentTypeExtension]) {\n\t\t[self performImportOfScriptFile:url];\n\n\t\treturn YES;\n\t}\n\n\tNSString *pluginSuffix = [TPCResourceManagerBundleDocumentTypeExtension stringByAppendingString:@\"/\"];\n\n\tif ([filePath hasSuffix:pluginSuffix]) {\n\t\t[self performImportOfPluginFile:url];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Custom Plugin Files\n\n- (void)performImportOfPluginFile:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *filename = url.lastPathComponent;\n\n\tBOOL performInstall = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[6tj-yp]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[xfl-8e]\", filename)\n\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\tif (performInstall == NO) {\n\t\treturn;\n\t}\n\n\tNSURL *newPath = [[TPCPathInfo customExtensionsURL] URLByAppendingPathComponent:filename];\n\n\tBOOL didImport = [self import:url into:newPath];\n\n\tif (didImport) {\n\t\tNSString *filenameWithoutExtension = filename.stringByDeletingPathExtension;\n\n\t\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[k69-q0]\")\n\t\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[xek-0t]\", filenameWithoutExtension)\n\t\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\t\talternateButton:nil];\n\t}\n}\n\n#pragma mark -\n#pragma mark Custom Script Files\n\n- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError\n{\n\tNSString *scriptsPath = [TPCPathInfo customScripts];\n\n\tif ([url.path hasPrefix:scriptsPath] == NO) {\n\t\tif (outError) {\n\t\t\tNSMutableDictionary<NSString *, id> *userInfo = [NSMutableDictionary dictionary];\n\n\t\t\tuserInfo[NSURLErrorKey] = url;\n\n\t\t\tuserInfo[NSLocalizedDescriptionKey] = TXTLS(@\"Prompts[m2r-gv]\");\n\t\t\tuserInfo[NSLocalizedRecoverySuggestionErrorKey] = TXTLS(@\"Prompts[ztu-nv]\");\n\n\t\t\t*outError = [NSError errorWithDomain:TXErrorDomain code:27984 userInfo:userInfo];\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n- (void)performImportOfScriptFile:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *filename = url.lastPathComponent;\n\n\t/* Ask user before installing. */\n\tBOOL performInstall = [TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[6tj-yp]\")\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle:TXTLS(@\"Prompts[xfl-8e]\", filename)\n\t\t\t\t\t\t\t\t\t\t\tdefaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\t\t\t\t\t\t  alternateButton:TXTLS(@\"Prompts[99q-gg]\")];\n\n\tif (performInstall == NO) {\n\t\treturn; // Do not install.\n\t}\n\n#if TEXTUAL_BUILT_INSIDE_SANDBOX == 0\n\tNSURL *newPath = [[TPCPathInfo customScriptsURL] URLByAppendingPathComponent:filename];\n\n\tBOOL didImport = [self import:url into:newPath];\n\n\tif (didImport) {\n\t\t[self performImportOfScriptFilePostflight:filename];\n\t}\n#else\n\tNSURL *folderRep = [TPCPathInfo customScriptsURL];\n\n\tif ([RZFileManager() fileExistsAtURL:folderRep] == NO) {\n\t\tfolderRep = [TPCPathInfo userApplicationScriptsURL];\n\t}\n\n\tNSString *bundleID = [TPCApplicationInfo applicationBundleIdentifier];\n\n\tNSSavePanel *d = [NSSavePanel savePanel];\n\n\td.delegate = (id)self;\n\n\td.canCreateDirectories = YES;\n\n\td.directoryURL = folderRep;\n\n\td.title = TXTLS(@\"Prompts[6hx-ni]\");\n\n\td.message = TXTLS(@\"Prompts[0bj-ic]\", bundleID);\n\n\td.nameFieldStringValue = url.lastPathComponent;\n\n\td.showsTagField = NO;\n\n\t[d beginWithCompletionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode == NSModalResponseOK) {\n\t\t\tif ([self import:url into:d.URL] == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSString *filename = d.URL.lastPathComponent;\n\n\t\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t\t[self performImportOfScriptFilePostflight:filename];\n\t\t\t});\n\t\t}\n\t}];\n#endif\n}\n\n- (void)performImportOfScriptFilePostflight:(NSString *)filename\n{\n\tNSParameterAssert(filename != nil);\n\n\tNSString *filenameWithoutExtension = filename.stringByDeletingPathExtension;\n\n\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[3ze-xh]\", filenameWithoutExtension)\n\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[4ua-v5]\", filenameWithoutExtension)\n\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\t\talternateButton:nil];\n}\n\n#pragma mark -\n#pragma mark General Import Controller\n\n- (BOOL)import:(NSURL *)url into:(NSURL *)destination\n{\n\treturn [RZFileManager() replaceItemAtURL:destination\n\t\t\t\t\t\t\t   withItemAtURL:url\n\t\t\t\t\t\t\t\t\t options:(CSFileManagerOptionsMoveToTrash |\n\t\t\t\t\t\t\t\t\t\t\t  CSFileManagerOptionsRemoveIfExists)];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/TPCSandboxMigration.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *   Copyright (c) 2024 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCPreferencesUserDefaultsLocal.h\"\n#import \"TPCSandboxMigrationPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/*\n Standalone Classic - This refers to an installation of Textual 7\n downloaded from codeux.com before the transition to sandbox.\n\n Mac App Store - This refers to an installation of Textual 7\n downloaded from the Mac App Store.\n\n Migration steps:\n\t1. \tCheck the age of the current group container.\n\t\tIf it wasn't recently created. Like within the\n\t\tspan of a few seconds ago, then stop.\n\t2. \tLocate Standalone Classic preferences\n\t3. \tIf located, is the value of TXRunCount >= 1\n\t\tIf yes, perform migration on that installation.\n\t4. \tIf migration is not performed, then locate\n\t\tMac App Store preferences if this is the first\n\t\ttime this installation of Textual has launched.\n\t5. \tIf located, is the value of TXRunCount >= 1\n\t\tIf yes, have the preferences been modified with\n\t\tthe last 30 days (see MaximumAgeOfStalePreferences)\n\t\tIf yes, perform migration on that installation.\n\n Data and files are migrated by creating copies.\n After migration is completed, the user will be asked if\n they want to remove (delete / erase) the old contents.\n*/\n\n/* Textual will import preferences from a Mac App Store purchase\n if this is the first launch. This macro defines the maximum amount\n of time that was allowed to elapse since the preferences for that\n installation was last modified. We don't want to import an installation\n that the user setup a year ago on a whim and only used it a day. */\n#define MaximumAgeOfStalePreferences \t\t(60 * 60 * 24 * 30)  // 30 days\n\n/* Defaults key set after migration is performed. */\n/* YES if migration was completed */\n#define MigrationCompleteDefaultsKey\t\t\t\t\t@\"Sandbox Migration -> Migrated Resources\"\n\n/* Integer for the installation that was migrated */\n/* nil value or zero result is possible even after migration\n is complete because nothing might have been migrated. */\n/* Migration is designed to be one shot. */\n#define MigrationInstallationMigratedDefaultsKey\t\t@\"Sandbox Migration -> Installation Migrated\"\n\n/* Whether the user has dismissed the notification alert */\n#define MigrationUserAcknowledgedDefaultsKey\t\t\t@\"Sandbox Migration -> User Acknowledged\"\n\n/* Whether the user wants to delete old files */\n#define MigrationUserPrefersPruningDefaultsKey\t\t\t@\"Sandbox Migration -> User Prefers Pruning Files\"\n\n/* YES if there are no more extensions to prune\n which means we can bypass all the directory scans. */\n#define MigrationAllExtensionsPrunedDefaultsKey\t\t\t@\"Sandbox Migration -> All Extensions Pruned\"\n\n/* An array of preference keys migrated */\n#define MigrationKeysImportedDefaultsKey\t\t\t\t@\"Sandbox Migration -> Imported Keys\"\n\n/* Result returned when performing migration of a specific installation. */\ntypedef NS_ENUM(NSUInteger, TPCMigrateSandboxResult)\n{\n\t/* Migration was performed successfully */\n\tTPCMigrateSandboxResultSuccess,\n\n\t/* Candidate for migration is not suitable.\n\t For example, a Mac App Store installation was located\n\t but the age of its preference file is out of range. */\n\tTPCMigrateSandboxResultNotSuitable,\n\n\t/* An error occurred during migration. */\n\t/* Errors are logged to console. */\n\tTPCMigrateSandboxResultError\n};\n\n/* The installation attempting migration / migrated */\ntypedef NS_ENUM(NSUInteger, TPCMigrateSandboxInstallation)\n{\n\t/* Standalone Classic */\n\tTPCMigrateSandboxInstallationStandaloneClassic \t= 100,\n\n\t/* Mac App Store */\n\tTPCMigrateSandboxInstallationMacAppStore\t\t= 200\n};\n\n@interface TPCPathInfo (TPCSandboxMigration)\n+ (nullable NSURL *)_groupContainerURLForInstallation:(TPCMigrateSandboxInstallation)installation;\n+ (nullable NSURL *)_groupContainerPreferencesURLForInstallation:(TPCMigrateSandboxInstallation)installation;\n+ (nullable NSURL *)_groupContainerExtensionsURLForInstallation:(TPCMigrateSandboxInstallation)installation;\n@end\n\n@interface TPCResourceManager (TPCSandoxMigration)\n+ (nullable NSArray<NSURL *> *)_listOfExtensionsForInstallation:(TPCMigrateSandboxInstallation)installation;\n+ (BOOL)_ageOfCurrentContainerIsRecent;\n+ (NSTimeInterval)_modificationDateForMacAppStorePreferencesIsRecent;\n+ (NSTimeInterval)_intervalSinceCreatedForURL:(NSURL *)url;\n+ (NSTimeInterval)_intervalSinceLastModificationForURL:(NSURL *)url;\n+ (BOOL)_URLIsSymbolicLink:(NSURL *)url;\n@end\n\n@interface TPCPreferencesUserDefaults ()\n- (void)_migrateObject:(nullable id)value forKey:(NSString *)defaultName;\n@end\n\n@implementation TPCSandboxMigration\n\n+ (void)migrateResources\n{\n\tLogToConsole(\"Preparing to migrate group containers\");\n\n\t/* Do not migrate if we have done so in the past. */\n\tif ([RZUserDefaults() boolForKey:MigrationCompleteDefaultsKey]) {\n\t\t[self _notifyGroupContainerMigratedFromDefaults];\n\t\t[self _pruneExtensionSymbolicLinksFromDefaults];\n\n\t\tLogToConsole(\"Group containers have already been migrated\");\n\n\t\treturn;\n\t}\n\n\t/* Do not migrate if the age of the current group container is not recent.\n\t The age is only going to be recent the launch it was created. */\n\tif ([TPCResourceManager _ageOfCurrentContainerIsRecent] == NO) {\n\t\t[self _setMigrationCompleteAndAcknowledged];\n\n\t\tLogToConsole(\"Current group container was not created recently\");\n\n\t\treturn;\n\t}\n\n\t/* The order of this array is the order of preference for migration.\n\t If one migrates, then it stops there. */\n\t/* I acknowledge creating a list of numbers just to enumerate them\n\t is not efficient. This will be ran once. It's okay. :) */\n\tNSArray *installations = @[@(TPCMigrateSandboxInstallationStandaloneClassic),\n\t\t\t\t\t\t\t   @(TPCMigrateSandboxInstallationMacAppStore)];\n\n\tfor (NSNumber *installationRef in installations) {\n\t\tif ([self _migrateInstallationEntry:installationRef]) {\n\t\t\treturn; // Success\n\t\t}\n\t}\n\n\t/* No other migration path */\n\t[self _setMigrationCompleteAndAcknowledged];\n}\n\n#pragma mark -\n#pragma mark Standalone Classic Migration\n\n+ (BOOL)_migrateInstallationEntry:(NSNumber *)installationRef\n{\n\tNSParameterAssert(installationRef != nil);\n\n\tTPCMigrateSandboxInstallation installation = installationRef.unsignedIntegerValue;\n\n\tNSString *description = [self _descriptionOfInstallation:installation];\n\n\tLogToConsole(\"Start: Migrating [%{public}@] installation\", description);\n\n\tTPCMigrateSandboxResult result = [self _migrateInstallation:installation];\n\n\tswitch (result) {\n\t\tcase TPCMigrateSandboxResultSuccess:\n\t\t\t[self _setMigrationCompleteForInstallation:installation];\n\n\t\t\tLogToConsole(\"End: Migrating [%{public}@] successful\", description);\n\n\t\t\treturn YES; // Stop further migration\n\t\tcase TPCMigrateSandboxResultError:\n\t\t\tLogToConsole(\"End: Migrating [%{public}@] failed. Stopping all migration\", description);\n\n\t\t\treturn YES; // Stop further migration\n\t\tcase TPCMigrateSandboxResultNotSuitable:\n\t\t\tLogToConsole(\"End: Migrating [%{public}@] failed. Installation is not suitable\", description);\n\n\t\t\treturn NO; // Allow further migration\n\t}\n}\n\n+ (TPCMigrateSandboxResult)_migrateInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\t/* Preflight checks */\n\tBOOL isMacAppStore = (installation == TPCMigrateSandboxInstallationMacAppStore);\n\n\tif (isMacAppStore && [TPCResourceManager _modificationDateForMacAppStorePreferencesIsRecent] == NO) {\n\t\tLogToConsoleDebug(\"Migration of Mac App Store has stale preferences file\");\n\n\t\treturn TPCMigrateSandboxResultNotSuitable;\n\t}\n\n\tNSString *suiteName = [self _defaultsSuiteNameForInstallation:installation];\n\n\tNSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName];\n\n\tif (defaults == nil) {\n\t\tLogToConsole(\"NSUserDefaults object could not be created for [%{public}@] domain: '%{public}@'\",\n\t\t\t[self _descriptionOfInstallation:installation], ((suiteName) ?: @\"<no suite name>\"));\n\n\t\treturn TPCMigrateSandboxResultNotSuitable;\n\t}\n\n\t/* Import preference keys */\n\t/* Import preferences before migrating group container that way if a\n\t hard failure is encountered there, it wont undo the progress we made.\n\t The user will want something rather than nothing. Especially when it\n\t comes to their configuration. Custom content can be copied manually. */\n\tNSDictionary *preferences = defaults.dictionaryRepresentation;\n\n\tNSUInteger runCount = [preferences unsignedIntegerForKey:@\"TXRunCount\"];\n\n\tif (runCount == 0) {\n\t\tLogToConsoleError(\"Migration of [%{public}@] has zero run count\",\n\t\t\t[self _descriptionOfInstallation:installation]);\n\n\t\treturn TPCMigrateSandboxResultNotSuitable;\n\t}\n\n\t/* Import preferences */\n\tNSArray *importedKeys = [self _importPreferences:preferences];\n\n\t/* Migrate group container */\n\tBOOL migrateContainer = [self _migrateGroupContainerContentsForInstallation:installation];\n\n\tif (migrateContainer == NO) {\n\t\treturn TPCMigrateSandboxResultError;\n\t}\n\n\t/* Finish */\n\t[self _setListOfImportedKeys:importedKeys];\n\n\t[self _notifyGroupContainerMigratedForInstallation:installation];\n\n\treturn TPCMigrateSandboxResultSuccess;\n}\n\n+ (NSArray<NSString *> *)_importPreferences:(NSDictionary<NSString *, id> *)dict\n{\n\tNSParameterAssert(dict != nil);\n\n\tLogToConsole(\"Start: Migrating preferences\");\n\n\tNSMutableArray *importedKeys = [NSMutableArray arrayWithCapacity:dict.count];\n\n\t[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, id object, BOOL *stop) {\n\t\tif ([TPCPreferencesUserDefaults keyIsExcludedFromMigration:key]) {\n#ifdef DEBUG\n\t\t\tLogToConsoleDebug(\"Key is excluded from migration: '%{public}@'\", key);\n#endif\n\n\t\t\treturn;\n\t\t}\n\n\t\t[importedKeys addObject:key];\n\n\t\t[RZUserDefaults() _migrateObject:object forKey:key];\n\t}];\n\n\tLogToConsole(\"End: Migrating preferences\");\n\n\treturn [importedKeys copy];\n}\n\n+ (void)_removeImportedKeysForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tLogToConsole(\"Start: Remove old preferences\");\n\n\tNSArray *listOfKeys = [RZUserDefaults() arrayForKey:MigrationKeysImportedDefaultsKey];\n\n\tif (listOfKeys == nil) {\n\t\tLogToConsole(\"No preferences to remove\");\n\n\t\treturn;\n\t}\n\n\tNSUserDefaults *defaults = \n\t[[NSUserDefaults alloc] initWithSuiteName:[self _defaultsSuiteNameForInstallation:installation]];\n\n\tif (defaults == nil) {\n\t\tLogToConsole(\"NSUserDefaults object could not be created for [%{public}@] installation\",\n\t\t\t[self _descriptionOfInstallation:installation]);\n\n\t\treturn;\n\t}\n\n\tfor (id key in listOfKeys) {\n\t\t/* This data could have been manipulated from the outside. */\n\t\tif ([key isKindOfClass:[NSString class]] == NO) {\n\t\t\tLogToConsoleFault(\"Corrupted data found inside list of keys\");\n\n\t\t\tcontinue;\n\t\t}\n\n#ifdef DEBUG\n\t\tLogToConsoleDebug(\"Removing key: '%{public}@'\", key);\n#endif\n\n\t\t[defaults removeObjectForKey:key];\n\t}\n\n\t[self _unsetListOfImportedKeys];\n\n\tLogToConsole(\"End: Remove old preferences - Removed: %{public}lu\", listOfKeys.count);\n}\n\n+ (void)_setListOfImportedKeys:(nullable NSArray<NSString *> *)list\n{\n\t[RZUserDefaults() _migrateObject:list forKey:MigrationKeysImportedDefaultsKey];\n}\n\n+ (void)_unsetListOfImportedKeys\n{\n\t[self _setListOfImportedKeys:nil];\n}\n\n+ (void)_setMigrationComplete\n{\n\t[RZUserDefaults() _migrateObject:@(YES) forKey:MigrationCompleteDefaultsKey];\n}\n\n+ (void)_setMigrationCompleteAndAcknowledged\n{\n\t/* This method is called when there was nothing to migrate\n\t so we set complete and pretend user acknowledged it. */\n\t[self _setMigrationComplete];\n\n\t[self _setUserAcknowledgedMigration];\n}\n\n+ (void)_setMigrationCompleteForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\t[RZUserDefaults() _migrateObject:@(installation) forKey:MigrationInstallationMigratedDefaultsKey];\n\n\t[self _setMigrationComplete];\n}\n\n#pragma mark -\n#pragma mark Group Container Migration\n\n+ (BOOL)_migrateGroupContainerContentsForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tLogToConsole(\"Start: Migrate group container for '%{public}@'\",\n\t\t[self _descriptionOfInstallation:installation]);\n\n\tNSURL *oldLocation = [TPCPathInfo _groupContainerURLForInstallation:installation];\n\n\tif (oldLocation == nil) {\n\t\tLogToConsoleError(\"Cannot migrate group container contents because of nil source location\");\n\n\t\treturn NO;\n\t}\n\n\tNSURL *newLocation = [TPCPathInfo groupContainerURL];\n\n\tif (newLocation == nil) {\n\t\tLogToConsoleError(\"Cannot migrate group container contents because of nil destination location\");\n\n\t\treturn NO;\n\t}\n\n\t/* Migration is performed by recursively copying contents effectively merging the contents. */\n\t/* If a file already exists, it will not be overwrote under any condition. */\n\t/* This should only be performed with no real resources in the group container\n\t destination group container anyways so this wont matter much. */\n\tBOOL result =\n\t[RZFileManager() mergeDirectoryAtURL:oldLocation\n\t\t\t\t\t  withDirectoryAtURL:newLocation\n\t\t\t\t\t\t\t\t options:(CSFileManagerOptionsEnumerateDirectories |\n\t\t\t\t\t\t\t\t\t\t  CSFileManagerOptionContinueOnError |\n\t\t\t\t\t\t\t\t\t\t  CSFileManagerOptionsCreateDirectory |\n\t\t\t\t\t\t\t\t\t\t  CSFileManagerCreateSymbolicLinkForPackages)];\n\n\tLogToConsole(\"End: Migrate group container - Result: %{BOOL}d\", result);\n\n\treturn result;\n}\n\n+ (void)_notifyGroupContainerMigratedForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tLogToConsole(\"Notifying user that installation of type [%{public}@] migration performed\",\n\t\t[self _descriptionOfInstallation:installation]);\n\n\tTVCAlert *alert =\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[qy4-5o]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[ios-na]\")\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[zjw-bd]\")\n\t\t\t   alternateButton:nil\n\t\t\t\t   otherButton:TXTLS(@\"Prompts[d90-au]\")\n\t\t\t\tsuppressionKey:nil\n\t\t\t   suppressionText:TXTLS(@\"Prompts[q3t-45]\")\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id  _Nullable underlyingAlert) \n\t {\n\t\t[self _setUserAcknowledgedMigration];\n\n\t\tif (suppressed) {\n\t\t\t[self _setUserPrefersPruningFiles];\n\n\t\t\t[self _removeImportedKeysForInstallation:installation];\n\t\t\t[self _removeGroupContainerContentsForInstallation:installation];\n\t\t} else {\n\t\t\t[self _unsetListOfImportedKeys];\n\t\t}\n\t}];\n\n\t[alert setButtonClickedBlock:^BOOL(TVCAlert *sender, TVCAlertResponseButton buttonClicked) {\n\t\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/miscellaneous/Why-Did-Textual-Copy-Files-to-a-New-Location.kb\" inBackground:NO];\n\n\t\treturn NO;\n\t} forButton:TVCAlertResponseButtonThird];\n}\n\n+ (void)_notifyGroupContainerMigratedFromDefaults\n{\n\t/* This method is only invoked internally if the defaults key\n\t MigrationCompleteDefaultsKey is set which means we are just\n\t asking the user what they want to do with their files until\n\t they acknowledge the alert. */\n\tBOOL userAcknowledged = [RZUserDefaults() boolForKey:MigrationUserAcknowledgedDefaultsKey];\n\n\tif (userAcknowledged) {\n\t\treturn; // Stop migration\n\t}\n\n\tTPCMigrateSandboxInstallation installation = [RZUserDefaults() unsignedIntegerForKey:MigrationInstallationMigratedDefaultsKey];\n\n\tif ([self _isInstallationSupported:installation] == NO) {\n\t\t[self _setUserAcknowledgedMigration];\n\n\t\treturn; // Stop migration\n\t}\n\n\t[self _notifyGroupContainerMigratedForInstallation:installation];\n}\n\n+ (void)_setUserAcknowledgedMigration\n{\n\t[RZUserDefaults() _migrateObject:@(YES) forKey:MigrationUserAcknowledgedDefaultsKey];\n}\n\n+ (void)_setUserPrefersPruningFiles\n{\n\t[RZUserDefaults() _migrateObject:@(YES) forKey:MigrationUserPrefersPruningDefaultsKey];\n}\n\n#pragma mark -\n#pragma mark Group Container Removal\n\n+ (BOOL)_removeGroupContainerContentsForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tLogToConsole(\"Start: Remove group container for '%{public}@'\",\n\t\t[self _descriptionOfInstallation:installation]);\n\n\tNSURL *gcLocation = [TPCPathInfo _groupContainerURLForInstallation:installation];\n\n\tif (gcLocation == nil) {\n\t\tLogToConsoleError(\"Cannot remove group container contents because of nil location\");\n\n\t\treturn NO;\n\t}\n\n\t/* -_listOfExtensionsForInstallation: should only return nil on fatal errors.\n\t It will not return nil for an extension folder that does not exist, or is empty. */\n\tNSArray *oldExtensions = [TPCResourceManager _listOfExtensionsForInstallation:installation];\n\n\tif (gcLocation == nil) {\n\t\tLogToConsoleError(\"Cannot remove group container contents because of nil extension list\");\n\n\t\treturn NO;\n\t}\n\n\tLogToConsole(\"Removing group container contents at URL: %{public}@\", gcLocation.standardizedTildePath);\n\n\tBOOL result = [RZFileManager() removeContentsOfDirectoryAtURL:gcLocation\n\t\t\t\t\t\t\t\t\t\t\t\t\texcludingURLs:oldExtensions\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t  options:(CSFileManagerOptionContinueOnError)];\n\n\tLogToConsole(\"End: Remove group container - Result: %{BOOL}d\", result);\n\n\treturn result;\n}\n\n#pragma mark -\n#pragma mark Extension Pruning\n\n+ (void)_pruneExtensionSymbolicLinksForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\t/* When you create a copy of a bundle programmatically, macOS will move it to\n\t quarantine. The user is then notified macOS can't verify that it isn't malware.\n\t That is less than ideal when performing migration. */\n\t/* When migration is performed, we create a symbolic link to the original\n\t extension instead of copying it to the new location. If the symbolic link\n\t at the new location is replaced, then that extension is now just dangling\n\t never to be used again. */\n\t/* TPCResourceManager will handle garbage collection. It will compare the\n\t contents of the old location and new location each launch. If a symbolic\n\t link is not present for an extension in the old location, that extension\n\t is deleted. Once all extensions are deleted, a flag is set to stop pruning\n\t so we don't keep scanning the old location forever. */\n\tLogToConsole(\"Start: Pruning extensions for '%{public}@'\",\n\t\t[self _descriptionOfInstallation:installation]);\n\n\tNSArray *oldExtensions = [TPCResourceManager _listOfExtensionsForInstallation:installation];\n\n\tif (oldExtensions == nil) {\n\t\t/* Helper method will describe error. */\n\n\t\treturn;\n\t}\n\n\tif (oldExtensions.count == 0) {\n\t\tLogToConsole(\"Source location for extensions to prune is empty\");\n\n\t\t[self _setAllExtensionSymbolicLinksPruned];\n\n\t\treturn;\n\t}\n\n\tNSURL *newLocation = [TPCPathInfo customExtensionsURL];\n\n\tif (newLocation == nil) {\n\t\tLogToConsoleError(\"Cannot prune extensions because of nil destination location\");\n\n\t\treturn;\n\t}\n\n\tNSUInteger numberPruned = 0;\n\tNSUInteger numberRemaining = 0;\n\n\tfor (NSURL *oldExtension in oldExtensions) {\n\t\tNSString *name = [oldExtension resourceValueForKey:NSURLNameKey];\n\t\t\n\t\tNSNumber *isPackage = [oldExtension resourceValueForKey:NSURLIsPackageKey];\n\n\t\tif ([name hasSuffix:@\".bundle\"] == NO ||\n\t\t\t(isPackage == nil || isPackage.boolValue == NO))\n\t\t{\n#ifdef DEBUG\n\t\t\tLogToConsoleDebug(\"Ignoring non-bundle: '%{public}@' - isPackage: %{BOOL}d\", name, isPackage.boolValue);\n#endif\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSURL *newExtension = [newLocation URLByAppendingPathComponent:name];\n\n\t\t/* Should we check if the symbolic link points to this extension\n\t\t and not some other random file on the operating system?\n\t\t The likelihood of the user having a symbolic link they\n\t\t created is near zero if not zero. This is already over engineered. */\n\t\tBOOL pruned = NO;\n\n\t\tif ([TPCResourceManager _URLIsSymbolicLink:newExtension] == NO) {\n#ifdef DEBUG\n\t\t\tLogToConsoleDebug(\"Pruning URL: '%{public}@'\", oldExtension.standardizedTildePath);\n#endif\n\n\t\t\tNSError *deleteError = nil;\n\n\t\t\tpruned = [RZFileManager() removeItemAtURL:oldExtension error:&deleteError];\n\n\t\t\tif (deleteError) {\n\t\t\t\tLogToConsoleError(\"Failed to prune extension at URL ['%{public}@']: %{public}@\",\n\t\t\t\t\toldExtension.standardizedTildePath, deleteError.localizedDescription);\n\t\t\t}\n\t\t}\n\n\t\tif (pruned) {\n\t\t\tnumberPruned += 1;\n\t\t} else {\n\t\t\tnumberRemaining += 1;\n\t\t}\n\t} // Directory list for loop\n\n\tif (numberRemaining == 0) {\n\t\t[self _setAllExtensionSymbolicLinksPruned];\n\t}\n\n\tLogToConsole(\"End: Pruning extensions completed. \"\n\t\t\t\t \"Number remaining: %{public}lu, Number pruned: %{public}lu\",\n\t\tnumberRemaining, numberPruned);\n}\n\n+ (void)_pruneExtensionSymbolicLinksFromDefaults\n{\n\tBOOL doPrune = [RZUserDefaults() boolForKey:MigrationUserPrefersPruningDefaultsKey];\n\n\tif (doPrune == NO) {\n\t\treturn; // Stop pruning\n\t}\n\n\tBOOL pruningExhausted = [RZUserDefaults() boolForKey:MigrationAllExtensionsPrunedDefaultsKey];\n\n\tif (pruningExhausted) {\n\t\treturn; // Stop pruning\n\t}\n\n\tTPCMigrateSandboxInstallation installation = [RZUserDefaults() unsignedIntegerForKey:MigrationInstallationMigratedDefaultsKey];\n\n\tif ([self _isInstallationSupported:installation] == NO) {\n\t\t[self _setAllExtensionSymbolicLinksPruned];\n\n\t\treturn; // Stop pruning\n\t}\n\n\t[self _pruneExtensionSymbolicLinksForInstallation:installation];\n}\n\n+ (void)_setAllExtensionSymbolicLinksPruned\n{\n\t[RZUserDefaults() _migrateObject:@(YES) forKey:MigrationAllExtensionsPrunedDefaultsKey];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (NSString *)_descriptionOfInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\t/* This is used for logging so is not localized.\n\t Localize is use changes. */\n\tswitch (installation) {\n\t\tcase TPCMigrateSandboxInstallationStandaloneClassic:\n\t\t\treturn @\"Standalone Classic\";\n\t\tcase TPCMigrateSandboxInstallationMacAppStore:\n\t\t\treturn @\"Mac App Store\";\n\t\tdefault:\n\t\t\treturn @\"<Unknown Installation>\";\n\t}\n}\n\n+ (nullable NSString *)_groupContainerIdentifierForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tswitch (installation) {\n\t\tcase TPCMigrateSandboxInstallationStandaloneClassic:\n\t\t\treturn @\"com.codeux.apps.textual\";\n\t\tcase TPCMigrateSandboxInstallationMacAppStore:\n\t\t\treturn @\"8482Q6EPL6.com.codeux.irc.textual\";\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\treturn nil;\n}\n\n+ (nullable NSString *)_defaultsSuiteNameForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tswitch (installation) {\n\t\tcase TPCMigrateSandboxInstallationMacAppStore:\n\t\t\treturn @\"8482Q6EPL6.com.codeux.irc.textual\";\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\treturn nil;\n}\n\n+ (BOOL)_isInstallationSupported:(TPCMigrateSandboxInstallation)installation\n{\n\treturn (installation == TPCMigrateSandboxInstallationStandaloneClassic ||\n\t\t\tinstallation == TPCMigrateSandboxInstallationMacAppStore);\n}\n\n@end\n\n#pragma mark -\n#pragma mark Resource Management\n\n@implementation TPCResourceManager (TPCSandoxMigration)\n\n+ (nullable NSArray<NSURL *> *)_listOfExtensionsForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tNSURL *oldLocation = [TPCPathInfo _groupContainerExtensionsURLForInstallation:installation];\n\n\tif (oldLocation == nil) {\n\t\tLogToConsoleError(\"Cannot list extensions because of nil source location\");\n\n\t\treturn nil;\n\t}\n\n\tif ([RZFileManager() fileExistsAtURL:oldLocation] == NO) {\n\t\treturn @[];\n\t}\n\n\tNSError *listExtensionsError = nil;\n\n\tNSArray *oldExtensions = [RZFileManager() contentsOfDirectoryAtURL:oldLocation\n\t\t\t\t\t\t\t\t\t\t\tincludingPropertiesForKeys:@[NSURLNameKey, NSURLIsPackageKey]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t   options:0\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t error:&listExtensionsError];\n\n\tif (listExtensionsError) {\n\t\tLogToConsoleError(\"Unable to list contents of extensions at URL ['%{public}@']: %{public}@\",\n\t\t\toldLocation.standardizedTildePath, listExtensionsError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\treturn oldExtensions;\n}\n\n+ (BOOL)_ageOfCurrentContainerIsRecent\n{\n\tNSURL *newLocation = [TPCPathInfo groupContainerURL];\n\n\tif (newLocation == NO) {\n\t\treturn NO;\n\t}\n\n\tNSTimeInterval age = [self _intervalSinceCreatedForURL:newLocation];\n\n\t/* macOS will create the group container the first time\n\t we ask for its path. If the group container wasn't created\n\t recently, then we have no reason to perform migration to it.\n\t In theory, this could probably be narrowed down further as\n\t the interval should be sub-second. */\n\treturn (age < 5.0);\n}\n\n+ (NSTimeInterval)_modificationDateForMacAppStorePreferencesIsRecent\n{\n\tNSURL *location = [TPCPathInfo _groupContainerPreferencesURLForInstallation:TPCMigrateSandboxInstallationMacAppStore];\n\n\tif (location == nil) {\n\t\treturn NO;\n\t}\n\n\tNSTimeInterval age = [self _intervalSinceLastModificationForURL:location];\n\n\treturn (age >= 0 && age <= MaximumAgeOfStalePreferences);\n}\n\n+ (NSTimeInterval)_intervalSinceCreatedForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSError *error = nil;\n\n\tNSTimeInterval age = [url intervalSinceCreatedWithError:&error];\n\n\tif (error) {\n\t\t/* This is purposely considered debug information as the user knowing\n\t\t a file not existing is not an error when that is probable outcome. */\n\t\tLogToConsoleDebug(\"Error caught when calculating age of file: %{public}@\",\n\t\t\terror.localizedDescription);\n\t}\n\n\treturn age;\n}\n\n+ (NSTimeInterval)_intervalSinceLastModificationForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSError *error = nil;\n\n\tNSTimeInterval age = [url intervalSinceLastModificationWithError:&error];\n\n\tif (error) {\n\t\t/* This is purposely considered debug information as the user knowing\n\t\t a file not existing is not an error when that is probable outcome. */\n\t\tLogToConsoleDebug(\"Error caught when calculating age of file: %{public}@\",\n\t\t\terror.localizedDescription);\n\t}\n\n\treturn age;\n}\n\n+ (BOOL)_URLIsSymbolicLink:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\t/* Skip check if file exists because no resource value\n\t will be returned if that is the case. */\n\tNSNumber *isSymblink = [url resourceValueForKey:NSURLIsSymbolicLinkKey];\n\n\treturn (isSymblink != nil && isSymblink.boolValue);\n}\n\n@end\n\n#pragma mark -\n#pragma mark Path Information\n\n@implementation TPCPathInfo (TPCSandboxMigration)\n\n+ (nullable NSURL *)_groupContainerURLForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tNSString *identifier = [TPCSandboxMigration _groupContainerIdentifierForInstallation:installation];\n\n\tif (identifier == nil) {\n\t\treturn nil;\n\t}\n\n\t/* The reason we are not using -containerURLForSecurityApplicationGroupIdentifier: in this context is because\n\t during testing, that method was returning ~/Library/Containers/com.codeux.apps.textual instead of the group\n\t container location. I assume it's related to the fact the group identifier is same as the app's identifier.\n\t This is not a make-or-break location in which hard coding will hurt it. */\n\tidentifier = [NSString localizedStringWithFormat:@\"/Library/Group Containers/%@/\", identifier];\n\n\tNSURL *baseURL = [[TPCPathInfo userHomeURL] URLByAppendingPathComponent:identifier];\n\n\treturn baseURL;\n}\n\n+ (nullable NSURL *)_groupContainerPreferencesURLForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tNSString *identifier = [TPCSandboxMigration _groupContainerIdentifierForInstallation:installation];\n\n\tif (identifier == nil) {\n\t\treturn nil;\n\t}\n\n\tidentifier = [NSString localizedStringWithFormat:@\"/Library/Group Containers/%1$@/Library/Preferences/%1$@.plist\", identifier];\n\n\tNSURL *baseURL = [[TPCPathInfo userHomeURL] URLByAppendingPathComponent:identifier];\n\n\treturn baseURL;\n}\n\n+ (nullable NSURL *)_groupContainerExtensionsURLForInstallation:(TPCMigrateSandboxInstallation)installation\n{\n\tNSURL *sourceURL = [self _groupContainerURLForInstallation:installation];\n\n\tif (sourceURL == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [sourceURL URLByAppendingPathComponent:@\"/Library/Application Support/Textual/Extensions/\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/Themes/TPCTheme.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXAppearance.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCResourceManager.h\"\n#import \"TPCThemePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _templateEngineVersionMaximum\t\t\tTPCThemeSettingsNewestTemplateEngineVersion\n#define _templateEngineVersionMinimum\t\t\tTPCThemeSettingsNewestTemplateEngineVersion\n\nNSString * const TPCThemeIntegrityCompromisedNotification\t= @\"TPCThemeIntegrityCompromisedNotification\";\nNSString * const TPCThemeIntegrityRestoredNotification\t\t= @\"TPCThemeIntegrityRestoredNotification\";\nNSString * const TPCThemeAppearanceChangedNotification\t\t= @\"TPCThemeAppearanceChangedNotification\";\nNSString * const TPCThemeVarietyChangedNotification\t\t\t= @\"TPCThemeVarietyChangedNotification\";\nNSString * const TPCThemeWasModifiedNotification\t\t\t= @\"TPCThemeWasModifiedNotification\";\nNSString * const TPCThemeWasDeletedNotification\t\t\t\t= @\"TPCThemeWasDeletedNotification\";\n\ntypedef NS_ENUM(NSUInteger, _TPCThemeChooseVarietyResult) {\n\t_TPCThemeChooseVarietyResultNoChange,\n\t_TPCThemeChooseVarietyResultNoBestChoice,\n\t_TPCThemeChooseVarietyResultChanged\n};\n\ntypedef NS_OPTIONS(NSUInteger, _TPCThemeMonitoringResult) {\n\t_TPCThemeMonitoringResultNoChange\t\t\t\t\t= 0, // Default\n\t_TPCThemeMonitoringResultReloadableFileModified\t\t= 1 << 0, // Any CSS or JavaScript file was changed in the current variety\n\t_TPCThemeMonitoringResultCriticalFileDeleted\t\t= 1 << 1, // The design.css or scripts.js file of any variety was deleted\n\t_TPCThemeMonitoringResultVarietyCreated\t\t\t\t= 1 << 2, // A variety was created\n\t_TPCThemeMonitoringResultVarietyDeleted\t\t\t\t= 1 << 3, // A variety was deleted\n\t_TPCThemeMonitoringResultThemeDeleted\t\t\t\t= 1 << 4  // The theme was deleted\n};\n\n@class TPCThemeVariety;\n\n@interface TPCTheme ()\n@property (nonatomic, copy, readwrite) NSString *name;\n@property (nonatomic, copy, readwrite) NSURL *originalURL;\n@property (nonatomic, copy, readwrite) NSURL *temporaryURL;\n@property (nonatomic, assign, readwrite) TPCThemeStorageLocation storageLocation;\n@property (nonatomic, assign, readwrite) BOOL usable;\n@property (nonatomic, strong) TPCThemeVariety *globalVariety;\n@property (nonatomic, strong, nullable) TPCThemeVariety *variety;\n@property (nonatomic, copy) NSArray<TPCThemeVariety *> *varieties;\n@property (nonatomic, strong, nullable) NSCache *templateCache;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *cssFiles;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *jsFiles;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *temporaryCSSFiles;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *temporaryJSFiles;\n@property (nonatomic, copy, readwrite) NSArray<GRMustacheTemplateRepository *> *templateRepositories;\n@property (nonatomic, strong) GRMustacheTemplateRepository *defaultTemplateRepository;\n@property (nonatomic, strong, readwrite) TPCThemeSettings *settings;\n@property (nonatomic, strong, nullable) XRFileSystemMonitor *fileSystemMonitor;\n@end\n\n@interface TPCThemeVariety : NSObject\n@property (nonatomic, copy) NSURL *url;\n@property (nonatomic, weak) TPCTheme *theme;\n@property (nonatomic, assign) BOOL isGlobalVariety;\n@property (nonatomic, assign) TPCThemeAppearanceType appearance;\n@property (nonatomic, copy, nullable) NSURL *cssFile;\n@property (nonatomic, copy, nullable) NSURL *jsFile;\n@property (nonatomic, copy) NSDictionary<NSString *, id> *settings;\n@property (nonatomic, strong, nullable) GRMustacheTemplateRepository *templateRepository;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithURL:(NSURL *)url NS_DESIGNATED_INITIALIZER;\n\n- (BOOL)_reevaluateFileDuringMonitoringAtURL:(NSURL *)fileURL;\n@end\n\n@interface TPCThemeSettings ()\n@property (nonatomic, assign, readwrite) BOOL supportsMultipleAppearances;\n@property (nonatomic, assign, readwrite) BOOL invertSidebarColors;\n@property (nonatomic, assign, readwrite) BOOL js_postHandleEventNotifications;\n@property (nonatomic, assign, readwrite) BOOL js_postAppearanceChangesNotification;\n@property (nonatomic, assign, readwrite) BOOL js_postPreferencesDidChangesNotifications;\n@property (nonatomic, assign, readwrite) BOOL usesIncompatibleTemplateEngineVersion;\n@property (nonatomic, copy, readwrite, nullable) NSFont *themeChannelViewFont;\n@property (nonatomic, copy, readwrite, nullable) NSString *themeNicknameFormat;\n@property (nonatomic, copy, readwrite, nullable) NSString *themeTimestampFormat;\n@property (nonatomic, copy, readwrite, nullable) NSString *settingsKeyValueStoreName;\n@property (nonatomic, copy, readwrite, nullable) NSColor *channelViewOverlayColor;\n@property (nonatomic, copy, readwrite, nullable) NSColor *underlyingWindowColor;\n@property (nonatomic, copy, readwrite, nullable) NSURL *cssFile;\n@property (nonatomic, copy, readwrite, nullable) NSURL *jsFile;\n@property (nonatomic, assign, readwrite) double indentationOffset;\n@property (nonatomic, assign, readwrite) TPCThemeSettingsNicknameColorStyle nicknameColorStyle;\n@property (nonatomic, assign, readwrite) NSUInteger templateEngineVersion;\n\n- (instancetype)initWithTheme:(TPCTheme *)theme NS_DESIGNATED_INITIALIZER;\n@end\n\n@implementation TPCTheme\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithURL:(NSURL *)url inStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(url.isFileURL);\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tif ((self = [super init])) {\n\t\tNSURL *originalURL = url.URLByStandardizingPath;\n\n\t\tself.name = originalURL.lastPathComponent;\n\n\t\tself.originalURL = originalURL;\n\n\t\tself.storageLocation = storageLocation;\n\n\t\t[self _loadTheme];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self _stopMonitoring];\n}\n\n- (void)_loadTheme\n{\n\t[self _assignTemporaryURL];\n\n\t[self _loadGlobalVariety];\n\n\t[self _loadVarieties];\n\n\tif (self.varieties == nil) {\n\t\tself.varieties = @[];\n\t}\n\n\t/* During init there should be not variety already set. */\n\tself.usable =\n\t([self _chooseBestVariety] == _TPCThemeChooseVarietyResultChanged);\n\n\t[self _startMonitoring];\n}\n\n- (void)_loadGlobalVariety\n{\n\tNSURL *url = self.originalURL;\n\n\tTPCThemeVariety *variety = [[TPCThemeVariety alloc] initWithURL:url];\n\n\tvariety.isGlobalVariety = YES;\n\n\tself.globalVariety = variety;\n}\n\n- (void)_loadVarieties\n{\n\tNSURL *varietiesURL = [self _varietiesURL];\n\n\tif ([RZFileManager() fileExistsAtURL:varietiesURL] == NO) {\n\t\treturn;\n\t}\n\n\tNSError *preFileListError;\n\n\tNSArray *preFileList =\n\t[RZFileManager() contentsOfDirectoryAtURL:varietiesURL\n\t\t\t\t   includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey]\n\t\t\t\t\t\t\t\t\t  options:NSDirectoryEnumerationSkipsHiddenFiles\n\t\t\t\t\t\t\t\t\t\terror:&preFileListError];\n\n\tif (preFileListError) {\n\t\tLogToConsoleError(\"Failed to list contents of Varieties folder: %{public}@\",\n\t\t\tpreFileListError.localizedDescription);\n\t}\n\n\tNSMutableArray<TPCThemeVariety *> *varieties = [NSMutableArray array];\n\n\tfor (NSURL *fileURL in preFileList) {\n\t\tNSNumber *isDirectory = [fileURL resourceValueForKey:NSURLIsDirectoryKey];\n\n\t\tif ([isDirectory boolValue] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tTPCThemeVariety *variety = [[TPCThemeVariety alloc] initWithURL:fileURL];\n\n\t\t[varieties addObject:variety];\n\t}\n\n\tself.varieties = varieties;\n}\n\n- (NSURL *)_varietiesURL\n{\n\tNSURL *url = self.originalURL;\n\n\treturn [url URLByAppendingPathComponent:@\"Varieties/\"];\n}\n\n- (void)_populateSettings\n{\n\tself.settings = [[TPCThemeSettings alloc] initWithTheme:self];\n}\n\n- (void)_assignDefaultTemplateRepository\n{\n\tNSURL *repositoryURL = [self _applicationTemplateRepositoryURL];\n\n\tGRMustacheTemplateRepository *repository = [GRMustacheTemplateRepository templateRepositoryWithBaseURL:repositoryURL];\n\n\tNSAssert((repository != nil),\n\t\t@\"Default template repository not found\");\n\n\tself.defaultTemplateRepository = repository;\n}\n\n- (void)_assignTemporaryURL\n{\n//\tNSURL *sourceURL = [TPCPathInfo applicationTemporaryProcessSpecificURL];\n\tNSURL *sourceURL = [TPCPathInfo applicationCachesURL];\n\n\tNSURL *baseURL = [sourceURL URLByAppendingPathComponent:@\"/Cached-Style-Resources/\"];\n\n\tself.temporaryURL = baseURL.URLByStandardizingPath;\n}\n\n#pragma mark -\n#pragma mark Monitoring\n\n- (BOOL)_isDirectoryURLSelf:(NSURL *)url\n{\n\tNSURL *selfURL = self.originalURL;\n\n\treturn [self _isDirectoryURL:url equalTo:selfURL];\n}\n\n- (BOOL)_isDirectoryURL:(NSURL *)url1 equalTo:(NSURL *)url2\n{\n\tNSParameterAssert(url1 != nil);\n\tNSParameterAssert(url2 != nil);\n\n\t/* The file representation is compared instead of the\n\t resource identifier because the resource identifier\n\t returns nil when the URL no longer exists. */\n\treturn [url1 isEqualByFileRepresentation:url2];\n}\n\n- (nullable TPCThemeVariety *)_varietyAtURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tTPCThemeVariety *globalVariety = self.globalVariety;\n\n\tNSURL *globalVarietyURL = globalVariety.url;\n\n\tif ([self _isDirectoryURL:url equalTo:globalVarietyURL]) {\n\t\treturn globalVariety;\n\t}\n\n\tNSArray *varieties = self.varieties;\n\n\tTPCThemeVariety *variety =\n\t[varieties objectPassingTest:^BOOL(TPCThemeVariety *variety, NSUInteger index, BOOL *stop) {\n\t\tNSURL *varietyURL = variety.url;\n\n\t\treturn [self _isDirectoryURL:url equalTo:varietyURL];\n\t}];\n\n\treturn variety;\n}\n\n- (void)_stopMonitoring\n{\n\tXRFileSystemMonitor *monitor = self.fileSystemMonitor;\n\n\tif (monitor == nil) {\n\t\treturn;\n\t}\n\n\t[monitor stopMonitoring];\n\n\tself.fileSystemMonitor = nil;\n}\n\n- (void)_startMonitoring\n{\n\tNSURL *url = self.originalURL;\n\n\t__weak TPCTheme *weakSelf = self;\n\n\t  XRFileSystemMonitor *monitor =\n\t[[XRFileSystemMonitor alloc] initWithFileURL:url callbackBlock:^(NSArray<XRFileSystemEvent *> *events) {\n\t\t[weakSelf _reactToMonitoringEvents:events];\n\t}];\n\n\t[monitor startMonitoringWithLatency:5.0];\n\n\tself.fileSystemMonitor = monitor;\n}\n\n- (void)_concludeMonitoringEventWithResult:(_TPCThemeMonitoringResult)result\n{\n\t/* Theme was deleted */\n\tif ((result & _TPCThemeMonitoringResultThemeDeleted) == _TPCThemeMonitoringResultThemeDeleted) {\n\t\t[self _reactToDeletion];\n\n\t\treturn;\n\t}\n\n\t/* Theme was modified in such a way that it must be validated\n\t and possibly a new best choice is chosen. */\n\tif ((result & _TPCThemeMonitoringResultCriticalFileDeleted) == _TPCThemeMonitoringResultCriticalFileDeleted ||\n\t\t(result & _TPCThemeMonitoringResultVarietyCreated) == _TPCThemeMonitoringResultVarietyCreated ||\n\t\t(result & _TPCThemeMonitoringResultVarietyDeleted) == _TPCThemeMonitoringResultVarietyDeleted)\n\t{\n\t\t[self _verifyIntegrity];\n\t}\n\n\t/* CSS or JavaScript file in the current variety was modified. */\n\telse if ((result & _TPCThemeMonitoringResultReloadableFileModified) == _TPCThemeMonitoringResultReloadableFileModified)\n\t{\n\t\t[self _notifyRecentlyModified];\n\t}\n}\n\n- (void)_reactToMonitoringEvents:(NSArray<XRFileSystemEvent *> *)events\n{\n\tNSParameterAssert(events != nil);\n\n\t_TPCThemeMonitoringResult result = _TPCThemeMonitoringResultNoChange;\n\n\tfor (XRFileSystemEvent *event in events) {\n\t\tresult |= [self _reactToMonitoringEventAtURL:event.url withFlags:event.flags];\n\t}\n\n\t[self _concludeMonitoringEventWithResult:result];\n}\n\n- (_TPCThemeMonitoringResult)_reactToMonitoringEventAtURL:(NSURL *)url withFlags:(FSEventStreamEventFlags)flags\n{\n\tNSParameterAssert(url != nil);\n\n\t/* Returns YES if something changed that requires an integrity check. NO otherwise. */\n\tif (flags & kFSEventStreamEventFlagItemIsFile) {\n\t\treturn [self _reactToMonitoringEventForFileAtURL:url withFlags:flags];\n\t} else if (flags & kFSEventStreamEventFlagItemIsDir) {\n\t\treturn [self _reactToMonitoringEventForDirectoryAtURL:url withFlags:flags];\n\t}\n\n\treturn _TPCThemeMonitoringResultNoChange; // No change\n}\n\n- (_TPCThemeMonitoringResult)_reactToMonitoringEventForFileAtURL:(NSURL *)url withFlags:(FSEventStreamEventFlags)flags\n{\n\tNSParameterAssert(url != nil);\n\n\tNSURL *directoryURL = url.URLByDeletingLastPathComponent;\n\n\tTPCThemeVariety *variety = [self _varietyAtURL:directoryURL];\n\n\t/* The monitor is used for two parts:\n\t 1. To continuously verify the integrity of the theme\n\t  and varieties so that the next time that it's reloaded,\n\t  it will be in a usable state.\n\t 2. To automatically reload the theme when CSS and JavaScript\n\t  files changed if that's what the user has configured.\n\t  If #1 is triggered, then we do not do #2. */\n\tif (variety == nil) {\n\t\treturn _TPCThemeMonitoringResultNoChange;\n\t}\n\n\t_TPCThemeMonitoringResult result = _TPCThemeMonitoringResultNoChange;\n\n\tBOOL varietyChanged = [self _verifyIntegrityOfFileAtURL:url duringMonitoringOfVariety:variety];\n\n\tif (varietyChanged) {\n\t\tresult |= _TPCThemeMonitoringResultCriticalFileDeleted;\n\t}\n\n\t/* Limit #2 to scope of active variety. */\n\tif (variety != self.variety &&\n\t\tvariety != self.globalVariety)\n\t{\n\t\treturn result;\n\t}\n\n\t/* Do #2 */\n\tNSString *fileExtension = url.pathExtension;\n\n\tif ([fileExtension isEqual:@\"css\"] ||\n\t\t[fileExtension isEqual:@\"js\"])\n\t{\n\t\tresult |= _TPCThemeMonitoringResultReloadableFileModified;\n\t}\n\n\treturn result; // No change\n}\n\n- (_TPCThemeMonitoringResult)_reactToMonitoringEventForDirectoryAtURL:(NSURL *)url withFlags:(FSEventStreamEventFlags)flags\n{\n\tNSParameterAssert(url != nil);\n\n\t/* React to changes to the theme itself. */\n\tif ([self _isDirectoryURLSelf:url]) {\n\t\tif ([RZFileManager() directoryExistsAtURL:url] == NO) {\n\t\t\treturn _TPCThemeMonitoringResultThemeDeleted;\n\t\t}\n\n\t\treturn _TPCThemeMonitoringResultNoChange;\n\t}\n\n\t/* React to changes to a specific variety folder.\n\t We determine which URLs to target by comparing the\n\t parent of this URL to the Varieties directory URL. */\n\tNSURL *parentURL = url.URLByDeletingLastPathComponent;\n\n\tNSURL *varietiesURL = [self _varietiesURL];\n\n\tif ([self _isDirectoryURL:parentURL equalTo:varietiesURL]) {\n\t\treturn [self _reactToMonitoringVarietyDirectoryEventAtURL:url withFlags:flags];\n\t}\n\n\treturn _TPCThemeMonitoringResultNoChange;\n}\n\n- (_TPCThemeMonitoringResult)_reactToMonitoringVarietyDirectoryEventAtURL:(NSURL *)url withFlags:(FSEventStreamEventFlags)flags\n{\n\tNSParameterAssert(url != nil);\n\n\tBOOL varietyDeleted = ([RZFileManager() directoryExistsAtURL:url] == NO);\n\n\tTPCThemeVariety *variety = [self _varietyAtURL:url];\n\n\tNSMutableArray *varieties = self.varieties.mutableCopy;\n\n\tif (variety) {\n\t\t[varieties removeObject:variety];\n\t} else {\n\t\tif (varietyDeleted) {\n\t\t\treturn _TPCThemeMonitoringResultNoChange; // No change\n\t\t}\n\t}\n\n\tif (varietyDeleted == NO) {\n\t\tTPCThemeVariety *newVariety = [[TPCThemeVariety alloc] initWithURL:url];\n\n\t\t[varieties addObject:newVariety];\n\t}\n\n\tself.varieties = varieties;\n\n\treturn ((varietyDeleted) ?\n\t\t\t_TPCThemeMonitoringResultVarietyDeleted :\n\t\t\t_TPCThemeMonitoringResultVarietyCreated);\n}\n\n- (void)_reactToDeletion\n{\n\t[self _stopMonitoring];\n\n\t[self _changeVariety:nil];\n\n\tself.usable = NO;\n\n\t[self _notifyDeleted];\n}\n\n- (void)_notifyRecentlyModified\n{\n\t[RZNotificationCenter() postNotificationName:TPCThemeWasModifiedNotification object:self];\n}\n\n- (void)_notifyDeleted\n{\n\t[RZNotificationCenter() postNotificationName:TPCThemeWasDeletedNotification object:self];\n}\n\n#pragma mark -\n#pragma mark Integrity\n\n- (BOOL)_verifyIntegrityOfFileAtURL:(NSURL *)url duringMonitoringOfVariety:(TPCThemeVariety *)variety\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(variety != nil);\n\n\t/* Returns YES if a change is made to property. NO otherwise. */\n\n\t/* The variety will first determine which type of file was\n\t changed. CSS or JavaScript.\n\t • If the property for this file is set and the file no longer\n\t   exists, then the property is set to nil.\n\t • If the property for this file is nil and the file exists,\n\t   then the property is set to the URL of the file.\n\t After action is performed by the variety, we can decide\n\t wether to do anything depending on whether a change\n\t actually took place. */\n\tBOOL fileChanged =\n\t[variety _reevaluateFileDuringMonitoringAtURL:url];\n\n\tif (fileChanged == NO) {\n\t\treturn NO; // No change\n\t}\n\n\treturn YES; // Change made\n}\n\n- (BOOL)_verifyIntegrity\n{\n\t/* The variety changed in some way as described above.\n\t The theme will now try to choose the best variety again.\n\t If there is not a suitable variety to change to, then at\n\t this point integrity of the theme is considered compromised.\n\t It is possible to recover from the compromised state by\n\t changing this variety or the global variety in such a way\n\t that either can be used. */\n\t_TPCThemeChooseVarietyResult varietyChanged = [self _chooseBestVariety];\n\n\tif (self.usable) {\n\t\tif (varietyChanged == _TPCThemeChooseVarietyResultNoChange) {\n\t\t\treturn NO; // No change\n\t\t}\n\n\t\tif (varietyChanged == _TPCThemeChooseVarietyResultNoBestChoice) {\n\t\t\tself.usable = NO;\n\n\t\t\t[self _chooseNoVariety]; // Reset selection\n\n\t\t\t[RZNotificationCenter() postNotificationName:TPCThemeIntegrityCompromisedNotification object:self];\n\t\t}\n\t}\n\telse // usable\n\t{\n\t\tif (varietyChanged == _TPCThemeChooseVarietyResultNoBestChoice) {\n\t\t\treturn NO; // No change\n\t\t}\n\n\t\tself.usable = YES;\n\n\t\t[RZNotificationCenter() postNotificationName:TPCThemeIntegrityRestoredNotification object:self];\n\t} // usable\n\n\treturn YES; // Change made\n}\n\n#pragma mark -\n#pragma mark Changing Variety\n\n- (void)_combineFiles\n{\n\tTPCThemeVariety *variety = self.variety;\n\n\tif (variety == nil) {\n\t\tself.cssFiles = @[];\n\t\tself.jsFiles = @[];\n\n\t\tself.temporaryCSSFiles = @[];\n\t\tself.temporaryJSFiles = @[];\n\n\t\tself.templateRepositories = @[];\n\n\t\treturn;\n\t}\n\n\tTPCThemeVariety *globalVariety = self.globalVariety;\n\n\tNSMutableArray<NSURL *> *cssFiles = [NSMutableArray array];\n\tNSMutableArray<NSURL *> *jsFiles = [NSMutableArray array];\n\tNSMutableArray<NSURL *> *temporaryCSSFiles = [NSMutableArray array];\n\tNSMutableArray<NSURL *> *temporaryJSFiles = [NSMutableArray array];\n\n\tNSMutableArray<GRMustacheTemplateRepository *> *templates = [NSMutableArray array];\n\n\tNSString *originalRemapPath = self.originalURL.path;\n\n\tif ([originalRemapPath hasSuffix:@\"/\"]) {\n\t\t originalRemapPath = [originalRemapPath substringAtIndex:0 toLength:(-1)];\n\t}\n\n\tNSString *temporaryRemapPath = self.temporaryURL.path;\n\n\tif ([temporaryRemapPath hasSuffix:@\"/\"]) {\n\t\t temporaryRemapPath = [temporaryRemapPath substringAtIndex:0 toLength:(-1)];\n\t}\n\n\tNSURL *(^_remapTemporaryFile)(NSURL *) = ^NSURL *(NSURL *url)\n\t{\n\t\tNSString *path = url.path;\n\n\t\tif ([path hasPrefix:originalRemapPath] == NO) {\n\t\t\treturn url;\n\t\t}\n\n\t\tpath = [path substringFromIndex:originalRemapPath.length];\n\n\t\tpath = [temporaryRemapPath stringByAppendingString:path];\n\n\t\treturn [NSURL fileURLWithPath:path].URLByStandardizingPath;\n\t};\n\n\tvoid (^_addCSSFile)(TPCThemeVariety *) = ^(TPCThemeVariety *variety) {\n\t\tNSURL *cssFile = variety.cssFile;\n\n\t\tif (cssFile == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[cssFiles addObject:cssFile];\n\n\t\t[temporaryCSSFiles addObject:_remapTemporaryFile(cssFile)];\n\t};\n\n\tvoid (^_addJSFile)(TPCThemeVariety *) = ^(TPCThemeVariety *variety) {\n\t\tNSURL *jsFile = variety.jsFile;\n\n\t\tif (jsFile == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[jsFiles addObject:jsFile];\n\n\t\t[temporaryJSFiles addObject:_remapTemporaryFile(jsFile)];\n\t};\n\n\tvoid (^_addTemplates)(TPCThemeVariety *) = ^(TPCThemeVariety *variety) {\n\t\tGRMustacheTemplateRepository *repository = variety.templateRepository;\n\n\t\tif (repository == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[templates addObject:repository];\n\t};\n\n\t_addCSSFile(globalVariety);\n\t_addJSFile(globalVariety);\n\n\tif (variety.isGlobalVariety == NO) {\n\t\t_addCSSFile(variety);\n\t\t_addJSFile(variety);\n\n\t\t_addTemplates(variety);\n\t}\n\n\t_addTemplates(globalVariety);\n\n\tself.cssFiles = cssFiles;\n\tself.jsFiles = jsFiles;\n\n\tself.temporaryCSSFiles = temporaryCSSFiles;\n\tself.temporaryJSFiles = temporaryJSFiles;\n\n\tself.templateRepositories = templates;\n}\n\n- (_TPCThemeChooseVarietyResult)_chooseBestVariety\n{\n\tTPCThemeVariety *bestVariety = [self _bestVariety];\n\n\tif (bestVariety == nil) {\n\t\treturn _TPCThemeChooseVarietyResultNoBestChoice;\n\t}\n\n\tTPCThemeVariety *currentVariety = self.variety;\n\n\tif (currentVariety == bestVariety) {\n\t\treturn _TPCThemeChooseVarietyResultNoChange;\n\t}\n\n\t[self _changeVariety:bestVariety];\n\n\treturn _TPCThemeChooseVarietyResultChanged;\n}\n\n- (void)_changeVariety:(nullable TPCThemeVariety *)variety\n{\n\tTPCThemeVariety *previousVariety = self.variety;\n\n\tself.templateCache = nil;\n\n\tself.variety = variety;\n\n\t[self _combineFiles];\n\n\t[self _populateSettings];\n\n\t/* Assign the default repository after populating settings\n\t as we need the template engine version for construction. */\n\t[self _assignDefaultTemplateRepository];\n\n\t/* Do not fire notification if there is not a previous\n\t variety (during init) or we are in a compromised state. */\n\tif (previousVariety != nil && variety != nil && self.usable) {\n\t\tif (previousVariety.appearance == variety.appearance) {\n\t\t\t[RZNotificationCenter() postNotificationName:TPCThemeVarietyChangedNotification object:self];\n\t\t} else {\n\t\t\t[RZNotificationCenter() postNotificationName:TPCThemeAppearanceChangedNotification object:self];\n\t\t}\n\t}\n}\n\n- (void)_chooseNoVariety\n{\n\t[self _changeVariety:nil];\n}\n\n- (nullable TPCThemeVariety *)_bestVariety\n{\n\tTXAppearance *appAppearance = [TXSharedApplication sharedAppearance];\n\n\tBOOL isDarkAppearance = appAppearance.properties.isDarkAppearance;\n\n\tTPCThemeVariety *globalVariety = self.globalVariety;\n\n\tBOOL globalHasCSS = (globalVariety.cssFile != nil);\n\tBOOL globalHasJS = (globalVariety.jsFile != nil);\n\n\tTPCThemeVariety *bestVariety = nil;\n\n\tNSArray *varieties = self.varieties;\n\n\t/* A variety does not need to contain a CSS or JavaScript file\n\t to be the best. As long those exist within the global variety,\n\t then any variety that meets the appearance criteria can be\n\t the best. This allows for flexibility such as specific variety\n\t containing different templates and/or settings while using a\n\t unified CSS and/or JavaScript file. */\n\tfor (TPCThemeVariety *variety in varieties) {\n\t\tBOOL isBestVariety = NO;\n\n\t\t/* Perform first pass based on appearance criteria. */\n\t\tif ((variety.appearance == TPCThemeAppearanceTypeLight && isDarkAppearance == NO) ||\n\t\t\t(variety.appearance == TPCThemeAppearanceTypeDark && isDarkAppearance))\n\t\t{\n\t\t\tisBestVariety = YES;\n\t\t}\n\n\t\t/* We always set a best appearance even when appearance doesn't match\n\t\t so that we can at least have one to work off of. Of course if we find\n\t\t a better variety while enumerating, such as one that does match the\n\t\t appearance, then the default is discarded. */\n\t\telse if (bestVariety == nil)\n\t\t{\n\t\t\tisBestVariety = YES;\n\t\t}\n\n\t\tif (isBestVariety) {\n\t\t\t/* Ensure someone has a CSS and JavaScript file. */\n\t\t\tif ((globalHasCSS == NO && variety.cssFile == nil) ||\n\t\t\t\t(globalHasJS == NO && variety.jsFile == nil))\n\t\t\t{\n\t\t\t\tisBestVariety = NO;\n\t\t\t}\n\t\t}\n\n\t\t/* Set as best variety if all conditions are met. */\n\t\tif (isBestVariety) {\n\t\t\tbestVariety = variety;\n\t\t}\n\t}\n\n\t/* If we do not have a best variety, then use the global\n\t variety assuming it can be used. */\n\tif (bestVariety == nil && globalHasCSS && globalHasCSS) {\n\t\tbestVariety = globalVariety;\n\t}\n\n\treturn bestVariety;\n}\n\n- (void)updateAppearance\n{\n\t[self _chooseBestVariety];\n}\n\n#pragma mark -\n#pragma mark Getters\n\n- (TPCThemeAppearanceType)appearance\n{\n\treturn self.variety.appearance;\n}\n\n- (NSArray<NSString *> *)cssFilePaths\n{\n\treturn [self _pathsArrayForURLs:self.cssFiles];\n}\n\n- (NSArray<NSString *> *)jsFilePaths\n{\n\treturn [self _pathsArrayForURLs:self.jsFiles];\n}\n\n- (NSArray<NSString *> *)temporaryCSSFilePaths\n{\n\treturn [self _pathsArrayForURLs:self.temporaryCSSFiles];\n}\n\n- (NSArray<NSString *> *)temporaryJSFilePaths\n{\n\treturn [self _pathsArrayForURLs:self.temporaryJSFiles];\n}\n\n- (NSArray<NSString *> *)_pathsArrayForURLs:(NSArray<NSURL *> *)urls\n{\n\tNSParameterAssert(urls != nil);\n\n\treturn [NSArray pathsArrayForFileURLs:urls];\n}\n\n#pragma mark -\n#pragma mark Templates\n\n+ (NSDictionary<NSString *, NSString *> *)_templateLineTypes\n{\t\n\treturn [TPCResourceManager dictionaryFromResources:@\"TemplateLineTypes\"];\n}\n\n- (NSURL *)_applicationTemplateRepositoryURL\n{\n\tTPCThemeSettings *settings = self.settings;\n\n\tNSString *filename = [NSString stringWithFormat:@\"/Style Default Templates/Version %lu/\", settings.templateEngineVersion];\n\n\tNSURL *templatesPath = [[TPCPathInfo applicationResourcesURL] URLByAppendingPathComponent:filename];\n\n\treturn templatesPath;\n}\n\n- (NSString *)applicationTemplateRepositoryPath\n{\n\tNSURL *repositoryURL = [self _applicationTemplateRepositoryURL];\n\n\treturn repositoryURL.path;\n}\n\n- (nullable GRMustacheTemplate *)templateWithLineType:(TVCLogLineType)type\n{\n\tNSString *typeString = [TVCLogLine stringForLineType:type];\n\n\tNSString *templateName = [@\"Line Types/\" stringByAppendingString:typeString];\n\n\tGRMustacheTemplate *template = [self _templateWithName:templateName logErrors:NO];\n\n\tif (template == nil) {\n\t\ttemplateName = [self.class _templateLineTypes][typeString];\n\n\t\tif (templateName == nil) {\n\t\t\treturn nil;\n\t\t}\n\n\t\ttemplate = [self _templateWithName:templateName logErrors:YES];\n\t}\n\n\treturn template;\n}\n\n- (nullable GRMustacheTemplate *)templateWithName:(NSString *)templateName\n{\n\treturn [self _templateWithName:templateName logErrors:YES];\n}\n\n- (nullable GRMustacheTemplate *)_templateWithName:(NSString *)templateName logErrors:(BOOL)logErrors\n{\n\tNSParameterAssert(templateName != nil);\n\n\tNSCache *cache = self.templateCache;\n\n\tif (cache == nil) {\n\t\tcache = [NSCache new];\n\n\t\tself.templateCache = cache;\n\t} else {\n\t\tGRMustacheTemplate *template = [cache objectForKey:templateName];\n\n\t\tif (template) {\n\t\t\treturn template;\n\t\t}\n\t}\n\n\t GRMustacheTemplate * _Nullable (^_loadTemplate)(GRMustacheTemplateRepository *) =\n\t^GRMustacheTemplate * _Nullable (GRMustacheTemplateRepository *repository)\n\t{\n\t\tNSError *loadError = nil;\n\n\t\tGRMustacheTemplate *template = [repository templateNamed:templateName error:&loadError];\n\n\t\tif (loadError && (loadError.code == GRMustacheErrorCodeTemplateNotFound || loadError.code == 260)) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif (loadError && logErrors) {\n\t\t\tLogToConsoleError(\"Failed to load template '%{public}@' with error: '%{public}@'\",\n\t\t\t\ttemplateName, loadError.localizedDescription);\n\t\t\tLogStackTrace();\n\t\t}\n\n\t\treturn template;\n\t};\n\n\tGRMustacheTemplate *template = nil;\n\n\tNSArray *repositories = self.templateRepositories;\n\n\tfor (GRMustacheTemplateRepository *repository in repositories) {\n\t\ttemplate = _loadTemplate(repository);\n\n\t\tif (template != nil) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (template == nil) {\n\t\tGRMustacheTemplateRepository *repository = self.defaultTemplateRepository;\n\n\t\ttemplate = _loadTemplate(repository);\n\t}\n\n\tif (template != nil) {\n\t\t[cache setObject:template forKey:templateName];\n\t}\n\n\treturn template;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Theme Variety\n\n@implementation TPCThemeVariety\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tif ((self = [super init])) {\n\t\tself.url = url.URLByStandardizingPath;\n\n\t\t[self _loadVariety];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)_loadVariety\n{\n\tNSURL *url = self.url;\n\n\t/* CSS file */\n\tNSURL *cssFile = [url URLByAppendingPathComponent:@\"design.css\"];\n\n\tif ([RZFileManager() fileExistsAtURL:cssFile]) {\n\t\tself.cssFile = cssFile;\n\t}\n\n\t/* JavaScript file */\n\tNSURL *jsFile = [url URLByAppendingPathComponent:@\"scripts.js\"];\n\n\tif ([RZFileManager() fileExistsAtURL:jsFile]) {\n\t\tself.jsFile = jsFile;\n\t}\n\n\tNSURL *templatesURL = [self.class _compatTemplatesAtURL:url];\n\n\tself.templateRepository = [GRMustacheTemplateRepository templateRepositoryWithBaseURL:templatesURL];\n\n\t/* Load settings dictionary */\n\tNSURL *settingsURL = [self.class _compatSettingsAtURL:url];\n\n\tNSDictionary<NSString *, id> *settings = [NSDictionary dictionaryWithContentsOfURL:settingsURL];\n\n\tif (settings == nil) {\n\t\tsettings = @{};\n\t}\n\n\tself.settings = settings;\n\n\t/* Appearance */\n\tTPCThemeAppearanceType appearance = TPCThemeAppearanceTypeDefault;\n\n\tNSString *appearanceObject = [settings stringForKey:@\"Appearance\"];\n\n\tif ([appearanceObject isEqual:@\"dark\"]) {\n\t\tappearance = TPCThemeAppearanceTypeDark;\n\t} else if ([appearanceObject isEqual:@\"light\"]) {\n\t\tappearance = TPCThemeAppearanceTypeLight;\n\t}\n\n\tself.appearance = appearance;\n}\n\nstatic inline BOOL _reevaluateFileDuringSetOrUnset(NSURL *fileURL, NSURL * __strong *setter)\n{\n\tBOOL fileExists = [RZFileManager() fileExistsAtURL:fileURL];\n\n\tif (fileExists) {\n\t\tif (*setter == nil) {\n\t\t\t*setter = [fileURL copy];\n\n\t\t\treturn YES;\n\t\t}\n\t} else {\n\t\tif (*setter) {\n\t\t\t*setter = nil;\n\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n- (BOOL)_reevaluateFileDuringMonitoringAtURL:(NSURL *)fileURL\n{\n\tNSParameterAssert(fileURL != nil);\n\tNSParameterAssert(fileURL.isFileURL);\n\n\t/* Returns YES if a change is made to property. NO otherwise. */\n\n\t/* This method is only called for the root of the variety which\n\t means we only need to perform file name comparison. */\n\tNSString *filename = fileURL.lastPathComponent;\n\n\tif ([filename isEqual:@\"design.css\"]) {\n\t\treturn _reevaluateFileDuringSetOrUnset(fileURL, &self->_cssFile);\n\t} else if ([filename isEqual:@\"scripts.js\"]) {\n\t\treturn _reevaluateFileDuringSetOrUnset(fileURL, &self->_jsFile);\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Backwards Compatibility\n\n+ (NSURL *)_compatSettingsAtURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSURL *oldURL = [url URLByAppendingPathComponent:@\"Data/Settings/styleSettings.plist\"];\n\n\tif ([RZFileManager() fileExistsAtURL:oldURL]) {\n\t\treturn oldURL;\n\t}\n\n\treturn [url URLByAppendingPathComponent:@\"settings.plist\"];\n}\n\n+ (NSURL *)_compatTemplatesAtURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSURL *oldURL = [url URLByAppendingPathComponent:@\"Data/Templates/\"];\n\n\tif ([RZFileManager() fileExistsAtURL:oldURL]) {\n\t\treturn oldURL;\n\t}\n\n\treturn [url URLByAppendingPathComponent:@\"Templates/\"];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Theme Settings\n\n@implementation TPCThemeSettings\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithTheme:(TPCTheme *)theme\n{\n\tNSParameterAssert(theme != nil);\n\n\tif ((self = [super init])) {\n\t\t[self _loadSettingsForTheme:theme];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)_loadSettingsForTheme:(TPCTheme *)theme\n{\n\t/* Combine both setting dictionaries */\n\tTPCThemeVariety *globalVariety = theme.globalVariety;\n\n\tNSDictionary *settings = globalVariety.settings;\n\n\tTPCThemeVariety *variety = theme.variety;\n\n\tif (variety && variety.isGlobalVariety == NO) {\n\t\tNSDictionary *settingsNew = variety.settings;\n\n\t\tif (settings == nil) {\n\t\t\tsettings = settingsNew;\n\t\t} else {\n\t\t\tsettings = [settings dictionaryByAddingEntries:variety.settings];\n\t\t}\n\t}\n\n\t/* Populate settings */\n\tself.themeChannelViewFont = [self.class _fontForKey:@\"Override Channel Font\" fromDictionary:settings];\n\n\tself.themeNicknameFormat = [self.class _stringForKey:@\"Nickname Format\" fromDictionary:settings];\n\tself.themeTimestampFormat = [self.class _stringForKey:@\"Timestamp Format\" fromDictionary:settings];\n\n\tself.invertSidebarColors = [settings boolForKey:@\"Force Invert Sidebars\"];\n\n\tself.channelViewOverlayColor = [self.class _colorForKey:@\"Channel View Overlay Color\" fromDictionary:settings];\n\tself.underlyingWindowColor = [self.class _colorForKey:@\"Underlying Window Color\" fromDictionary:settings];\n\n\tself.settingsKeyValueStoreName = [self.class _stringForKey:@\"Key-value Store Name\" fromDictionary:settings];\n\n\tself.js_postHandleEventNotifications = [settings boolForKey:@\"Post Textual.handleEvent() Notifications\"];\n\tself.js_postAppearanceChangesNotification = [settings boolForKey:@\"Post Textual.appearanceDidChange() Notifications\"];\n\tself.js_postPreferencesDidChangesNotifications = [settings boolForKey:@\"Post Textual.preferencesDidChange() Notifications\"];\n\n\t/* Disable indentation? */\n\tid indentationOffset = settings[@\"Indentation Offset\"];\n\n\tif (indentationOffset == nil) {\n\t\tself.indentationOffset = TPCThemeSettingsDisabledIndentationOffset;\n\t} else {\n\t\tdouble indentationOffsetDouble = [indentationOffset doubleValue];\n\n\t\tif (indentationOffsetDouble < 0.0) {\n\t\t\tself.indentationOffset = TPCThemeSettingsDisabledIndentationOffset;\n\t\t} else {\n\t\t\tself.indentationOffset = indentationOffsetDouble;\n\t\t}\n\t}\n\n\t/* Nickname color style */\n\tTPCThemeAppearanceType appearance = variety.appearance;\n\n\tid nicknameColorStyle = settings[@\"Nickname Color Style\"];\n\n\tif ([nicknameColorStyle isEqual:@\"HSL-light\"]) {\n\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleLight;\n\t} else if ([nicknameColorStyle isEqual:@\"HSL-dark\"]) {\n\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleDark;\n\t} else if (appearance == TPCThemeAppearanceTypeLight) {\n\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleLight;\n\t} else if (appearance == TPCThemeAppearanceTypeDark) {\n\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleDark;\n\t} else {\n\t\tif (self.underlyingWindowColorIsDark == NO) {\n\t\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleLight;\n\t\t} else {\n\t\t\tself.nicknameColorStyle = TPCThemeSettingsNicknameColorStyleDark;\n\t\t}\n\t}\n\n\t/* Get style template version */\n\tBOOL usesIncompatibleTemplateEngineVersion = YES;\n\n\tNSUInteger templateEngineVersion = 0;\n\n\tNSDictionary<NSString *, NSNumber *> *templateVersions = [settings dictionaryForKey:@\"Template Engine Versions\"];\n\n\t{\n\t\tNSString *applicationVersion = [TPCApplicationInfo applicationVersionShort];\n\n\t\tNSUInteger targetVersion = [templateVersions unsignedIntegerForKey:applicationVersion];\n\n\t\tif (NSNumberInRange(targetVersion, _templateEngineVersionMinimum, _templateEngineVersionMaximum)) {\n\t\t\ttemplateEngineVersion = targetVersion;\n\n\t\t\tusesIncompatibleTemplateEngineVersion = NO;\n\t\t}\n\t}\n\n\tif (templateEngineVersion == 0) {\n\t\tNSUInteger defaultVersion = [templateVersions unsignedIntegerForKey:@\"default\"];\n\n\t\tif (NSNumberInRange(defaultVersion, _templateEngineVersionMinimum, _templateEngineVersionMaximum)) {\n\t\t\ttemplateEngineVersion = defaultVersion;\n\n\t\t\tusesIncompatibleTemplateEngineVersion = NO;\n\t\t}\n\t}\n\n\tif (templateEngineVersion == 0) {\n\t\ttemplateEngineVersion = _templateEngineVersionMaximum;\n\t}\n\n\tself.usesIncompatibleTemplateEngineVersion = usesIncompatibleTemplateEngineVersion;\n\n\tself.templateEngineVersion = templateEngineVersion;\n}\n\n#pragma mark -\n#pragma mark Getters\n\n- (BOOL)underlyingWindowColorIsDark\n{\n\tNSColor *windowColor = self.underlyingWindowColor;\n\n\tif (windowColor == nil) {\n\t\treturn NO;\n\t}\n\n\t@try {\n\t\tCGFloat brightness = windowColor.brightnessComponent;\n\n\t\tif (brightness < 0.5) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\t@catch (NSException *exception) {\n\t\tLogToConsoleError(\"Caught exception: %{public}@\", exception.reason);\n\t\tLogStackTrace();\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Setting Loaders\n\n+ (nullable NSString *)_stringForKey:(NSString *)key fromDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(key != nil);\n\tNSParameterAssert(dic != nil);\n\n\tNSString *stringValue = [dic stringForKey:key];\n\n\t/* An empty string should not be considered a valid value */\n\tif (stringValue.length == 0) {\n\t\treturn nil;\n\t}\n\n\treturn stringValue;\n}\n\n+ (nullable NSColor *)_colorForKey:(NSString *)key fromDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(key != nil);\n\tNSParameterAssert(dic != nil);\n\n\tNSString *colorValue = [dic stringForKey:key];\n\n\treturn [NSColor colorWithHexadecimalValue:colorValue];\n}\n\n+ (nullable NSFont *)_fontForKey:(NSString *)key fromDictionary:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(key != nil);\n\tNSParameterAssert(dic != nil);\n\n\tNSDictionary<NSString *, id> *fontDictionary = [dic dictionaryForKey:key];\n\n\tif (fontDictionary == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *fontName = [fontDictionary stringForKey:@\"Font Name\"];\n\n\tif (fontName == nil || [NSFont fontIsAvailable:fontName] == NO) {\n\t\treturn nil;\n\t}\n\n\tCGFloat fontSize = [fontDictionary doubleForKey:@\"Font Size\"];\n\n\tif (fontSize < 5.0) {\n\t\treturn nil;\n\t}\n\n\treturn [NSFont fontWithName:fontName size:fontSize];\n}\n\n#pragma mark -\n#pragma mark Style Settings\n\n- (nullable NSString *)_keyValueStoreName\n{\n\tNSString *storeName = self.settingsKeyValueStoreName;\n\n\tif (storeName.length == 0) {\n\t\treturn nil;\n\t}\n\n\treturn [NSString stringWithFormat:@\"Internal Theme Settings Key-value Store -> %@\", storeName];\n}\n\n- (nullable id)styleSettingsRetrieveValueForKey:(NSString *)key error:(NSString * _Nullable *)resultError\n{\n\tif (key == nil || key.length == 0) {\n\t\tif ( resultError) {\n\t\t\t*resultError = @\"Empty key value\";\n\t\t}\n\n\t\treturn nil;\n\t}\n\n\tNSString *storeKey = [self _keyValueStoreName];\n\n\tif (storeKey == nil) {\n\t\tif ( resultError) {\n\t\t\t*resultError = @\"Empty key-value store name in settings.plist — Set the key \\\"Key-value Store Name\\\" in settings.plist as a string. The current style name is the recommended value.\";\n\t\t}\n\n\t\treturn nil;\n\t}\n\n\tNSDictionary *styleSettings = [RZUserDefaults() dictionaryForKey:storeKey];\n\n\tif (styleSettings == nil) {\n\t\treturn nil;\n\t}\n\n\treturn styleSettings[key];\n}\n\n- (BOOL)styleSettingsSetValue:(nullable id)objectValue forKey:(NSString *)objectKey error:(NSString * _Nullable *)resultError\n{\n\tif (objectKey == nil || objectKey.length <= 0) {\n\t\tif (resultError) {\n\t\t\t*resultError = @\"Empty key value\";\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\tNSString *storeKey = [self _keyValueStoreName];\n\n\tif (storeKey == nil) {\n\t\tif (resultError) {\n\t\t\t*resultError = @\"Empty key-value store name in settings.plist — Set the key \\\"Key-value Store Name\\\" in settings.plist as a string. The current style name is the recommended value.\";\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\tBOOL removeValue = ( objectValue == nil ||\n\t\t\t\t\t\t[objectValue isKindOfClass:[NSNull class]] ||\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\t\t\t\t\t[objectValue isKindOfClass:[WebUndefined class]]);\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n\tNSDictionary *styleSettings = [RZUserDefaults() dictionaryForKey:storeKey];\n\n\tNSMutableDictionary<NSString *, id> *styleSettingsMutable = nil;\n\n\tif (styleSettings == nil) {\n\t\tif (removeValue) {\n\t\t\treturn YES;\n\t\t}\n\n\t\tstyleSettingsMutable = [NSMutableDictionary dictionaryWithCapacity:1];\n\t} else {\n\t\tstyleSettingsMutable = [styleSettings mutableCopy];\n\t}\n\n\tif (removeValue) {\n\t\t[styleSettingsMutable removeObjectForKey:objectKey];\n\t} else {\n\t\tstyleSettingsMutable[objectKey] = objectValue;\n\t}\n\n\t[RZUserDefaults() setObject:[styleSettingsMutable copy] forKey:storeKey];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Preferences/Themes/TPCThemeController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearance.h\"\n#import \"TXGlobalModels.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TDCAlert.h\"\n#import \"TDCProgressIndicatorSheetPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesReload.h\"\n#import \"TPCResourceManager.h\"\n#import \"TPCThemePrivate.h\"\n#import \"TPCThemeControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TPCThemeControllerCustomThemeNameBasicPrefix\t\t\t= @\"user\";\nNSString * const TPCThemeControllerCustomThemeNameCompletePrefix\t\t= @\"user:\";\n\nNSString * const TPCThemeControllerBundledThemeNameBasicPrefix\t\t\t= @\"resource\";\nNSString * const TPCThemeControllerBundledThemeNameCompletePrefix\t\t= @\"resource:\";\n\nNSString * const TPCThemeControllerThemeListDidChangeNotification\t\t= @\"TPCThemeControllerThemeListDidChangeNotification\";\n\ntypedef NSDictionary\t\t<NSString *, TPCTheme *> \t*TPCThemeControllerThemeList;\ntypedef NSMutableDictionary\t<NSString *, TPCTheme *> \t*TPCThemeControllerThemeListMutable;\n\n/* Copy operation class is responsible for copying the active theme to a \n different location when a user requests a local copy of the theme. */\n@interface TPCThemeControllerCopyOperation : NSObject\n@property (nonatomic, weak) TPCThemeController *themeController;\n@property (nonatomic, copy) NSString *themeName; // Name without source prefix\n@property (nonatomic, copy) NSString *pathBeingCopiedTo;\n@property (nonatomic, copy) NSString *pathBeingCopiedFrom;\n@property (nonatomic, assign) TPCThemeStorageLocation destinationLocation;\n@property (nonatomic, assign) BOOL reloadThemeWhenCopied; // If YES, setThemeName: is called when copy completes. Otherwise, files are copied and nothing happens.\n@property (nonatomic, assign) BOOL openThemeWhenCopied;\n@property (nonatomic, strong) TDCProgressIndicatorSheet *progressIndicator;\n\n- (void)beginOperation;\n@end\n\n@interface TPCThemeController ()\n@property (nonatomic, copy) NSString *cachedThemeName;\n@property (nonatomic, copy, readwrite) NSString *cacheToken;\n@property (nonatomic, strong, readwrite) TPCTheme *theme;\n@property (nonatomic, strong, nullable) TPCThemeControllerCopyOperation *currentCopyOperation;\n@property (nonatomic, strong) TPCThemeControllerThemeListMutable bundledThemes;\n@property (nonatomic, strong) TPCThemeControllerThemeListMutable customThemes;\n@property (nonatomic, strong) XRFileSystemMonitor *themeMonitor;\n@end\n\n#pragma mark -\n#pragma mark Theme Controller\n\n@implementation TPCThemeController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.bundledThemes = [NSMutableDictionary dictionary];\n\tself.customThemes = [NSMutableDictionary dictionary];\n\n\t[self populateThemes];\n\n\t[self startMonitoringThemes];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(applicationAppearanceChanged:)\n\t\t\t\t\t\t\t\t   name:TXApplicationAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeIntegrityCompromised:)\n\t\t\t\t\t\t\t\t   name:TPCThemeIntegrityCompromisedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeWasDeleted:)\n\t\t\t\t\t\t\t\t   name:TPCThemeWasDeletedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeWasModified:)\n\t\t\t\t\t\t\t\t   name:TPCThemeWasModifiedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeVarietyChanged:)\n\t\t\t\t\t\t\t\t   name:TPCThemeAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeVarietyChanged:)\n\t\t\t\t\t\t\t\t   name:TPCThemeVarietyChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing theme controller\");\n\n\tLogToConsoleTerminationProgress(\"Removing theme controller observers\");\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\tLogToConsoleTerminationProgress(\"Removing theme change observers\");\n\n\t[self stopMonitoringThemes];\n\n\tLogToConsoleTerminationProgress(\"Empty theme cache\");\n\n\t[self removeTemporaryCopyOfTheme];\n}\n\n- (NSURL *)originalURL\n{\n\treturn self.theme.originalURL;\n}\n\n- (NSString *)originalPath\n{\n\treturn self.originalURL.path;\n}\n\n- (NSURL *)temporaryURL\n{\n\treturn self.theme.temporaryURL;\n}\n\n- (NSString *)temporaryPath\n{\n\treturn self.temporaryURL.path;\n}\n\n- (TPCThemeSettings *)settings\n{\n\treturn self.theme.settings;\n}\n\n- (TPCThemeStorageLocation)storageLocation\n{\n\treturn self.theme.storageLocation;\n}\n\n- (NSString *)name\n{\n\treturn self.theme.name;\n}\n\n- (void)metadata:(void (^ NS_NOESCAPE)(NSString *fileName, TPCThemeStorageLocation storageLocation))metadataBlock ofThemeNamed:(NSString *)themeName\n{\n\tNSParameterAssert(metadataBlock != nil);\n\tNSParameterAssert(themeName != nil);\n\n\tNSString *fileName = [self.class extractThemeName:themeName];\n\n\tif (fileName == nil) {\n\t\treturn;\n\t}\n\n\tTPCThemeStorageLocation storageLocation = [self.class storageLocationOfThemeWithName:themeName];\n\n\tif (storageLocation == TPCThemeStorageLocationUnknown) {\n\t\treturn;\n\t}\n\n\tmetadataBlock(fileName, storageLocation);\n}\n\n- (BOOL)themeExists:(NSString *)themeName\n{\n\tTPCTheme *theme = [self themeNamed:themeName createIfNecessary:YES];\n\n\treturn theme.usable;\n}\n\n- (nullable TPCTheme *)themeNamed:(NSString *)themeName\n{\n\treturn [self themeNamed:themeName createIfNecessary:NO];\n}\n\n- (nullable TPCTheme *)themeNamed:(NSString *)themeName createIfNecessary:(BOOL)createIfNecessary\n{\n\tNSParameterAssert(themeName != nil);\n\n\t__block TPCTheme *theme = nil;\n\n\t[self metadata:^(NSString *fileName, TPCThemeStorageLocation storageLocation) {\n\t\tTPCThemeControllerThemeListMutable list = [self mutableListForStorageLocation:storageLocation];\n\n\t\tif (list == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *filePath = [self.class pathOfThemeWithFilename:fileName storageLocation:storageLocation];\n\n\t\tif (filePath == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSURL *fileURL = [NSURL fileURLWithPath:filePath isDirectory:YES];\n\n\t\ttheme =\n\t\t[self themeAtURL:fileURL\n\t\t\twithFilename:fileName\n\t\t storageLocation:storageLocation\n\t\t\t\t  inList:list\n\t   createIfNecessary:createIfNecessary\n\t\t  skipFileExists:NO];\n\t} ofThemeNamed:themeName];\n\n\treturn theme;\n}\n\n- (nullable TPCTheme *)themeAtURL:(NSURL *)url withFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation inList:(TPCThemeControllerThemeListMutable)list createIfNecessary:(BOOL)createIfNecessary skipFileExists:(BOOL)skipFileExists\n{\n\treturn [self themeAtURL:url\n\t\t\t   withFilename:name\n\t\t\tstorageLocation:storageLocation\n\t\t\t\t\t inList:list\n\t\t  createIfNecessary:createIfNecessary\n\t\t\t\t wasCreated:NULL\n\t\t\t skipFileExists:skipFileExists];\n}\n\n- (nullable TPCTheme *)themeAtURL:(NSURL *)url withFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation inList:(TPCThemeControllerThemeListMutable)list createIfNecessary:(BOOL)createIfNecessary wasCreated:(nullable BOOL *)wasCreated skipFileExists:(BOOL)skipFileExists\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(url.isFileURL);\n\tNSParameterAssert(name != nil);\n\tNSParameterAssert(name.length > 0);\n\tNSParameterAssert(list != nil);\n\n\tTPCTheme *theme = nil;\n\n\t@synchronized (list) {\n\t\ttheme = list[name];\n\t}\n\n\tif (theme || (theme == nil && createIfNecessary == NO)) {\n\t\treturn theme;\n\t}\n\n\tif (skipFileExists == NO && [RZFileManager() directoryExistsAtURL:url] == NO) {\n\t\treturn nil;\n\t}\n\n\ttheme = [[TPCTheme alloc] initWithURL:url inStorageLocation:storageLocation];\n\n\t[self addTheme:theme withFilename:name storageLocation:storageLocation];\n\n\tif ( wasCreated) {\n\t\t*wasCreated = YES;\n\t}\n\n\treturn theme;\n}\n\n- (void)addTheme:(nullable TPCTheme *)theme withFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\t[self add:YES theme:theme withFilename:name storageLocation:storageLocation];\n}\n\n- (void)removeThemeWithFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\t[self add:NO theme:nil withFilename:name storageLocation:storageLocation];\n}\n\n- (void)add:(BOOL)addOrRemove theme:(nullable TPCTheme *)theme withFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert((addOrRemove && theme != nil) ||\n\t\t\t\t\t   addOrRemove == NO);\n\tNSParameterAssert(name != nil);\n\tNSParameterAssert(name.length > 0);\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tTPCThemeControllerThemeListMutable list = [self mutableListForStorageLocation:storageLocation];\n\n\tif (list == nil) {\n\t\treturn;\n\t}\n\n\t@synchronized (list) {\n\t\tif (addOrRemove) {\n\t\t\tlist[name] = theme;\n\t\t} else {\n\t\t\t[list removeObjectForKey:name];\n\t\t}\n\t}\n}\n\n+ (nullable NSString *)pathOfThemeWithName:(NSString *)themeName\n{\n\treturn [self pathOfThemeWithName:themeName storageLocation:NULL];\n}\n\n+ (nullable NSString *)pathOfThemeWithName:(NSString *)themeName storageLocation:(nullable TPCThemeStorageLocation *)storageLocationIn\n{\n\tNSParameterAssert(themeName != nil);\n\n\tTPCThemeStorageLocation storageLocation = [self.class storageLocationOfThemeWithName:themeName];\n\n\tif ( storageLocationIn) {\n\t\t*storageLocationIn = storageLocation;\n\t}\n\n\tif (storageLocation == TPCThemeStorageLocationUnknown) {\n\t\treturn nil;\n\t}\n\n\tNSString *fileName = [self extractThemeName:themeName];\n\n\tif (fileName == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self pathOfThemeWithFilename:fileName storageLocation:storageLocation];\n}\n\n+ (nullable NSString *)pathOfThemeWithFilename:(NSString *)name storageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(name != nil);\n\tNSParameterAssert(name.length > 0);\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tNSString *basePath = [self pathOfStorageLocation:storageLocation];\n\n\tif (basePath == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *filePath = [basePath stringByAppendingPathComponent:name];\n\n\treturn filePath.stringByStandardizingPath;\n}\n\n+ (nullable NSString *)pathOfStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tswitch (storageLocation) {\n\t\tcase TPCThemeStorageLocationBundle:\n\t\t{\n\t\t\treturn [TPCPathInfo bundledThemes];\n\t\t}\n\t\tcase TPCThemeStorageLocationCustom:\n\t\t{\n\t\t\treturn [TPCPathInfo customThemes];\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (nullable TPCThemeControllerThemeListMutable)mutableListForStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tswitch (storageLocation) {\n\t\tcase TPCThemeStorageLocationBundle:\n\t\t{\n\t\t\treturn self.bundledThemes;\n\t\t}\n\t\tcase TPCThemeStorageLocationCustom:\n\t\t{\n\t\t\treturn self.customThemes;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (void)startMonitoringThemes\n{\n\tNSMutableArray<NSURL *> *urls = [NSMutableArray arrayWithCapacity:2];\n\n\tNSMutableDictionary<NSURL *, NSNumber *> *context = [NSMutableDictionary dictionaryWithCapacity:2];\n\n\tvoid (^_addStorageLocation)(TPCThemeStorageLocation) = ^(TPCThemeStorageLocation storageLocation)\n\t{\n\t\tNSString *path = [self.class pathOfStorageLocation:storageLocation];\n\n\t\tif (path == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];\n\n\t\t[urls addObject:url];\n\n\t\t[context setObject:@(storageLocation) forKey:url];\n\t};\n\n\t_addStorageLocation(TPCThemeStorageLocationCustom);\n\n\t__weak TPCThemeController *weakSelf = self;\n\n\t  XRFileSystemMonitor *monitor =\n\t[[XRFileSystemMonitor alloc] initWithFileURLs:urls context:context callbackBlock:^(NSArray<XRFileSystemEvent *> *events) {\n\t\t[weakSelf reactToMonitoringEvents:events];\n\t}];\n\n\t[monitor startMonitoringWithLatency:1.0];\n\n\tself.themeMonitor = monitor;\n}\n\n- (void)stopMonitoringThemes\n{\n\tXRFileSystemMonitor *monitor = self.themeMonitor;\n\n\tif (monitor == nil) {\n\t\treturn;\n\t}\n\n\t[monitor stopMonitoring];\n\n\tself.themeMonitor = nil;\n}\n\n- (void)reactToMonitoringEvents:(NSArray<XRFileSystemEvent *> *)events\n{\n\tNSParameterAssert(events != nil);\n\n\tfor (XRFileSystemEvent *event in events) {\n\t\t[self reactToMonitoringEvent:event];\n\t}\n}\n\n- (void)reactToMonitoringEvent:(XRFileSystemEvent *)event\n{\n\tNSParameterAssert(event != nil);\n\n\t/* The purpose of the theme monitor is to recognize when\n\t new themes have appeared so that we can make them an\n\t option for the user immediately. To accomplish this we\n\t monitor the directory of each storage location. */\n\t/* Monitor is recursive which means we have to use flags\n\t and context information to narrow scope of events. */\n\tFSEventStreamEventFlags flags = event.flags;\n\n\tif ((flags & kFSEventStreamEventFlagItemIsDir) != kFSEventStreamEventFlagItemIsDir) {\n//\t\tLogToConsoleDebug(\"Ignoring monitoring event for non-directory\");\n\n\t\treturn;\n\t}\n\n\t/* Each URL that is monitored is assigned the storage location\n\t enum value as its context object. We can use this to understand\n\t with certainty which storage location an event is related to. */\n\tNSURL *url = event.url;\n\n\tNSURL *parentURL = url.URLByDeletingLastPathComponent;\n\n\t/* If the parent URL of this event does not contain an object,\n\t then the event is not related to a subfolder of the storage location. */\n\tNSNumber *parentContext = [self.themeMonitor contextObjectForURL:parentURL];\n\n\tif (parentContext == nil) {\n//\t\tLogToConsoleDebug(\"Ignoring monitoring event for unrelated directory\");\n\n\t\treturn;\n\t}\n\n\tTPCThemeStorageLocation storageLocation = parentContext.unsignedIntegerValue;\n\n\t[self reactToMonitoringEventAtURL:url storageLocation:storageLocation flags:flags];\n}\n\n- (void)reactToMonitoringEventAtURL:(NSURL *)url storageLocation:(TPCThemeStorageLocation)storageLocation flags:(FSEventStreamEventFlags)flags\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\t/* TPCTheme objects will announce when they are deleted.\n\t We are not interested in events related to those. */\n\tif ([RZFileManager() fileExistsAtURL:url] == NO) {\n\t\treturn;\n\t}\n\n\t/* Create theme */\n\tNSString *themeName = [url resourceValueForKey:NSURLNameKey];\n\n\tTPCThemeControllerThemeListMutable themeList = [self mutableListForStorageLocation:storageLocation];\n\n\tBOOL themeCreated = NO;\n\n\tTPCTheme *theme =\n\t[self themeAtURL:url\n\t\twithFilename:themeName\n\t storageLocation:storageLocation\n\t\t\t  inList:themeList\n   createIfNecessary:YES\n\t\t  wasCreated:&themeCreated\n\t  skipFileExists:YES];\n\n\t/* Only post notification if the theme was created. */\n\tif (themeCreated == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Theme '%{public}@' named '%{public}@' at '%{public}@' created\", theme, themeName, url.standardizedTildePath);\n\n\t[RZNotificationCenter() postNotificationName:TPCThemeControllerThemeListDidChangeNotification object:self];\n}\n\n- (void)populateThemes\n{\n\t[self populateThemesFromStorageLocation:TPCThemeStorageLocationBundle];\n\t[self populateThemesFromStorageLocation:TPCThemeStorageLocationCustom];\n}\n\n- (void)populateThemesFromStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tNSString *path = [self.class pathOfStorageLocation:storageLocation];\n\n\tif (path == nil) {\n\t\treturn;\n\t}\n\n\tTPCThemeControllerThemeListMutable list = [self mutableListForStorageLocation:storageLocation];\n\n\tif (list == nil) {\n\t\treturn;\n\t}\n\n\tNSURL *url = [NSURL fileURLWithPath:path isDirectory:YES];\n\n\tNSError *preFileListError;\n\n\tNSArray *preFileList =\n\t[RZFileManager() contentsOfDirectoryAtURL:url\n\t\t\t\t   includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey]\n\t\t\t\t\t\t\t\t\t  options:(NSDirectoryEnumerationSkipsHiddenFiles |\n\t\t\t\t\t\t\t\t\t\t\t   NSDirectoryEnumerationSkipsPackageDescendants)\n\t\t\t\t\t\t\t\t\t\terror:&preFileListError];\n\n\tif (preFileListError) {\n\t\tLogToConsoleError(\"Failed to list contents of theme folder: %{public}@\",\n\t\t\tpreFileListError.localizedDescription);\n\t}\n\n\tfor (NSURL *fileURL in preFileList) {\n\t\tNSNumber *isDirectory = [fileURL resourceValueForKey:NSURLIsDirectoryKey];\n\n\t\tif ([isDirectory boolValue] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *name = [fileURL resourceValueForKey:NSURLNameKey];\n\n\t\t(void)[self themeAtURL:fileURL\n\t\t\t\t  withFilename:name\n\t\t\t   storageLocation:storageLocation\n\t\t\t\t\t\tinList:list\n\t\t\t createIfNecessary:YES\n\t\t\t\tskipFileExists:YES];\n\t}\n}\n\n- (TPCThemeControllerThemeList)themesInStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tTPCThemeControllerThemeListMutable list = [self mutableListForStorageLocation:storageLocation];\n\n\tif (list == nil) {\n\t\treturn @{};\n\t}\n\n\treturn [list copy];\n}\n\n- (void)enumerateAvailableThemesWithBlock:(void(NS_NOESCAPE ^)(NSString *fileName, TPCThemeStorageLocation storageLocation, BOOL multipleVariants, BOOL *stop))enumerationBlock\n{\n\tNSParameterAssert(enumerationBlock != nil);\n\n\t/* Create a dictionary of the theme name (file name) as the key,\n\t and an array of storage locations it appears within as the value. */\n\tNSMutableDictionary<NSString *, NSMutableArray<NSNumber *> *> *themesMappedByName = [NSMutableDictionary dictionary];\n\n\tvoid (^_mapByName)(TPCThemeStorageLocation) = ^(TPCThemeStorageLocation storageLocation)\n\t{\n\t\tTPCThemeControllerThemeList themes = [self themesInStorageLocation:storageLocation];\n\n\t\t[themes enumerateKeysAndObjectsUsingBlock:^(NSString *name, TPCTheme *theme, BOOL *stop) {\n\t\t\tif (theme.usable == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tNSMutableArray<NSNumber *> *mappedLocations = themesMappedByName[name];\n\n\t\t\tif (mappedLocations == nil) {\n\t\t\t\tmappedLocations = [NSMutableArray array];\n\n\t\t\t\tthemesMappedByName[name] = mappedLocations;\n\t\t\t}\n\n\t\t\t[mappedLocations addObject:@(storageLocation)];\n\t\t}];\n\t};\n\n\t_mapByName(TPCThemeStorageLocationBundle);\n\t_mapByName(TPCThemeStorageLocationCustom);\n\n\t/* Create sorted list of themes */\n\tNSArray *themeNamesSorted = themesMappedByName.sortedDictionaryKeys;\n\n\t/* Perform enumeration */\n\tBOOL stopEnumeration = NO;\n\n\tfor (NSString *themeName in themeNamesSorted) {\n\t\tNSArray *themeLocations = themesMappedByName[themeName];\n\n\t\tBOOL multipleVariants = (themeLocations.count > 1);\n\n\t\tfor (NSNumber *themeLocation in themeLocations) {\n\t\t\tenumerationBlock(themeName, themeLocation.unsignedIntegerValue, multipleVariants, &stopEnumeration);\n\n\t\t\tif (stopEnumeration) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // for themeLocation\n\t} // for themeName\n}\n\n- (void)applicationAppearanceChanged:(NSNotification *)notification\n{\n\t[self.theme updateAppearance];\n}\n\n- (void)themeVarietyChanged:(NSNotification *)notification\n{\n\t[self updatePreferences];\n}\n\n- (void)themeIntegrityCompromised:(NSNotification *)notification\n{\n\tTPCTheme *theme = notification.object;\n\n\tif (self.theme != theme) {\n\t\treturn;\n\t}\n\n\tif ([self resetPreferencesForActiveTheme] == NO) { // Validate theme\n\t\treturn;\n\t}\n\n\tLogToConsoleInfo(\"Reloading theme because it failed validation\");\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionStyle];\n\n\t[RZNotificationCenter() postNotificationName:TPCThemeControllerThemeListDidChangeNotification object:self];\n\n\t[self presentIntegrityCompromisedAlert];\n}\n\n- (void)themeWasDeleted:(NSNotification *)notification\n{\n\tTPCTheme *theme = notification.object;\n\n\t[self removeThemeWithFilename:theme.name storageLocation:theme.storageLocation];\n\n\tif (self.theme != theme) {\n\t\t[RZNotificationCenter() postNotificationName:TPCThemeControllerThemeListDidChangeNotification object:self];\n\n\t\treturn;\n\t}\n\n\tif ([self resetPreferencesForActiveTheme] == NO) { // Validate theme\n\t\tLogToConsoleFault(\"This should be an impossible condition\");\n\t\tLogStackTrace();\n\n\t\treturn;\n\t}\n\n\tLogToConsoleInfo(\"Reloading theme because it was deleted\");\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionStyle];\n\n\t[RZNotificationCenter() postNotificationName:TPCThemeControllerThemeListDidChangeNotification object:self];\n}\n\n- (void)themeWasModified:(NSNotification *)notification\n{\n\tTPCTheme *theme = notification.object;\n\n\tif (self.theme != theme) {\n\t\treturn;\n\t}\n\n\tif ([TPCPreferences automaticallyReloadCustomThemesWhenTheyChange] == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleInfo(\"Reloading theme because it was modified\");\n\n\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionStyle];\n}\n\n- (void)load\n{\n\t/* resetPreferencesForPreferredTheme is called for the configured\n\t theme before the first ever -reload is called to recover from a\n\t style being deleted while the app was closed. */\n\t[self resetPreferencesForPreferredTheme];\n\n\t[self reload];\n}\n\n- (void)reload\n{\n\tNSString *themeName = [TPCPreferences themeName];\n\n\tTPCTheme *theme = [self themeNamed:themeName createIfNecessary:YES];\n\n\tNSAssert1((theme != nil), @\"Missing style resource files: %@\", themeName);\n\n\tif (self.theme != theme) {\n\t\tself.theme = theme;\n\t} else {\n\t\treturn;\n\t}\n\n\tself.cachedThemeName = themeName;\n\n\tself.cacheToken = [NSString stringWithUnsignedInteger:TXRandomNumber(1000000)];\n\n\t[self updatePreferences];\n\n\t[self createTemporaryCopyOfTheme];\n\n\t[self presentCompatibilityAlert];\n\n\t[self presentInvertSidebarColorsAlert];\n}\n\n- (void)updatePreferences\n{\n\t/* Inform our defaults controller about a few overrides. */\n\t/* These setValue calls basically tell the NSUserDefaultsController for the \"Preferences\"\n\t window that the active theme has overrode a few user configurable options. The window then\n\t blanks out the options specified to prevent the user from modifying. */\n\tTPCThemeSettings *settings = self.settings;\n\n\t[TPCPreferences setThemeChannelViewFontPreferenceUserConfigurable:(settings.themeChannelViewFont == nil)];\n\n\t[TPCPreferences setThemeNicknameFormatPreferenceUserConfigurable:(settings.themeNicknameFormat.length == 0)];\n\n\t[TPCPreferences setThemeTimestampFormatPreferenceUserConfigurable:(settings.themeTimestampFormat.length == 0)];\n}\n\n- (void)recreateTemporaryCopyOfThemeIfNecessary\n{\n\tNSURL *temporaryURL = self.temporaryURL;\n\n\tif ([RZFileManager() fileExistsAtURL:temporaryURL]) {\n\t\treturn;\n\t}\n\n\t[self createTemporaryCopyOfTheme];\n}\n\n- (void)removeTemporaryCopyOfTheme\n{\n\tNSURL *temporaryURL = self.temporaryURL;\n\n\tif ([RZFileManager() fileExistsAtURL:temporaryURL] == NO) {\n\t\treturn;\n\t}\n\n\tNSError *removeItemError = nil;\n\n\tif ([RZFileManager() removeItemAtURL:temporaryURL error:&removeItemError] == NO) {\n\t\tLogToConsoleError(\"Failed to remove temporary directory: %{public}@\",\n\t\t\t\tremoveItemError.localizedDescription);\n\t}\n}\n\n- (void)createTemporaryCopyOfTheme\n{\n\tNSURL *originalURL = self.originalURL;\n\n\tNSURL *temporaryURL = self.temporaryURL;\n\n\t[RZFileManager() replaceItemAtURL:temporaryURL\n\t\t\t\t\t\twithItemAtURL:originalURL\n\t\t\t\t\t\t\t  options:CSFileManagerOptionsRemoveIfExists];\n}\n\n- (void)presentCompatibilityAlert\n{\n\tif (self.settings.usesIncompatibleTemplateEngineVersion == NO) {\n\t\treturn;\n\t}\n\n\tNSUInteger themeNameHash = self.cachedThemeName.hash;\n\n\tNSString *suppressionKey = [NSString stringWithFormat:\n\t\t\t\t\t@\"incompatible_theme_dialog_%lu\", themeNameHash];\n\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[76t-pn]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[py0-cr]\", self.name)\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[2a3-5s]\")\n\t\t\t   alternateButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t\tsuppressionKey:suppressionKey\n\t\t\t   suppressionText:nil\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t   if (buttonClicked != TDCAlertResponseDefault) {\n\t\t\t\t\t   return;\n\t\t\t\t   }\n\n\t\t\t\t   [menuController() showStylePreferences:nil];\n\t\t\t   }];\n}\n\n- (void)presentInvertSidebarColorsAlert\n{\n\tif (self.settings.invertSidebarColors == NO) {\n\t\treturn;\n\t}\n\n\tif ([TXSharedApplication sharedAppearance].properties.isDarkAppearance) {\n\t\treturn;\n\t}\n\n\tNSUInteger themeNameHash = self.cachedThemeName.hash;\n\n\tNSString *suppressionKey = [NSString stringWithFormat:\n\t\t\t\t\t\t\t\t@\"theme_appearance_dialog_%lu\", themeNameHash];\n\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[193-6o]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[ezn-rm]\", self.name)\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[hf0-w3]\")\n\t\t\t   alternateButton:TXTLS(@\"Prompts[hv0-79]\")\n\t\t\t\tsuppressionKey:suppressionKey\n\t\t\t   suppressionText:nil\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t   if (buttonClicked == TDCAlertResponseDefault) {\n\t\t\t\t\t   return;\n\t\t\t\t   }\n\n\t\t\t\t   [TPCPreferences setAppearance:TXPreferredAppearanceDark];\n\n\t\t\t\t   [TPCPreferences performReloadAction:TPCPreferencesReloadActionAppearance];\n\t\t\t   }];\n}\n\n- (void)presentIntegrityCompromisedAlert\n{\n\t[TDCAlert alertWithMessage:TXTLS(@\"Prompts[3wd-gj]\")\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[fjw-hj]\", self.name)\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[c4z-2b]\")\n\t\t\t   alternateButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t   completionBlock:^(TDCAlertResponse buttonClicked, BOOL suppressed, id underlyingAlert) {\n\t\t\t\t   if (buttonClicked != TDCAlertResponseDefault) {\n\t\t\t\t\t   return;\n\t\t\t\t   }\n\n\t\t\t\t   [menuController() showStylePreferences:nil];\n\t\t\t   }];\n}\n\n- (void)resetPreferencesForPreferredTheme\n{\n\tNSString *themeName = [TPCPreferences themeName];\n\n\t[self resetPreferencesForThemeNamed:themeName];\n}\n\n- (BOOL)resetPreferencesForActiveTheme\n{\n\tNSString *themeName = self.cachedThemeName;\n\n\treturn [self resetPreferencesForThemeNamed:themeName];\n}\n\n- (BOOL)resetPreferencesForThemeNamed:(NSString *)themeName\n{\n\tNSParameterAssert(themeName != nil);\n\n\tNSString *suggestedFontName = nil;\n\tNSString *suggestedThemeName = nil;\n\n\tBOOL validationResult = [self performValidationForTheme:themeName\n\t\t\t\t\t\t\t\t\t\t\t  suggestedFont:&suggestedFontName\n\t\t\t\t\t\t\t\t\t\t\t suggestedTheme:&suggestedThemeName];\n\n\tif (validationResult) {\n\t\treturn NO;\n\t}\n\n\tif (suggestedFontName) {\n\t\t[TPCPreferences setThemeChannelViewFontName:suggestedFontName];\n\t}\n\n\tif (suggestedThemeName) {\n\t\t[TPCPreferences setThemeName:suggestedThemeName];\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)performValidationForTheme:(NSString *)validatedTheme suggestedFont:(NSString **)suggestedFontName suggestedTheme:(NSString **)suggestedThemeName\n{\n\tNSParameterAssert(validatedTheme != nil);\n\tNSParameterAssert(suggestedFontName != NULL);\n\tNSParameterAssert(suggestedThemeName != NULL);\n\n\t/* Validate font */\n\tBOOL keyChanged = NO;\n\n\tNSString *fontName = [TPCPreferences themeChannelViewFontName];\n\n\tif ([NSFont fontIsAvailable:fontName] == NO) {\n\t\tif ( suggestedFontName) {\n\t\t\t*suggestedFontName = [TPCPreferences themeChannelViewFontNameDefault];\n\t\t}\n\n\t\tkeyChanged = YES;\n\t}\n\n\t/* Validate theme */\n\tNSString *themeName = [self.class extractThemeName:validatedTheme];\n\n\tNSString *themeSource = [self.class extractThemeSource:validatedTheme];\n\n\tLogToConsoleInfo(\"Performing validation on theme named '%{public}@' with source type of '%{public}@'\", themeName, themeSource);\n\n\t/* Note from October 2020 during refactoring:\n\t I know this is ugly as hell. Please don't shame me for it.\n\t I just don't have the time to improve it.\n\t If it works, it works. */\n\n\tif (themeSource == nil || [themeSource isEqualToString:TPCThemeControllerBundledThemeNameBasicPrefix])\n\t{\n\t\t/* Remap name of bundled themes. */\n\t\tNSString *bundledTheme = [self remappedThemeName:validatedTheme];\n\n\t\tif (bundledTheme) {\n\t\t\tif ( suggestedThemeName) {\n\t\t\t\t*suggestedThemeName = bundledTheme;\n\n\t\t\t\tkeyChanged = YES;\n\t\t\t}\n\t\t}\n\n\t\t/* If the theme is faulted and is a bundled theme, then we can do\n\t\t nothing except try to recover by using the default one. */\n\t\tif (bundledTheme == nil) {\n\t\t\tbundledTheme = validatedTheme;\n\t\t}\n\n\t\tif ([self themeExists:bundledTheme] == NO) {\n\t\t\tif ( suggestedThemeName) {\n\t\t\t\t*suggestedThemeName = [TPCPreferences themeNameDefault];\n\n\t\t\t\tkeyChanged = YES;\n\t\t\t}\n\t\t} // preferred theme exists\n\t} // theme source bundled\n\n\telse if ([themeSource isEqualToString:TPCThemeControllerCustomThemeNameBasicPrefix])\n\t{\n\t\tif ([self themeExists:validatedTheme] == NO) {\n\t\t\tNSString *bundledTheme = [self.class buildFilename:themeName forStorageLocation:TPCThemeStorageLocationBundle];\n\n\t\t\tif ([self themeExists:bundledTheme]) {\n\t\t\t\t/* Use a bundled theme with the same name if available. */\n\t\t\t\tif ( suggestedThemeName) {\n\t\t\t\t\t*suggestedThemeName = bundledTheme;\n\n\t\t\t\t\tkeyChanged = YES;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* Revert back to the default theme if no recovery is possible. */\n\t\t\t\tif ( suggestedThemeName) {\n\t\t\t\t\t*suggestedThemeName = [TPCPreferences themeNameDefault];\n\n\t\t\t\t\tkeyChanged = YES;\n\t\t\t\t}\n\t\t\t} // bundled theme exists\n\t\t} // preferred theme exists\n\t} // theme source custom\n\n\treturn (keyChanged == NO);\n}\n\n- (nullable NSString *)remappedThemeName:(NSString *)themeName\n{\n\tNSParameterAssert(themeName != nil);\n\n\tNSDictionary *cachedValues =\n\t[TPCResourceManager dictionaryFromResources:@\"StaticStore\" key:@\"TPCThemeController Remapped Themes\"];\n\n\treturn cachedValues[themeName];\n}\n\n- (BOOL)isBundledTheme\n{\n\treturn (self.storageLocation == TPCThemeStorageLocationBundle);\n}\n\n+ (nullable NSString *)buildFilename:(NSString *)name forStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tNSParameterAssert(name != nil);\n\tNSParameterAssert(name.length > 0);\n\tNSParameterAssert(storageLocation != TPCThemeStorageLocationUnknown);\n\n\tswitch (storageLocation) {\n\t\tcase TPCThemeStorageLocationBundle:\n\t\t{\n\t\t\treturn [TPCThemeControllerBundledThemeNameCompletePrefix stringByAppendingString:name];\n\t\t}\n\t\tcase TPCThemeStorageLocationCustom:\n\t\t{\n\t\t\treturn [TPCThemeControllerCustomThemeNameCompletePrefix stringByAppendingString:name];\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n+ (nullable NSString *)descriptionForStorageLocation:(TPCThemeStorageLocation)storageLocation\n{\n\tswitch (storageLocation) {\n\t\tcase TPCThemeStorageLocationBundle:\n\t\t{\n\t\t\treturn TXTLS(@\"BasicLanguage[7lm-bq]\");\n\t\t}\n\t\tcase TPCThemeStorageLocationCustom:\n\t\t{\n\t\t\treturn TXTLS(@\"BasicLanguage[bm2-4p]\");\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n+ (nullable NSString *)extractThemeSource:(NSString *)source\n{\n\tNSParameterAssert(source != nil);\n\n\tif ([source hasPrefix:TPCThemeControllerCustomThemeNameCompletePrefix] == NO &&\n\t\t[source hasPrefix:TPCThemeControllerBundledThemeNameCompletePrefix] == NO)\n\t{\n\t\treturn nil;\n\t}\n\n\tNSInteger colonIndex = [source stringPosition:@\":\"];\n\n\treturn [source substringToIndex:colonIndex];\n}\n\n+ (nullable NSString *)extractThemeName:(NSString *)source\n{\n\tNSParameterAssert(source != nil);\n\n\tif ([source hasPrefix:TPCThemeControllerCustomThemeNameCompletePrefix] == NO &&\n\t\t[source hasPrefix:TPCThemeControllerBundledThemeNameCompletePrefix] == NO)\n\t{\n\t\treturn nil;\n\t}\n\n\tNSInteger colonIndex = [source stringPosition:@\":\"];\n\n\tNSString *name = [source substringAfterIndex:colonIndex];\n\n\tif (name.length == 0) {\n\t\treturn nil;\n\t}\n\n\treturn name;\n}\n\n+ (TPCThemeStorageLocation)storageLocationOfThemeWithName:(NSString *)themeName\n{\n\tNSParameterAssert(themeName != nil);\n\n\tif ([themeName hasPrefix:TPCThemeControllerCustomThemeNameCompletePrefix]) {\n\t\treturn TPCThemeStorageLocationCustom;\n\t} else if ([themeName hasPrefix:TPCThemeControllerBundledThemeNameCompletePrefix]) {\n\t\treturn TPCThemeStorageLocationBundle;\n\t}\n\n\treturn TPCThemeStorageLocationUnknown;\n}\n\n- (void)copyActiveThemeToDestinationLocation:(TPCThemeStorageLocation)destinationLocation reloadOnCopy:(BOOL)reloadOnCopy openOnCopy:(BOOL)openOnCopy\n{\n\tNSAssert((self.currentCopyOperation == nil),\n\t\t@\"Tried to create a new copy operation with operation already in progress\");\n\n\tif (self.storageLocation == destinationLocation) {\n\t\tLogToConsoleError(\"Tried to copy active theme to same storage location that it already exists within\");\n\n\t\treturn;\n\t}\n\n\tif (TPCThemeStorageLocationBundle == destinationLocation) {\n\t\tLogToConsoleError(\"Tried to copy active theme to the application itself\");\n\n\t\treturn;\n\t}\n\n\tTPCThemeControllerCopyOperation *copyOperation = [TPCThemeControllerCopyOperation new];\n\n\tcopyOperation.themeController = self;\n\n\tcopyOperation.themeName = self.name;\n\n\tcopyOperation.pathBeingCopiedFrom = self.originalPath;\n\n\tcopyOperation.destinationLocation = destinationLocation;\n\n\tcopyOperation.openThemeWhenCopied = openOnCopy;\n\tcopyOperation.reloadThemeWhenCopied = reloadOnCopy;\n\n\t[copyOperation beginOperation];\n\n\tself.currentCopyOperation = copyOperation;\n}\n\n- (void)copyActiveThemeOperationCompleted\n{\n\tself.currentCopyOperation = nil;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Theme Controller Copy Operation\n\n@implementation TPCThemeControllerCopyOperation\n\n- (void)beginOperation\n{\n\t/* Setup progress indicator. */\n\t  TDCProgressIndicatorSheet *progressIndicator =\n\t[[TDCProgressIndicatorSheet alloc] initWithWindow:[NSApp keyWindow]];\n\n\tself.progressIndicator = progressIndicator;\n\n\t[self.progressIndicator start];\n\n\t/* All work is done in a background thread. */\n\t/* Once started, the operation cannot be cancelled. It will occur\n\t then it will either call -cancelOperation itself on failure or wait\n\t for the theme controller itself to call -completeOperation which \n\t signals to the copier that the theme controller sees the files. */\n\tXRPerformBlockAsynchronouslyOnGlobalQueue(^{\n\t\t[self _beginOperation];\n\t});\n}\n\n- (void)_beginOperation\n{\n\t[self _defineDestinationPath];\n\n\tNSURL *sourceURL = [NSURL fileURLWithPath:self.pathBeingCopiedFrom isDirectory:YES];\n\n\tNSURL *destinationURL = [NSURL fileURLWithPath:self.pathBeingCopiedTo isDirectory:YES];\n\n\tif ([RZFileManager() replaceItemAtURL:destinationURL\n\t\t\t\t\t\t\twithItemAtURL:sourceURL\n\t\t\t\t\t\t\t\t  options:(CSFileManagerOptionsMoveToTrash |\n\t\t\t\t\t\t\t\t\t\t   CSFileManagerOptionsRemoveIfExists)] == NO)\n\t{\n\t\t[self cancelOperation];\n\n\t\treturn;\n\t}\n\n\t[self completeOperation];\n}\n\n- (void)_defineDestinationPath\n{\n\tNSString *destinationPath = nil;\n\n\tdestinationPath = [TPCPathInfo customThemes];\n\tdestinationPath = [destinationPath stringByAppendingPathComponent:self.themeName];\n\n\t/* Cast as nonnull to make static analyzer happy */\n\tself.pathBeingCopiedTo = (NSString * _Nonnull)destinationPath;\n}\n\n- (void)cancelOperation\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _cancelOperation];\n\t});\n}\n\n- (void)completeOperation\n{\n\t/* The copy process is usually instantaneous so add a slight \n\t delay because I like to mess with people */\n\t[NSThread sleepForTimeInterval:3.0];\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _completeOperation];\n\t});\n}\n\n- (void)_cancelOperation\n{\n\t[self invalidateOperation];\n}\n\n- (void)_completeOperation\n{\n\t/* Maybe open new path of theme */\n\tif (self.openThemeWhenCopied) {\n\t\tNSURL *fileURL = [NSURL fileURLWithPath:self.pathBeingCopiedTo];\n\n\t\t[RZWorkspace() openURL:fileURL];\n\t}\n\n\t/* Maybe reload new theme */\n\tif (self.reloadThemeWhenCopied) {\n\t\tNSString *newThemeName = [TPCThemeController buildFilename:self.themeName forStorageLocation:self.destinationLocation];\n\n\t\t[TPCPreferences setThemeName:newThemeName];\n\n\t\t[TPCPreferences performReloadAction:TPCPreferencesReloadActionStyle];\n\t}\n\n\t/* Close progress indicator */\n\t[self invalidateOperation];\n}\n\n- (void)invalidateOperation\n{\n\t[self.progressIndicator stop];\n\t self.progressIndicator = nil;\n\n\t[self.themeController copyActiveThemeOperationCompleted];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Services/ICLPayloadLocal.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCThemeController.h\"\n#import \"ICLPayloadInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLPayload (ICLPayloadLocalPrivate)\n\n- (NSString *)_resourcesTemporaryLocation\n{\n//\tNSString *sourcePath = [TPCPathInfo applicationTemporaryProcessSpecific];\n\tNSString *sourcePath = themeController().temporaryPath;\n\n\tNSString *basePath = [sourcePath stringByAppendingPathComponent:@\"/ICLPayload-Resources/\"];\n\n\t[TPCPathInfo _createDirectoryAtPath:basePath];\n\n\treturn basePath;\n}\n\n/* WebKit2 uses sandboxed processes. We copy the resources files to\n the application's temporary folder so that it can access them. */\n- (nullable NSArray<NSString *> *)_copyResourcesToTemporaryLocation:(nullable NSArray<NSURL *> *)resources\n{\n\tif (resources == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *basePath = [self _resourcesTemporaryLocation];\n\n\tNSString *(^copyOperation)(NSURL *) = ^NSString *(NSURL *resourceURL)\n\t{\n\t\tif (resourceURL.isFileURL == NO) {\n\t\t\treturn resourceURL.absoluteString;\n\t\t}\n\n\t\tNSString *resourcePath = resourceURL.relativePath;\n\n\t\tNSString *filename =\n\t\t[NSString stringWithFormat:@\"%@.%@\",\n\t\t resourcePath.md5,\n\t\t resourcePath.pathExtension];\n\n\t\tNSString *destinationPath = [basePath stringByAppendingPathComponent:filename];\n\n\t\tif ([RZFileManager() fileExistsAtPath:destinationPath]) {\n\t\t\treturn destinationPath;\n\t\t}\n\n\t\tNSError *copyError;\n\n\t\tBOOL copyResult =\n\t\t[RZFileManager() copyItemAtPath:resourcePath\n\t\t\t\t\t\t\t\t toPath:destinationPath\n\t\t\t\t\t\t\t\t  error:&copyError];\n\n\t\tif (copyResult == NO) {\n\t\t\tLogToConsoleError(\"Copy operation for '%{public}@' failed with error: %{public}@\",\n\t\t\t\tresourcePath.standardizedTildePath, copyError.localizedDescription);\n\t\t}\n\n\t\treturn destinationPath;\n\t};\n\n\tNSMutableArray<NSString *> *temporaryResources = [NSMutableArray arrayWithCapacity:resources.count];\n\n\tfor (NSURL *resourceURL in resources) {\n\t\t@autoreleasepool {\n\t\t\t[temporaryResources addObject:copyOperation(resourceURL)];\n\t\t}\n\t}\n\n\treturn [temporaryResources copy];\n}\n\n- (NSDictionary<NSString *, id> *)javaScriptObject\n{\n\tNSMutableDictionary *dic = [NSMutableDictionary dictionary];\n\n\t[dic setUnsignedInteger:self->_contentLength forKey:@\"contentLength\"];\n\n\t[dic setObject:@{\n\t\t@\"width\" : @(self->_contentSize.width),\n\t\t@\"height\" : @(self->_contentSize.height)\n\t} forKey:@\"contentSize\"];\n\n\t[dic maybeSetObject:[self _copyResourcesToTemporaryLocation:self->_styleResources]\n\t\t\t\t forKey:@\"styleResources\"];\n\n\t[dic maybeSetObject:[self _copyResourcesToTemporaryLocation:self->_scriptResources]\n\t\t\t\t forKey:@\"scriptResources\"];\n\n\t[dic setObject:self->_html forKey:@\"html\"];\n\n\tNSString *entrypoint = self->_entrypoint;\n\n\tif (entrypoint) {\n\t\t[dic setObject:entrypoint forKey:@\"entrypoint\"];\n\n\t\t/* call self. instead of self->_ for entrypointPayload to allow\n\t\t the default values to be assigned to the exported object. */\n\t\t[dic setObject:self.entrypointPayload forKey:@\"entrypointPayload\"];\n\t}\n\n\t[dic setObject:self->_url forKey:@\"url\"];\n\t[dic setObject:self->_urlToInline forKey:@\"urlToInline\"];\n\n\t[dic setObject:self->_lineNumber forKey:@\"lineNumber\"];\n\n\t[dic setObject:self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n//\t[dic setObject:self->_viewIdentifier forKey:@\"viewIdentifier\"];\n\n\t[dic setUnsignedInteger:self->_index forKey:@\"index\"];\n\n\treturn [dic copy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel Selection Table/TVCChannelSelectionOutlineCellView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCTreeItem.h\"\n#import \"TVCChannelSelectionViewControllerPrivate.h\"\n#import \"TVCChannelSelectionOutlineViewCellPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCChannelSelectionOutlineCellView ()\n@property (readonly) IRCTreeItem *cellItem;\n\n- (IBAction)selectionCheckboxClicked:(id)sender;\n@end\n\n@implementation TVCChannelSelectionOutlineCellView\n\n- (void)prepareInitialState\n{\n\tNSOutlineView *outlineView = self.parentController.outlineView;\n\n\tIRCTreeItem *cellItem = self.cellItem;\n\n\tBOOL isGroupItem = [outlineView isGroupItem:cellItem];\n\n\tself.textField.stringValue = cellItem.name;\n\n\tself.selectedCheckbox.allowsMixedState = isGroupItem;\n}\n\n- (void)selectionCheckboxClicked:(id)sender\n{\n\t[self.parentController selectionCheckboxClickedInCell:self];\n}\n\n- (IRCTreeItem *)cellItem\n{\n\treturn self.objectValue;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel Selection Table/TVCChannelSelectionViewController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCWorld.h\"\n#import \"TVCChannelSelectionOutlineViewCellPrivate.h\"\n#import \"TVCChannelSelectionViewController.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCChannelSelectionViewController ()\n@property (nonatomic, strong) IBOutlet NSScrollView *outlineViewScrollView;\n@property (nonatomic, weak) IBOutlet NSOutlineView *outlineView;\n@property (nonatomic, weak) NSView *attachedView;\n@property (nonatomic, strong) NSMutableArray<NSString *> *cachedSelectedClientIds;\n@property (nonatomic, strong) NSMutableArray<NSString *> *cachedSelectedChannelIds;\n@property (nonatomic, copy) NSDictionary<IRCClient *, NSArray<IRCChannel *> *> *cachedChannelList;\n@property (nonatomic, strong) dispatch_source_t expandOutlineViewTimer;\n@end\n\n@implementation TVCChannelSelectionViewController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TVCChannelSelectionView\" owner:self topLevelObjects:nil];\n\n\t[self addObserverForChannelListUpdates];\n\n\t[self rebuildCachedChannelList];\n}\n\n- (void)dealloc\n{\n\t[self removeObserverForChannelListUpdates];\n}\n\n- (void)attachToView:(NSView *)view\n{\n\tNSParameterAssert(view != nil);\n\n\tif (self.attachedView == nil) {\n\t\tself.attachedView = view;\n\t} else {\n\t\tNSAssert(NO, @\"Table view is already attached to a view\");\n\t}\n\n\tNSScrollView *outlineViewScroller = self.outlineViewScrollView;\n\n\t[view addSubview:outlineViewScroller];\n\n\t[view addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-0-[outlineViewScroller]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(outlineViewScroller)]];\n\n\t[view addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-0-[outlineViewScroller]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(outlineViewScroller)]];\n}\n\n- (nullable IRCTreeItem *)itemFromCellView:(TVCChannelSelectionOutlineCellView *)cellView\n{\n\tNSParameterAssert(cellView != nil);\n\n\tNSOutlineView *outlineView = self.outlineView;\n\n\tNSInteger cellRow = [outlineView rowForView:cellView];\n\n\tif (cellRow < 0) {\n\t\treturn nil;\n\t}\n\n\treturn [outlineView itemAtRow:cellRow];\n}\n\n- (void)selectionCheckboxClickedInCell:(TVCChannelSelectionOutlineCellView *)clickedCell\n{\n\tNSParameterAssert(clickedCell != nil);\n\n\tIRCTreeItem *item = [self itemFromCellView:clickedCell];\n\n\tNSOutlineView *outlineView = self.outlineView;\n\n\tBOOL isGroupItem = [outlineView isGroupItem:item];\n\n\tBOOL isEnablingItem = (clickedCell.selectedCheckbox.state == NSControlStateValueOn ||\n\t\t\t\t\t\t   clickedCell.selectedCheckbox.state == NSControlStateValueMixed);\n\n\t/* Add or remove item from appropriate filter */\n\tif (isGroupItem) {\n\t\tif (isEnablingItem) {\n\t\t\t[self.cachedSelectedClientIds addObject:item.uniqueIdentifier];\n\t\t} else {\n\t\t\t[self.cachedSelectedClientIds removeObject:item.uniqueIdentifier];\n\t\t}\n\t} else {\n\t\tif (isEnablingItem) {\n\t\t\t[self.cachedSelectedChannelIds addObject:item.uniqueIdentifier];\n\t\t} else {\n\t\t\t[self.cachedSelectedChannelIds removeObject:item.uniqueIdentifier];\n\t\t}\n\t}\n\n\t/* Further process filters depending on state of other items */\n\tif (isGroupItem && isEnablingItem) {\n\t\tNSArray *childrenItems = [outlineView itemsFromParentGroup:item];\n\n\t\tfor (IRCTreeItem *childItem in childrenItems) {\n\t\t\t[self.cachedSelectedChannelIds removeObject:childItem.uniqueIdentifier];\n\t\t}\n\t}\n\n\t/* Reload checkbox state for all */\n\t[self updateSelectedStateForItem:item];\n\n\t/* Call out to delegate */\n\tif ([self.delegate respondsToSelector:@selector(channelSelectionControllerSelectionChanged:)]) {\n\t\t[self.delegate channelSelectionControllerSelectionChanged:self];\n\t}\n}\n\n- (void)updateSelectedStateForItem:(IRCTreeItem *)item\n{\n\tNSOutlineView *outlineView = self.outlineView;\n\n\tIRCTreeItem *parentItem = ((item.isClient) ? item : item.associatedClient);\n\n\tNSInteger parentItemRow = [outlineView rowForItem:parentItem];\n\n\tTVCChannelSelectionOutlineCellView *parentItemView = [outlineView viewAtColumn:0 row:parentItemRow makeIfNecessary:NO];\n\n\tBOOL parentItemInFilter = [self.cachedSelectedClientIds containsObject:parentItem.uniqueIdentifier];\n\n\tBOOL atleastOneChildChecked = NO;\n\n\tNSArray *childrenItems = [outlineView itemsInGroup:parentItem];\n\n\tfor (IRCTreeItem *childItem in childrenItems) {\n\t\tNSInteger childItemRow = [outlineView rowForItem:childItem];\n\n\t\tTVCChannelSelectionOutlineCellView *childItemView = [outlineView viewAtColumn:0 row:childItemRow makeIfNecessary:NO];\n\n\t\tBOOL childItemInFilter = [self.cachedSelectedChannelIds containsObject:childItem.uniqueIdentifier];\n\n\t\tif (parentItemInFilter) {\n\t\t\tchildItemView.selectedCheckbox.state = NSControlStateValueOn;\n\t\t} else if (childItemInFilter) {\n\t\t\tif (atleastOneChildChecked == NO) {\n\t\t\t\tatleastOneChildChecked = YES;\n\t\t\t}\n\n\t\t\tchildItemView.selectedCheckbox.state = NSControlStateValueOn;\n\t\t} else {\n\t\t\tchildItemView.selectedCheckbox.state = NSControlStateValueOff;\n\t\t}\n\n\t\tchildItemView.selectedCheckbox.enabled = (parentItemInFilter == NO);\n\t}\n\n\t/* Process parent item */\n\tif (parentItemInFilter) {\n\t\tparentItemView.selectedCheckbox.state = NSControlStateValueOn;\n\t} else if (atleastOneChildChecked) {\n\t\tparentItemView.selectedCheckbox.state = NSControlStateValueMixed;\n\t} else {\n\t\tparentItemView.selectedCheckbox.state = NSControlStateValueOff;\n\t}\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (NSArray<NSString *> *)selectedClientIds\n{\n\t@synchronized (self.cachedSelectedClientIds) {\n\t\treturn [self.cachedSelectedClientIds copy];\n\t}\n}\n\n- (NSArray<NSString *> *)selectedChannelIds\n{\n\t@synchronized (self.cachedSelectedChannelIds) {\n\t\treturn [self.cachedSelectedChannelIds copy];\n\t}\n}\n\n- (void)setSelectedClientIds:(NSArray<NSString *> *)selectedClientIds\n{\n\t@synchronized (self.cachedSelectedClientIds) {\n\t\tif (self->_cachedSelectedClientIds != selectedClientIds) {\n\t\t\tself->_cachedSelectedClientIds = [selectedClientIds mutableCopy];\n\n\t\t\t[self reloadOutlineView];\n\t\t}\n\t}\n}\n\n- (void)setSelectedChannelIds:(NSArray<NSString *> *)selectedChannelIds\n{\n\t@synchronized (self.cachedSelectedChannelIds) {\n\t\tif (self->_cachedSelectedChannelIds != selectedChannelIds) {\n\t\t\tself->_cachedSelectedChannelIds = [selectedChannelIds mutableCopy];\n\n\t\t\t[self reloadOutlineView];\n\t\t}\n\t}\n}\n\n#pragma mark -\n#pragma mark Cache Management\n\n- (void)addObserverForChannelListUpdates\n{\n\t[RZNotificationCenter() addObserver:self selector:@selector(channelListChanged:) name:IRCWorldClientListWasModifiedNotification object:nil];\n\n\t[RZNotificationCenter() addObserver:self selector:@selector(channelListChanged:) name:IRCClientChannelListWasModifiedNotification object:nil];\n}\n\n- (void)removeObserverForChannelListUpdates\n{\n\t[RZNotificationCenter() removeObserver:self];\n}\n\n- (void)reloadOutlineView\n{\n\t[self.outlineView reloadData];\n}\n\n- (void)expandOutlineViewItemsCancelTimer\n{\n\tif (self.expandOutlineViewTimer != nil) {\n\t\tXRCancelScheduledBlock(self.expandOutlineViewTimer);\n\t}\n}\n\n- (void)expandOutlineViewItemsCreateTimer\n{\n\tif (self.expandOutlineViewTimer != nil) {\n\t\treturn;\n\t}\n\n\t__weak TVCChannelSelectionViewController *weakSelf = self;\n\n\tdispatch_source_t expandOutlineViewTimer =\n\tXRScheduleBlockOnMainQueue(^{\n\t\tif (weakSelf == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\t[weakSelf.outlineView expandItem:nil expandChildren:YES];\n\n\t\tweakSelf.expandOutlineViewTimer = nil;\n\t}, 0.5);\n\n\tXRResumeScheduledBlock(expandOutlineViewTimer);\n\n\tself.expandOutlineViewTimer = expandOutlineViewTimer;\n}\n\n- (void)channelListChanged:(id)sender\n{\n\t[self rebuildCachedChannelList];\n\n\t[self reloadOutlineView];\n\n\t[self expandOutlineViewItemsCancelTimer];\n}\n\n- (void)rebuildCachedChannelList\n{\n\tNSArray *clientList = worldController().clientList;\n\n\tNSMutableDictionary<IRCClient *, NSArray<IRCChannel *> *> *cachedChannelList = [NSMutableDictionary dictionary];\n\n\tfor (IRCClient *u in clientList) {\n\t\tNSMutableArray<IRCChannel *> *uChannelList = [NSMutableArray array];\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tif (c.isChannel == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t[uChannelList addObject:c];\n\t\t}\n\n\t\tcachedChannelList[(id)u] = [uChannelList copy];\n\t}\n\n\tself.cachedChannelList = cachedChannelList;\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(nullable id)item\n{\n\tif (item) {\n\t\treturn self.cachedChannelList[item].count;\n\t}\n\n\treturn self.cachedChannelList.count;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(nullable id)item\n{\n\tif (item) {\n\t\treturn self.cachedChannelList[item][index];\n\t}\n\n\treturn self.cachedChannelList.allKeys[index];\n}\n\n- (nullable id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable id)item\n{\n\treturn item;\n}\n\n- (nullable NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(nullable NSTableColumn *)tableColumn item:(id)item\n{\n\tTVCChannelSelectionOutlineCellView *newView = nil;\n\t\n\tif ([item isClient]) {\n\t\tnewView = (id)[outlineView makeViewWithIdentifier:@\"serverEntry\" owner:self];\n\t} else {\n\t\tnewView = (id)[outlineView makeViewWithIdentifier:@\"channelEntry\" owner:self];\n\t}\n\n\tnewView.parentController = self;\n\n\treturn newView;\n}\n\n- (void)outlineView:(NSOutlineView *)outlineView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row\n{\n\t/* Perform work on next pass of the main thread to avoid exception:\n\t \"insertRowsAtIndexes:withRowAnimation: can not happen while updating visible rows!\" */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\tNSView *cellView = [rowView viewAtColumn:0];\n\n\t\t[cellView prepareInitialState];\n\n\t\tid item = [outlineView itemAtRow:row];\n\n\t\t[self updateSelectedStateForItem:item];\n\t});\n\n\t[self expandOutlineViewItemsCreateTimer];\n}\n\n- (BOOL)outlineView:(NSOutlineView *)sender isItemExpandable:(id)item\n{\n\treturn YES;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item\n{\n\treturn NO;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item\n{\n\treturn NO;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldShowOutlineCellForItem:(id)item\n{\n\treturn NO;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/Extras/TVCLogControllerHistoricLogFile.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"HLSHistoricLogProtocol.h\"\n\n#import \"TXMasterController.h\"\n#import \"IRCTreeItem.h\"\n#import \"IRCWorld.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogLinePrivate.h\"\n#import \"TVCLogLineXPCPrivate.h\"\n#import \"TVCLogControllerHistoricLogFilePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogControllerHistoricLogFile ()\n@property (nonatomic, assign, readwrite) BOOL isSaving;\n@property (nonatomic, assign, readwrite) BOOL isTerminating;\n@property (nonatomic, assign, readwrite) BOOL processLoaded;\n@property (nonatomic, assign, readwrite) BOOL processLoading;\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@property (nonatomic, assign) BOOL connectionInvalidatedVoluntarily;\n@property (nonatomic, assign) BOOL connectionInvalidatedErrorDialogDisplayed;\n@property (nonatomic, copy, nullable) NSError *lastServiceConnectionError;\n@end\n\n@implementation TVCLogControllerHistoricLogFile\n\n+ (TVCLogControllerHistoricLogFile *)sharedInstance\n{\n\tstatic id sharedSelf = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsharedSelf = [[self alloc] init];\n\t});\n\n\treturn sharedSelf;\n}\n\n#pragma mark -\n#pragma mark Save Path\n\n- (NSString *)databaseSavePath\n{\n\treturn [TPCPathInfo groupContainerApplicationCaches];\n}\n\n#pragma mark -\n#pragma mark Construction\n\n- (void)warmProcessIfNeeded\n{\n\tif (self.processLoading || self.processLoaded) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Warming process...\");\n\n\tself.processLoading = YES;\n\n\t[self connectToService];\n\n\t[self openDatabase];\n\n\t[self resetMaximumLineCount];\n}\n\n- (void)invalidateProcess\n{\n\tif (self.processLoading == NO && self.processLoaded == NO) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Invalidating process...\");\n\n\tself.connectionInvalidatedVoluntarily = YES;\n\n\t[self.serviceConnection invalidate];\n}\n\n- (void)openDatabase\n{\n\t[[self remoteObjectProxyWithErrorHandler:^(NSError *error) {\n\t\tself.processLoading = NO;\n\t\tself.processLoaded = NO;\n\n\t\tLogToConsoleError(\"Failed to communicate with process to open database\");\n\t}] openDatabaseInDirectory:[self databaseSavePath] withCompletionBlock:^(BOOL success) {\n\t\tif (success) {\n\t\t\tLogToConsoleDebug(\"Successfully opened database\");\n\t\t} else {\n\t\t\tLogToConsoleError(\"Failed to open database\");\n\t\t}\n\n\t\tself.processLoading = NO;\n\t\tself.processLoaded = success;\n\t}];\n}\n\n- (void)connectToService\n{\n\tNSXPCConnection *serviceConnection = [[NSXPCConnection alloc] initWithServiceName:@\"com.codeux.app-utilities.Textual-ScrollbackHistoryManager\"];\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HLSHistoricLogServerProtocol)];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:ascending:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:YES];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:withUniqueIdentifier:beforeFetchLimit:afterFetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:YES];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:beforeUniqueIdentifier:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:YES];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:afterUniqueIdentifier:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:YES];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:afterUniqueIdentifier:beforeUniqueIdentifier:fetchLimit:withCompletionBlock:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:YES];\n\n\tserviceConnection.remoteObjectInterface = remoteObjectInterface;\n\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HLSHistoricLogClientProtocol)];\n\n\tserviceConnection.exportedInterface = exportedInterface;\n\n\tserviceConnection.exportedObject = self;\n\n\tserviceConnection.interruptionHandler = ^{\n\t\t[self interruptionHandler];\n\n\t\tLogToConsole(\"Interruption handler called\");\n\t};\n\n\tserviceConnection.invalidationHandler = ^{\n\t\t[self invalidationHandler];\n\n\t\tLogToConsole(\"Invalidation handler called\");\n\t};\n\n\t[serviceConnection resume];\n\n\tself.serviceConnection = serviceConnection;\n}\n\n- (void)interruptionHandler\n{\n\t[self invalidateProcess];\n}\n\n- (void)invalidationHandler\n{\n\tself.serviceConnection = nil;\n\n\t[self resetContext];\n\n\tif (self.connectionInvalidatedVoluntarily) {\n\t\tself.connectionInvalidatedVoluntarily = NO;\n\n\t\treturn;\n\t}\n\n\t/* Error dialog is purposely only ever shown once */\n\tif (self.connectionInvalidatedErrorDialogDisplayed == NO) {\n\t\tself.connectionInvalidatedErrorDialogDisplayed = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\tNSString *lastErrorMessage = self.lastServiceConnectionError.localizedDescription;\n\n\tif (lastErrorMessage == nil) {\n\t\tlastErrorMessage = @\"\";\n\t} else {\n\t\tlastErrorMessage = TXTLS(@\"Prompts[nlz-um]\", lastErrorMessage);\n\t}\n\n\t[TDCAlert alertWithMessage:lastErrorMessage\n\t\t\t\t\t\t title:TXTLS(@\"Prompts[h99-3q]\")\n\t\t\t\t defaultButton:TXTLS(@\"Prompts[c7s-dq]\")\n\t\t\t   alternateButton:nil];\n}\n\n- (void)resetContext\n{\n\tself.isSaving = NO;\n\n\tself.processLoading = NO;\n\tself.processLoaded = NO;\n}\n\n- (void)resetMaximumLineCount\n{\n\tNSUInteger maximumLineCount = [TPCPreferences scrollbackSaveLimit];\n\n\t[[self remoteObjectProxy] setMaximumLineCount:maximumLineCount];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tself.isTerminating = YES;\n\n\t[self saveData];\n}\n\n#pragma mark -\n#pragma mark Private API\n\n- (id <HLSHistoricLogServerProtocol>)remoteObjectProxy\n{\n\treturn [self remoteObjectProxyWithErrorHandler:nil];\n}\n\n- (id <HLSHistoricLogServerProtocol>)remoteObjectProxyWithErrorHandler:(void (^ _Nullable)(NSError *error))handler\n{\n\treturn [self.serviceConnection remoteObjectProxyWithErrorHandler:^(NSError *error) {\n\t\tself.lastServiceConnectionError = error;\n\n\t\tLogToConsoleError(\"Error occurred while communicating with service: %{public}@\",\n\t\t\terror.localizedDescription);\n\n\t\tif (handler) {\n\t\t\thandler(error);\n\t\t}\n\t}];\n}\n\n#pragma mark -\n#pragma mark Public API\n\n- (NSArray<TVCLogLine *> *)_logLinesFromXPCObjects:(NSArray<TVCLogLineXPC *> *)xpcObjects\n{\n\tNSParameterAssert(xpcObjects != nil);\n\n\tNSMutableArray *logLines = [NSMutableArray arrayWithCapacity:xpcObjects.count];\n\n\tfor (TVCLogLineXPC *xpcObject in xpcObjects) {\n\t\tTVCLogLine *logLine = [TVCLogLine logLineFromXPCObject:xpcObject];\n\n\t\tif (logLine == nil) {\n\t\t\tLogToConsoleError(\"Failed to initialize object %{public}@. Corrupt data?\", xpcObject.description);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t[logLines addObject:logLine];\n\t}\n\n\treturn [logLines copy];\n}\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t\t\t\t  ascending:(BOOL)ascending\n\t\t\t\t  fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\t limitToDate:(nullable NSDate *)limitToDate\n\t\t withCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock\n{\n\t[self warmProcessIfNeeded];\n\n\t__weak typeof(self) weakSelf = self;\n\n\t[[self remoteObjectProxy] fetchEntriesForView:item.uniqueIdentifier\n\t\t\t\t\t\t\t\t\t\tascending:ascending\n\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t  withCompletionBlock:^(NSArray<TVCLogLineXPC *> *entries) {\n\t\t\t\t\t\t\t\t  NSArray *logLines = [weakSelf _logLinesFromXPCObjects:entries];\n\n\t\t\t\t\t\t\t\t  completionBlock(logLines);\n\t\t\t\t\t\t\t  }];\n}\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t   withUniqueIdentifier:(NSString *)uniqueId\n\t\t   beforeFetchLimit:(NSUInteger)fetchLimitBefore\n\t\t\tafterFetchLimit:(NSUInteger)fetchLimitAfter\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock\n{\n\t[self warmProcessIfNeeded];\n\n\t__weak typeof(self) weakSelf = self;\n\n\t[[self remoteObjectProxy] fetchEntriesForView:item.uniqueIdentifier\n\t\t\t\t\t\t\t withUniqueIdentifier:uniqueId\n\t\t\t\t\t\t\t\t beforeFetchLimit:fetchLimitBefore\n\t\t\t\t\t\t\t\t  afterFetchLimit:fetchLimitAfter\n\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t  withCompletionBlock:^(NSArray<TVCLogLineXPC *> *entries) {\n\t\t\t\t\t\t\t\t  NSArray *logLines = [weakSelf _logLinesFromXPCObjects:entries];\n\n\t\t\t\t\t\t\t\t  completionBlock(logLines);\n\t\t\t\t\t\t\t  }];\n}\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t beforeUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock\n{\n\t[self warmProcessIfNeeded];\n\n\t__weak typeof(self) weakSelf = self;\n\n\t[[self remoteObjectProxy] fetchEntriesForView:item.uniqueIdentifier\n\t\t\t\t\t\t   beforeUniqueIdentifier:uniqueId\n\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t  withCompletionBlock:^(NSArray<TVCLogLineXPC *> *entries) {\n\t\t\t\t\t\t\t\t  NSArray *logLines = [weakSelf _logLinesFromXPCObjects:entries];\n\n\t\t\t\t\t\t\t\t  completionBlock(logLines);\n\t\t\t\t\t\t\t  }];\n}\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t  afterUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock\n{\n\t[self warmProcessIfNeeded];\n\n\t__weak typeof(self) weakSelf = self;\n\n\t[[self remoteObjectProxy] fetchEntriesForView:item.uniqueIdentifier\n\t\t\t\t\t\t   afterUniqueIdentifier:uniqueId\n\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t  withCompletionBlock:^(NSArray<TVCLogLineXPC *> *entries) {\n\t\t\t\t\t\t\t\t  NSArray *logLines = [weakSelf _logLinesFromXPCObjects:entries];\n\n\t\t\t\t\t\t\t\t  completionBlock(logLines);\n\t\t\t\t\t\t\t  }];\n}\n\n- (void)fetchEntriesForItem:(IRCTreeItem *)item\n\t  afterUniqueIdentifier:(NSString *)uniqueIdAfter\n\t beforeUniqueIdentifier:(NSString *)uniqueIdBefore\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\twithCompletionBlock:(void (^)(NSArray<TVCLogLine *> *entries))completionBlock\n{\n\t[self warmProcessIfNeeded];\n\n\t__weak typeof(self) weakSelf = self;\n\n\t[[self remoteObjectProxy] fetchEntriesForView:item.uniqueIdentifier\n\t\t\t\t\t\t\tafterUniqueIdentifier:uniqueIdAfter\n\t\t\t\t\t\t   beforeUniqueIdentifier:uniqueIdBefore\n\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t  withCompletionBlock:^(NSArray<TVCLogLineXPC *> *entries) {\n\t\t\t\t\t\t\t\t  NSArray *logLines = [weakSelf _logLinesFromXPCObjects:entries];\n\n\t\t\t\t\t\t\t\t  completionBlock(logLines);\n\t\t\t\t\t\t\t  }];\n}\n\n- (void)saveData\n{\n\tif (self.isTerminating) {\n\t\tif (self.processLoaded == NO && self.processLoading == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (self.isSaving == NO) {\n\t\tself.isSaving = YES;\n\t} else {\n\t\tLogToConsoleDebug(\"Cancelled save because a save is already saving\");\n\n\t\treturn;\n\t}\n\n\t[self warmProcessIfNeeded];\n\n\t[[self remoteObjectProxy] saveDataWithCompletionBlock:^{\n\t\tself.isSaving = NO;\n\n\t\tif (self.isTerminating) {\n\t\t\t[self invalidateProcess];\n\t\t}\n\t}];\n}\n\n- (void)forgetItem:(IRCTreeItem *)item\n{\n\t[self warmProcessIfNeeded];\n\n\t[[self remoteObjectProxy] forgetView:item.uniqueIdentifier];\n}\n\n- (void)resetDataForItem:(IRCTreeItem *)item\n{\n\t[self warmProcessIfNeeded];\n\n\t[[self remoteObjectProxy] resetDataForView:item.uniqueIdentifier];\n}\n\n- (void)writeNewEntryWithLogLine:(TVCLogLine *)logLine forItem:(IRCTreeItem *)item\n{\n\t[self warmProcessIfNeeded];\n\n\tTVCLogLineXPC *newEntry = [logLine xpcObjectForTreeItem:item];\n\n\t[[self remoteObjectProxy] writeLogLine:newEntry];\n}\n\n#pragma mark -\n#pragma mark Private API (Client)\n\n- (void)willDeleteUniqueIdentifiers:(NSArray<NSString *> *)uniqueIdentifiers\n\t\t\t\t\t\t\t inView:(NSString *)viewId\n{\n\tIRCTreeItem *item = [worldController() findItemWithId:viewId];\n\n\tif (item == nil) {\n\t\treturn;\n\t}\n\n\t[item.viewController notifyHistoricLogWillDeleteLines:uniqueIdentifiers];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/Extras/TVCLogControllerInlineMediaService.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentProtocol.h\"\n#import \"ICLPayload.h\"\n#import \"TXMasterController.h\"\n#import \"IRCClient.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCTreeItem.h\"\n#import \"IRCWorld.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPathInfoPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TDCPreferencesControllerPrivate.h\"\n#import \"TVCAlert.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogControllerInlineMediaService ()\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@end\n\n@implementation TVCLogControllerInlineMediaService\n\n+ (TVCLogControllerInlineMediaService *)sharedInstance\n{\n\tstatic id sharedSelf = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsharedSelf = [[self alloc] init];\n\t});\n\n\treturn sharedSelf;\n}\n\n#pragma mark -\n#pragma mark Construction\n\n- (void)warmProcessIfNeeded\n{\n\tif (self.serviceConnection != nil) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Warming process...\");\n\n\t[self connectToService];\n}\n\n- (void)invalidateProcess\n{\n\tif (self.serviceConnection == nil) {\n\t\treturn;\n\t}\n\n\tLogToConsoleDebug(\"Invalidating process...\");\n\n\t[self.serviceConnection invalidate];\n}\n\n- (void)connectToService\n{\n\tNSXPCConnection *serviceConnection = [[NSXPCConnection alloc] initWithServiceName:@\"com.codeux.app-utilities.Textual-InlineContentLoader\"];\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ICLInlineContentServerProtocol)];\n\n\t[remoteObjectInterface setClasses:[NSSet setWithObjects:[NSArray class], [NSURL class], nil]\n\t\t\t\t\t\t  forSelector:@selector(warmServiceByLoadingPluginsAtLocations:)\n\t\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t\t  ofReply:NO];\n\n\tserviceConnection.remoteObjectInterface = remoteObjectInterface;\n\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ICLInlineContentClientProtocol)];\n\n\tserviceConnection.exportedInterface = exportedInterface;\n\n\tserviceConnection.exportedObject = self;\n\n\tserviceConnection.interruptionHandler = ^{\n\t\t[self interruptionHandler];\n\n\t\tLogToConsole(\"Interruption handler called\");\n\t};\n\n\tserviceConnection.invalidationHandler = ^{\n\t\t[self invalidationHandler];\n\n\t\tLogToConsole(\"Invalidation handler called\");\n\t};\n\n\t[serviceConnection resume];\n\n\tself.serviceConnection = serviceConnection;\n\n\t[self registerDefaults];\n\t[self registerPlugins];\n}\n\n- (void)interruptionHandler\n{\n\t[self invalidateProcess];\n}\n\n- (void)invalidationHandler\n{\n\tself.serviceConnection = nil;\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Invalidating media service process\");\n\n\t[self invalidateProcess];\n}\n\n- (void)registerDefaults\n{\n\t/* We pass the registered defaults for the app to the XPC\n\t service because it accesses preferences within that domain. */\n\t/* The registered defaults aren't changed after launch which\n\t means this is a one off deal, but we should use notifications\n\t if that ever changes in the future. */\n\n\tNSDictionary *defaults = [RZUserDefaults() registeredDefaults];\n\n\t[[self remoteObjectProxy] warmServiceByRegisteringDefaults:defaults];\n}\n\n- (void)registerPlugins\n{\n\tNSArray *pluginLocations = @[\n\t\t [self _applicationSupportInlineMediaPluginsURL]\n\t];\n\n\t[[self remoteObjectProxy] warmServiceByLoadingPluginsAtLocations:pluginLocations];\n}\n\n- (NSURL *)_applicationSupportInlineMediaPluginsURL\n{\n\tNSURL *sourceURL = [TPCPathInfo groupContainerApplicationSupportURL];\n\n\tNSURL *baseRL = [sourceURL URLByAppendingPathComponent:@\"/Inline Media Modules/\"];\n\n\t[TPCPathInfo _createDirectoryAtURL:baseRL];\n\n\treturn baseRL;\n}\n\n#pragma mark -\n#pragma mark Private API\n\n- (id <ICLInlineContentServerProtocol>)remoteObjectProxy\n{\n\treturn [self remoteObjectProxyWithErrorHandler:nil];\n}\n\n- (id <ICLInlineContentServerProtocol>)remoteObjectProxyWithErrorHandler:(void (^ _Nullable)(NSError *error))handler\n{\n\treturn [self.serviceConnection remoteObjectProxyWithErrorHandler:^(NSError *error) {\n\t\tLogToConsoleError(\"Error occurred while communicating with service: %{public}@\",\n\t\t\terror.localizedDescription);\n\n\t\tif (handler) {\n\t\t\thandler(error);\n\t\t}\n\t}];\n}\n\n#pragma mark -\n#pragma mark Public API\n\n- (void)processAddress:(NSString *)address withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index forItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(address != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(item != nil);\n\n\t/* WebKit is able to translate an address to punycode\n\t for us by giving it a pasteboard with the URL. */\n\tNSURL *url = address.URLUsingWebKitPasteboard;\n\n\tif (url == nil) {\n\t\tLogToConsoleError(\"Address could not be normalized\");\n\n\t\treturn;\n\t}\n\n\t[self processURL:url withUniqueIdentifier:uniqueIdentifier atLineNumber:lineNumber index:index forItem:item];\n}\n\n- (void)processURL:(NSURL *)url withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index forItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(item != nil);\n\n\t[self warmProcessIfNeeded];\n\n\t[[self remoteObjectProxy] processURL:url withUniqueIdentifier:uniqueIdentifier atLineNumber:lineNumber index:index inView:item.uniqueIdentifier];\n}\n\n- (void)reloadService\n{\n\t[self invalidateProcess];\n}\n\n#pragma mark -\n#pragma mark Private API (Client)\n\n- (void)processingPayloadSucceeded:(ICLPayload *)payload\n{\n\tIRCTreeItem *item = [worldController() findItemWithId:payload.viewIdentifier];\n\n\tif (item == nil) {\n\t\treturn;\n\t}\n\n\t[self _processingPayloadSucceeded:payload forItem:item];\n}\n\n- (void)processingPayload:(ICLPayload *)payload failedWithError:(NSError *)error\n{\n\tIRCTreeItem *item = [worldController() findItemWithId:payload.viewIdentifier];\n\n\tif (item == nil) {\n\t\treturn;\n\t}\n\n\t[self _processingPayload:payload forItem:item failedWithError:error];\n}\n\n- (void)_processingPayloadSucceeded:(ICLPayload *)payload forItem:(IRCTreeItem *)item\n{\n\t[item.viewController processingInlineMediaPayloadSucceeded:payload];\n}\n\n- (void)_processingPayload:(ICLPayload *)payload forItem:(IRCTreeItem *)item failedWithError:(NSError *)error\n{\n\t[item.viewController processingInlineMediaPayload:payload failedWithError:error];\n}\n\n#pragma mark -\n#pragma mark Helpers\n\n+ (void)askPermissionToEnableInlineMediaWithCompletionBlock:(void (NS_NOESCAPE ^)(BOOL granted))completionBlock\n{\n\tBOOL presentDialog = NO;\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tif (u.config.proxyType != IRCConnectionProxyTypeNone) {\n\t\t\tpresentDialog = YES;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (presentDialog == NO) {\n\t\tcompletionBlock(YES);\n\n\t\treturn;\n\t}\n\n\tTVCAlert *alert = [TVCAlert new];\n\n\talert.messageText = TXTLS(@\"Prompts[82q-zi]\");\n\talert.informativeText = TXTLS(@\"Prompts[vcq-sz]\");\n\n\talert.type = TVCAlertTypeWarning;\n\n\t[alert setTitle:TXTLS(@\"Prompts[xkj-nw]\") forButton:TVCAlertResponseButtonFirst];\n\t[alert setTitle:TXTLS(@\"Prompts[qso-2g]\") forButton:TVCAlertResponseButtonSecond];\n\t[alert setTitle:TXTLS(@\"Prompts[x3e-ur]\") forButton:TVCAlertResponseButtonThird];\n\n\t[alert setButtonClickedBlock:^BOOL(TVCAlert *sender, TVCAlertResponseButton buttonClicked) {\n\t\t[TDCPreferencesController openProxySettingsInSystemPreferences];\n\n\t\treturn NO;\n\t} forButton:TVCAlertResponseButtonThird];\n\n\tTVCAlertResponseButton response = [alert runModal];\n\n\tcompletionBlock(response == TVCAlertResponseButtonFirst);\n}\n\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/Extras/TVCLogControllerOperationQueue.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogControllerOperationQueuePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Define Private Header\n\n@interface TVCLogControllerPrintingOperation : NSOperation\n@property (nonatomic, copy, nullable) TVCLogControllerPrintingBlock executionBlock;\n@property (nonatomic, weak) TVCLogController *viewController;\n@property (readonly, getter=isPending) BOOL pending;\n@property (nonatomic, assign, getter=isStandalone) BOOL standalone;\n@end\n\n@interface TVCLogControllerPrintingOperationQueue ()\n/* This queue is application wide and stores all printing operations. \n Having a single queue gives us greater control over what happens,\n instead of trying to optimize one queue per-server. */\n/* One problem of having a single queue through, is indexing which\n operations are associated with which view controller. To make this\n task easier, we maintain our own internal cache of pending operations\n which we can query at any time to know whats happening. The queue\n then observes the isFinished property to know when to remove the\n operations from our internal cache. */\n@property (nonatomic, strong) NSMutableDictionary<NSString *, NSMutableArray *> *pendingOperations;\n@end\n\n#pragma mark -\n#pragma mark Operation Queue\n\n@implementation TVCLogControllerPrintingOperationQueue\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;\n\n\tself.name = @\"TVCLogControllerPrintingOperationQueue\";\n\n\tself.pendingOperations = [NSMutableDictionary dictionary];\n\n\tself.qualityOfService = NSQualityOfServiceDefault;\n }\n\n#pragma mark -\n#pragma mark Queue Additions\n\n- (void)enqueueMessageBlock:(TVCLogControllerPrintingBlock)callbackBlock for:(TVCLogController *)viewController\n{\n\t[self enqueueMessageBlock:callbackBlock for:viewController isStandalone:NO];\n}\n\n- (void)enqueueMessageBlock:(TVCLogControllerPrintingBlock)callbackBlock for:(TVCLogController *)viewController isStandalone:(BOOL)isStandalone\n{\n\tNSParameterAssert(callbackBlock != nil);\n\tNSParameterAssert(viewController != nil);\n\n\tif (masterController().applicationIsTerminating) {\n\t\treturn;\n\t}\n\n\tTVCLogControllerPrintingOperation *operation = [TVCLogControllerPrintingOperation new];\n\n\toperation.executionBlock = callbackBlock;\n\n\toperation.standalone = isStandalone;\n\n\toperation.viewController = viewController;\n\n\t[self addPendingOperation:operation];\n}\n\n#pragma mark -\n#pragma mark Internal Operation Management\n\n- (NSArray<TVCLogControllerPrintingOperation *> *)pendingOperationsForViewController:(TVCLogController *)viewController\n{\n\tNSParameterAssert(viewController != nil);\n\n\tNSString *pendingOperationsKey = viewController.description;\n\n\tNSArray<TVCLogControllerPrintingOperation *> *pendingOperations = nil;\n\n\t@synchronized (self.pendingOperations) {\n\t\tpendingOperations = self.pendingOperations[pendingOperationsKey];\n\t}\n\n\tif (pendingOperations == nil) {\n\t\treturn @[];\n\t}\n\n\treturn [pendingOperations copy];\n}\n\n- (void)addPendingOperation:(TVCLogControllerPrintingOperation *)operation\n{\n\tNSParameterAssert(operation != nil);\n\n\tTVCLogControllerPrintingOperation *operationDependency = nil;\n\n\t/* Add operation to list of pending operations and while we have those,\n\t also pick out what will be its dependency. */\n\tNSString *pendingOperationsKey = operation.viewController.description;\n\n\t@synchronized (self.pendingOperations) {\n\t\tNSMutableArray *pendingOperations = self.pendingOperations[pendingOperationsKey];\n\n\t\tif (pendingOperations == nil) {\n\t\t\tpendingOperations = [NSMutableArray array];\n\n\t\t\tself.pendingOperations[pendingOperationsKey] = pendingOperations;\n\t\t} else {\n\t\t\tfor (TVCLogControllerPrintingOperation *pendingOperation in pendingOperations.reverseObjectEnumerator) {\n\t\t\t\tif (pendingOperation.isCancelled || pendingOperation.isStandalone) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\toperationDependency = pendingOperation;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t[pendingOperations addObject:operation];\n\t}\n\n\t/* Add dependency to operation */\n\tif (operationDependency) {\n\t\t[operation addDependency:operationDependency];\n\t}\n\n\t/* Begin observing when the status of the operation changes */\n\t[operation addObserver:self forKeyPath:@\"isFinished\" options:NSKeyValueObservingOptionNew context:nil];\n\n\t/* Add operation to the queue */\n\t[super addOperation:operation];\n}\n\n- (void)removePendingOperation:(TVCLogControllerPrintingOperation *)operation\n{\n\tNSParameterAssert(operation != nil);\n\n\t/* Remove operation from list of pending operations */\n\tNSString *pendingOperationsKey = operation.viewController.description;\n\n\t@synchronized (self.pendingOperations) {\n\t\tNSMutableArray *pendingOperations = self.pendingOperations[pendingOperationsKey];\n\n\t\tif (pendingOperations == nil) {\n\t\t\tLogToConsoleError(\"'pendingOperations' is nil when it's not supposed to be. wat?\");\n\n\t\t\treturn;\n\t\t}\n\n\t\t[pendingOperations removeObjectIdenticalTo:operation];\n\t}\n\n\t/* Remove dependency to operation */\n\t/* Having a ton of chained dependencies can cause a stack overflow\n\t when they deallocate. Manually removing dependencies fixes this pattern:\n\n\t 0   CoreFoundation                       0x00007fffa2694d1e -[__NSArrayM dealloc] + 14\n\t 1   Foundation                           0x00007fffa410d79b -[__NSOperationInternal dealloc] + 177\n\t 2   Foundation                           0x00007fffa410d664 -[NSOperation dealloc] + 58\n\t 3   CoreFoundation                       0x00007fffa27e237e common_removeAllObjects + 254\n\t 4   CoreFoundation                       0x00007fffa2694d23 -[__NSArrayM dealloc] + 19\n\t 5   Foundation                           0x00007fffa410d79b -[__NSOperationInternal dealloc] + 177\n\t 6   Foundation                           0x00007fffa410d664 -[NSOperation dealloc] + 58\n\t 7   CoreFoundation                       0x00007fffa27e237e common_removeAllObjects + 254\n\n\t ... repeated for a total of 512 hops before crashing. */\n\tNSOperation *operationDependency = operation.dependencies.firstObject;\n\n\tif (operationDependency) {\n\t\t[operation removeDependency:operationDependency];\n\t}\n\n\t/* End observing when the status of the operation changes */\n\t[operation removeObserver:self forKeyPath:@\"isFinished\"];\n}\n\n#pragma mark -\n#pragma mark cancelAllOperations Substitute\n\n- (void)cancelOperationsForViewController:(TVCLogController *)viewController\n{\n\tNSParameterAssert(viewController != nil);\n\n\tNSArray *operations = [self pendingOperationsForViewController:viewController];\n\n\t[operations makeObjectsPerformSelector:@selector(cancel)];\n}\n\n- (void)cancelOperationsForClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\t[self cancelOperationsForViewController:client.viewController];\n}\n\n- (void)cancelOperationsForChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[self cancelOperationsForViewController:channel.viewController];\n}\n\n#pragma mark -\n#pragma mark State Changes\n\n- (void)updateReadinessState:(TVCLogController *)viewController\n{\n\tNSParameterAssert(viewController != nil);\n\n\tNSArray *operations = [self pendingOperationsForViewController:viewController];\n\n\tfor (TVCLogControllerPrintingOperation *operation in operations) {\n\t\tif (operation.isPending == NO || operation.dependencies.count > 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[operation willChangeValueForKey:@\"isReady\"];\n\t\t[operation didChangeValueForKey:@\"isReady\"];\n\t}\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"isFinished\"]) {\n\t\t[self removePendingOperation:object];\n\t}\n}\n\n@end\n\n#pragma mark -\n#pragma mark Operation Queue Items\n\n@implementation TVCLogControllerPrintingOperation\n\n- (BOOL)isPending\n{\n\treturn (self.isCancelled == NO && self.isExecuting == NO && self.isFinished == NO);\n}\n\n- (void)main\n{\n\t[self executeBlock];\n}\n\n- (void)executeBlock\n{\n\tif (self.isCancelled) {\n\t\treturn;\n\t}\n\n\tself.executionBlock(self);\n}\n\n- (BOOL)isReady\n{\n\tif (self.dependencies.count < 1 || self.isStandalone) {\n\t\treturn (super.isReady && self.viewController.viewIsLoaded);\n\t} else {\n\t\treturn  super.isReady;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXGlobalModels.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"ICLPayloadLocalPrivate.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCChannel.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"THOPluginProtocolPrivate.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCThemePrivate.h\"\n#import \"TLOLinkParser.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogLine.h\"\n#import \"TVCLogRenderer.h\"\n#import \"TVCLogControllerHistoricLogFilePrivate.h\"\n#import \"TVCLogControllerInlineMediaServicePrivate.h\"\n#import \"TVCLogControllerOperationQueuePrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _enqueueBlock(operationBlock)\t\t\t\\\n\t[self.printingQueue enqueueMessageBlock:(operationBlock) for:self isStandalone:NO];\n\n#define _enqueueBlockStandalone(operationBlock)\t\t\t\\\n\t[self.printingQueue enqueueMessageBlock:(operationBlock) for:self isStandalone:YES];\n\n@interface TVCLogControllerPrintOperationContext ()\n@property (nonatomic, weak, readwrite) IRCClient *client;\n@property (nonatomic, weak, readwrite) IRCChannel *channel;\n@property (nonatomic, assign, readwrite, getter=isHighlight) BOOL highlight;\n@property (nonatomic, copy, readwrite) TVCLogLine *logLine;\n@property (nonatomic, copy, readwrite) NSString *lineNumber;\n@end\n\n@interface TVCLogController ()\n@property (nonatomic, assign, readwrite, getter=viewIsLoaded) BOOL loaded;\n@property (nonatomic, assign) BOOL terminating;\n@property (nonatomic, assign) BOOL historyLoadedForFirstTime;\n@property (nonatomic, assign) BOOL reloadingHistory;\n@property (nonatomic, assign) BOOL reloadingTheme;\n@property (nonatomic, assign) BOOL historyLoaded;\n@property (nonatomic, assign) NSInteger activeLineCount;\n@property (nonatomic, copy, nullable) NSString *lastVisitedHighlight;\n@property (nonatomic, copy, nullable, readwrite) NSString *newestLineNumberFromPreviousSession;\n@property (nonatomic, copy, nullable, readwrite) NSString *oldestLineNumber;\n@property (nonatomic, copy, nullable, readwrite) NSString *newestLineNumber;\n@property (nonatomic, strong, nullable) TVCLogLine *lastLine;\n@property (nonatomic, strong) NSMutableArray<NSString *> *highlightedLineNumbers;\n@property (nonatomic, strong) NSCache *jumpToLineCallbacks;\n@property (nonatomic, strong, readwrite) TVCLogView *backingView;\n@property (weak, readonly) IRCTreeItem *associatedItem;\n@property (nonatomic, weak, readwrite) IRCClient *associatedClient;\n@property (nonatomic, weak, readwrite) IRCChannel *associatedChannel;\n@property (nonatomic, weak, readwrite) TVCMainWindow *attachedWindow;\n@property (nonatomic, assign) NSTimeInterval viewLoadedTimestamp;\n@property (readonly) TVCLogControllerPrintingOperationQueue *printingQueue;\n@property (readonly, copy) NSURL *baseURL;\n@end\n\nNSString * const TVCLogControllerViewFinishedLoadingNotification = @\"TVCLogControllerViewFinishedLoadingNotification\";\n\n@implementation TVCLogController\n\n#pragma mark -\n#pragma mark Initialization\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithClient:(IRCClient *)client inWindow:(TVCMainWindow *)window\n{\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(window != nil);\n\n\tif ((self = [super init])) {\n\t\tself.associatedClient = client;\n\n\t\tself.attachedWindow = window;\n\n\t\t[self prepareInitialState];\n\n\t\t[self setUp];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithChannel:(IRCChannel *)channel inWindow:(TVCMainWindow *)window\n{\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(window != nil);\n\n\tif ((self = [super init])) {\n\t\tself.associatedClient = channel.associatedClient;\n\t\tself.associatedChannel = channel;\n\n\t\tself.attachedWindow = window;\n\n\t\t[self prepareInitialState];\n\n\t\t[self setUp];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tself.encrypted = self.associatedChannel.encryptionStateIsEncrypted;\n#endif\n\n\tself.highlightedLineNumbers\t= [NSMutableArray new];\n\n\tself.jumpToLineCallbacks = [NSCache new];\n}\n\n- (void)prepareForTermination:(BOOL)isTerminatingApplication\n{\n\tself.terminating = YES;\n\n\tself.loaded = NO;\n\n\t[self.backingView stopLoading]; // allow view to teardown\n\tself.backingView = nil;\n\n\t[self.printingQueue cancelOperationsForViewController:self];\n\n\tif (isTerminatingApplication) {\n\t\t[self closeHistoricLog];\n\t} else {\n\t\t[self historicLogForgetChannel];\n\t}\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Preparing view controller: %{public}@\", self.uniqueIdentifier);\n\n\t[self prepareForTermination:YES];\n}\n\n- (void)prepareForPermanentDestruction\n{\n\t[self prepareForTermination:NO];\n}\n\n- (void)dealloc\n{\n\t[self cancelPerformRequests];\n}\n\n#pragma mark -\n#pragma mark Create View\n\n- (void)setUp\n{\n\t[self buildBackingView];\n\n\t[self loadInitialDocument];\n}\n\n- (void)buildBackingView\n{\n\tself.backingView = [[TVCLogView alloc] initWithViewController:self];\n}\n\n- (void)rebuildBackingView\n{\n\t[self buildBackingView];\n\n\tif (self.visible) {\n\t\t[self.attachedWindow updateChannelViewBoxContentViewSelection];\n\t}\n}\n\n- (void)loadInitialDocument\n{\n\t[self loadAlternateHTML:[self initialDocument]];\n}\n\n- (void)loadAlternateHTML:(NSString *)newHTML\n{\n\tNSParameterAssert(newHTML != nil);\n\n\t[self.backingView stopLoading];\n\n\t[self.backingView loadHTMLString:newHTML baseURL:self.baseURL];\n}\n\n#pragma mark -\n#pragma mark Manage Historic Log\n\n- (void)historicLogForgetChannel\n{\n\t/* Delete any trace of the channel, including context */\n\t[TVCLogControllerHistoricLogSharedInstance() forgetItem:self.associatedItem];\n}\n\n- (void)historicLogResetChannel\n{\n\t/* Delete log for channel but keep context */\n\t[TVCLogControllerHistoricLogSharedInstance() resetDataForItem:self.associatedItem];\n}\n\n- (void)closeHistoricLog\n{\n\t/* The historic log file is always open regardless of whether the user asked\n\t Textual to remember the history between restarts. It is always open because\n\t the reloading of a theme uses it to fill in the backlog after a reload.\n\t -closeHistoricLog is the point where we decide to actually save the file\n\t or erase it. If the user has Textual configured to remember between restarts,\n\t then we call a save before terminating. Or, we just erase the file from the\n\t path that it is written to entirely. */\n\n\tIRCChannel *channel = self.associatedChannel;\n\n\tif (\n\t\t/* 1 */ [TPCPreferences reloadScrollbackOnLaunch] == NO ||\n\t\t/* 2 */  channel.isUtility ||\n\t\t/* 3 */ (channel.isPrivateMessage &&\n\t\t\t\t [TPCPreferences rememberServerListQueryStates] == NO) ||\n\t\t/* 4 */ self.encrypted)\n\t{\n\t\t[self historicLogResetChannel];\n\t}\n}\n\n#pragma mark -\n#pragma mark Properties\n\n- (nullable IRCTreeItem *)associatedItem\n{\n\tif (self.associatedChannel) {\n\t\treturn self.associatedChannel;\n\t} else {\n\t\treturn self.associatedClient;\n\t}\n}\n\n- (NSString *)uniqueIdentifier\n{\n\treturn self.associatedItem.uniqueIdentifier;\n}\n\n- (NSURL *)baseURL\n{\n\treturn themeController().temporaryURL;\n}\n\n- (TVCLogControllerPrintingOperationQueue *)printingQueue\n{\n\treturn [TXSharedApplication sharedPrintingQueue];\n}\n\n- (BOOL)inlineMediaEnabledForView\n{\n\tIRCChannel *channel = self.associatedChannel;\n\n\tif (channel == nil) {\n\t\treturn NO;\n\t}\n\n\tIRCChannelConfig *config = channel.config;\n\n\treturn (([TPCPreferences showInlineMedia]\t\t&& config.inlineMediaDisabled == NO) ||\n\t\t\t([TPCPreferences showInlineMedia] == NO\t&& config.inlineMediaEnabled));\n}\n\n- (BOOL)viewIsSelected\n{\n\treturn (self.attachedWindow.selectedViewController == self);\n}\n\n- (BOOL)viewIsVisible\n{\n\tIRCChannel *channel = self.associatedChannel;\n\n\tif (channel) {\n\t\treturn [self.attachedWindow isItemVisible:channel];\n\t} else {\n\t\treturn [self.attachedWindow isItemVisible:self.associatedClient];\n\t}\n}\n\n#pragma mark -\n#pragma mark Document Append & JavaScript Controller\n\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments\n{\n\t[self evaluateFunction:function withArguments:arguments onQueue:YES];\n}\n\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments onQueue:(BOOL)onQueue\n{\n\tNSParameterAssert(function != nil);\n\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\tif (onQueue) {\n\t\tTVCLogControllerPrintingBlock scriptBlock = ^(id operation) {\n\t\t\t[self _evaluateFunction:function withArguments:arguments];\n\t\t};\n\n\t\t_enqueueBlock(scriptBlock)\n\t} else {\n\t\t[self _evaluateFunction:function withArguments:arguments];\n\t}\n}\n\n- (void)_evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments\n{\n\tNSParameterAssert(function != nil);\n\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn;\n\t}\n\n\t[self.backingView evaluateFunction:function withArguments:arguments];\n}\n\n- (void)appendToDocumentBody:(NSString *)html withLineNumbers:(NSArray<NSString *> *)lineNumbers\n{\n\tNSParameterAssert(html != nil);\n\n\t[self _evaluateFunction:@\"MessageBuffer.bufferElementAppend\" withArguments:@[html, lineNumbers]];\n}\n\n#pragma mark -\n#pragma mark Channel Topic Bar\n\n- (void)setInitialTopic\n{\n\tNSString *topic = self.associatedChannel.topic;\n\n\t[self setTopic:topic];\n}\n\n- (void)setTopic:(nullable NSString *)topic\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tNSString *topicString = nil;\n\n\t\tif (topic == nil || topic.length == 0) {\n\t\t\ttopicString = TXTLS(@\"TVCMainWindow[vi3-23]\");\n\t\t} else {\n\t\t\ttopicString = topic;\n\t\t}\n\n\t\tNSString *topicTemplate = [TVCLogRenderer renderBody:topicString\n\t\t\t\t\t\t\t\t\t\t   forViewController:self\n\t\t\t\t\t\t\t\t\t\t\t  withAttributes:@{\n\t\t\t\t\t\t\t\t\t\t\t\t\tTVCLogRendererConfigurationRenderLinksAttribute : @YES,\n\t\t\t\t\t\t\t\t\t\t\t\t\tTVCLogRendererConfigurationLineTypeAttribute : @(TVCLogLineTypeTopic)\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t  resultInfo:NULL];\n\n\t\t[self _evaluateFunction:@\"Textual.setTopicBarValue\" withArguments:@[topicString, topicTemplate]];\n\n\t\t[self.backingView redrawView];\n\t};\n\n\t_enqueueBlockStandalone(operationBlock)\n}\n\n#pragma mark -\n#pragma mark Move to Bottom/Top\n\n- (void)moveToTop\n{\n\t[self _evaluateFunction:@\"Textual.scrollToTopOfView\" withArguments:@[@(YES)]];\n}\n\n- (void)moveToBottom\n{\n\t[self _evaluateFunction:@\"Textual.scrollToBottomOfView\" withArguments:@[@(YES)]];\n}\n\n#pragma mark -\n#pragma mark Add/Remove History Mark\n\n- (void)mark\n{\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tNSString *markTemplate = [TVCLogRenderer renderTemplateNamed:@\"historyIndicator\"];\n\n\t\t[self _evaluateFunction:@\"_Textual.historyIndicatorAdd\" withArguments:@[markTemplate]];\n\t};\n\n\t_enqueueBlock(operationBlock);\n}\n\n- (void)unmark\n{\n\t[self _evaluateFunction:@\"_Textual.historyIndicatorRemove\" withArguments:nil];\n}\n\n- (void)goToMark\n{\n\t[self _evaluateFunction:@\"Textual.scrollToHistoryIndicator\" withArguments:nil];\n}\n\n#pragma mark -\n#pragma mark Reload Scrollback\n\n- (void)appendHistoricMessageFragment:(NSString *)html withLineNumbers:(NSArray<NSString *> *)lineNumbers isReload:(BOOL)isReload\n{\n\tNSParameterAssert(html != nil);\n\n\t[self _evaluateFunction:@\"_Textual.documentBodyAppendHistoric\" withArguments:@[html, lineNumbers, @(isReload)]];\n}\n\n/* reloadOldLines: is supposed to be called from inside a queue. */\n- (void)reloadOldLines:(NSArray<TVCLogLine *> *)oldLines isReload:(BOOL)isReload\n{\n\tNSParameterAssert(oldLines != nil);\n\n\tNSMutableArray<NSString *> *lineNumbers = [NSMutableArray array];\n\n\tNSMutableString *patchedAppend = [NSMutableString string];\n\n\tNSMutableArray<THOPluginDidPostNewMessageConcreteObject *> *pluginObjects = nil;\n\n\tfor (TVCLogLine *logLine in oldLines) {\n\t\t/* Render result info HTML */\n\t\tNSDictionary<NSString *, id> *resultInfo = nil;\n\n\t\tNSString *html = [self renderLogLine:logLine resultInfo:&resultInfo];\n\n\t\tif (html == nil) {\n\t\t\tLogToConsoleError(\"Failed to render log line %{public}@\", logLine.description);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t[patchedAppend appendString:html];\n\n\t\t/* Record information about rendering */\n\t\tNSString *lineNumber = logLine.uniqueIdentifier;\n\n\t\t[lineNumbers addObject:lineNumber];\n\n\t\t/* Add reference to plugin concrete object */\n\t\tTHOPluginDidPostNewMessageConcreteObject *pluginObject = resultInfo[@\"pluginConcreteObject\"];\n\n\t\tif (pluginObject) {\n\t\t\tif (pluginObjects == nil) {\n\t\t\t\tpluginObjects = [NSMutableArray array];\n\t\t\t}\n\n\t\t\t[pluginObjects addObject:pluginObject];\n\t\t}\n\n\t\t/* Record highlights */\n\t\tBOOL highlighted = [resultInfo boolForKey:TVCLogRendererResultsKeywordMatchFoundAttribute];\n\n\t\tif (highlighted) {\n\t\t\t@synchronized(self.highlightedLineNumbers) {\n\t\t\t\t[self.highlightedLineNumbers addObject:lineNumber];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Render the result in WebKit */\n\t[self appendHistoricMessageFragment:patchedAppend withLineNumbers:lineNumbers isReload:isReload];\n\n\t/* Inform plugins of new content */\n\tfor (THOPluginDidPostNewMessageConcreteObject *pluginObject in pluginObjects) {\n\t\tpluginObject.isProcessedInBulk = YES;\n\n\t\t[THOPluginDispatcher enqueueDidPostNewMessage:pluginObject];\n\t}\n}\n\n- (void)maybeReloadHistory\n{\n\tif (self.loaded == NO) {\n\t\treturn;\n\t}\n\n\tif (self.historyLoaded) {\n\t\treturn;\n\t}\n\n\t[self reloadHistory];\n}\n\n- (void)reloadHistory\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\tBOOL firstTimeLoadingHistory = (self.historyLoadedForFirstTime == NO);\n\n\tIRCChannel *channel = self.associatedChannel;\n\n\tif (\n\t\t/* 1 */ self.encrypted ||\n\t\t/* 2 */ (firstTimeLoadingHistory &&\n\t\t\t\t [TPCPreferences reloadScrollbackOnLaunch] == NO) ||\n\t\t/* 3 */  channel.isUtility ||\n\t\t/* 4 */ (firstTimeLoadingHistory &&\n\t\t\t\t channel.isPrivateMessage &&\n\t\t\t\t [TPCPreferences rememberServerListQueryStates] == NO))\n\t{\n\t\tself.historyLoadedForFirstTime = YES;\n\n\t\tself.historyLoaded = YES;\n\n\t\t[self notifyViewFinishedLoadingHistory];\n\n\t\treturn;\n\t} else {\n\t\tBOOL lazyLoadHistory = [RZUserDefaults() boolForKey:@\"Optimizations -> Load History Lazily\"];\n\n\t\tif (lazyLoadHistory && self.visible == NO) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tself.reloadingHistory = YES;\n\n\tvoid (^reloadBlock)(NSArray *) = ^(NSArray<TVCLogLine *> *objects) {\n\t\tTVCLogLine *lastLine = objects.lastObject;\n\n\t\t/* Only assign lastLine to self if there is none because\n\t\t if we do it when there is some, then there will be a big\n\t\t cluster fuck of incorrect date changes. */\n\t\tif (self.lastLine == nil) {\n\t\t\tself.lastLine = lastLine;\n\t\t}\n\n\t\tif (firstTimeLoadingHistory) {\n\t\t\tNSString *newestLineNumber = lastLine.uniqueIdentifier;\n\n\t\t\tself.newestLineNumberFromPreviousSession = newestLineNumber;\n\t\t}\n\n\t\t[self reloadOldLines:objects isReload:(firstTimeLoadingHistory == NO)];\n\n\t\tself.reloadingHistory = NO;\n\n\t\tself.historyLoaded = YES;\n\t\tself.historyLoadedForFirstTime = YES;\n\n\t\t[self notifyViewFinishedLoadingHistory];\n\n\t\t[self.backingView redrawViewIfNeeded];\n\t};\n\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tNSDate *limitToDate = [NSDate dateWithTimeIntervalSince1970:self.viewLoadedTimestamp];\n\n\t\t[TVCLogControllerHistoricLogSharedInstance()\n\t\t fetchEntriesForItem:self.associatedItem\n\t\t\t\t   ascending:NO\n\t\t\t\t  fetchLimit:100\n\t\t\t\t limitToDate:limitToDate\n\t\t withCompletionBlock:^(NSArray<TVCLogLine *> *objects) {\n\t\t\t\tif ([operation isCancelled]) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treloadBlock(objects.reverseObjectEnumerator.allObjects);\n\t\t }];\n\t};\n\n\t_enqueueBlockStandalone(operationBlock)\n}\n\n- (void)reloadTheme\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _reloadTheme];\n\t});\n}\n\n- (void)_reloadTheme\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\tif (self.reloadingTheme) {\n\t\treturn;\n\t}\n\n\t/* Even if the user has never loaded their history, we force this\n\t flag to YES when reloading theme. We do not want history to be\n\t displayed as historic when playing it back after a reload. */\n\tself.historyLoadedForFirstTime = YES;\n\n\tself.reloadingTheme = YES;\n\n\t[self clearWithReset:NO];\n\n\tself.reloadingTheme = NO;\n}\n\n- (NSString *)dateIndicatorWithDate:(NSDate *)date\n{\n\tNSParameterAssert(date != nil);\n\n\tNSString *dateString = TXFormatDate(date, NSDateFormatterLongStyle, NSDateFormatterNoStyle, NO);\n\n\treturn dateString;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)jumpToCurrentSession\n{\n\tNSString *lineNumber = self.newestLineNumberFromPreviousSession;\n\n\tif (lineNumber == nil) {\n\t\tlineNumber = self.oldestLineNumber;\n\t}\n\n\tif (lineNumber == nil) {\n\t\treturn;\n\t}\n\n\t[self jumpToLine:lineNumber];\n}\n\n- (void)jumpToPresent\n{\n\tNSString *lineNumber = self.newestLineNumber;\n\n\tif (lineNumber == nil) {\n\t\tlineNumber = self.newestLineNumberFromPreviousSession;\n\t}\n\n\tif (lineNumber == nil) {\n\t\treturn;\n\t}\n\n\t[self jumpToLine:lineNumber];\n}\n\n- (void)jumpToLine:(NSString *)lineNumber\n{\n\t[self jumpToLine:lineNumber completionHandler:nil];\n}\n\n- (void)jumpToLine:(NSString *)lineNumber completionHandler:(void (^ _Nullable)(BOOL result))completionHandler\n{\n\tNSParameterAssert(lineNumber != nil);\n\n\t/* Jumping to line chains callback functions which may take time to load.\n\t We do not want invoke the completion handler until we know for certain\n\t whether the line was jumped to. We therefore change the completion\n\t handler and call it from a bridged function when we are finished. */\n\tif (completionHandler) {\n\t\t[self.jumpToLineCallbacks setObject:completionHandler forKey:lineNumber];\n\t}\n\n\t[self.backingView evaluateFunction:@\"Textual.jumpToLine\" withArguments:@[lineNumber]];\n}\n\n- (void)notifyDidBecomeVisible /* When the view is switched to */\n{\n\t[self _evaluateFunction:@\"_Textual.notifyDidBecomeVisible\" withArguments:nil];\n\n\t[self maybeReloadHistory];\n\n\t[self.backingView restoreScrollerPosition];\n\n\t[self.backingView enableOffScreenUpdates];\n\n\t[self.backingView redrawViewIfNeeded];\n}\n\n- (void)notifySelectionChanged\n{\n\t[self _evaluateFunction:@\"_Textual.notifySelectionChanged\" withArguments:@[@(self.selected)]];\n}\n\n- (void)notifyDidBecomeHidden\n{\n\t[self _evaluateFunction:@\"_Textual.notifyDidBecomeHidden\" withArguments:nil];\n\n\t[self.backingView saveScrollerPosition];\n\n\t[self.backingView disableOffScreenUpdates];\n}\n\n- (void)notifyViewFinishedLoadingHistory\n{\n\t[self _evaluateFunction:@\"_Textual.viewFinishedLoadingHistory\" withArguments:nil];\n}\n\n- (void)changeTextSize:(BOOL)bigger\n{\n\tdouble sizeMultiplier = self.attachedWindow.textSizeMultiplier;\n\n\t[self _evaluateFunction:@\"Textual.changeTextSizeMultiplier\" withArguments:@[@(sizeMultiplier)]];\n\n\t[self _evaluateFunction:@\"Textual.viewFontSizeChanged\" withArguments:@[@(bigger)]];\n}\n\n- (void)changeScrollbackLimit\n{\n\tNSUInteger scrollbackLimit = [TPCPreferences scrollbackVisibleLimit];\n\n\t[self _evaluateFunction:@\"_MessageBuffer.setBufferLimit\" withArguments:@[@(scrollbackLimit)]];\n}\n\n#pragma mark -\n#pragma mark Plugins\n\n- (void)notifyJumpToLine:(NSString *)lineNumber successful:(BOOL)successful scrolledToBottom:(BOOL)scrolledToBottom\n{\n\tNSParameterAssert(lineNumber != nil);\n\n\t/* The Objective-C based automatic scroller relies on notifications of\n\t bounds and frame changes to know when a WebView scrolls. If the WebView\n\t is offscreen, then we have no way to know when a jump occurs because\n\t these notifications are not received. To workaround this, the JavaScript\n\t passes the scrolledToBottom argument. The Objective-C automatic scroller\n\t can then be passed this argument to know whether to perform automatic\n\t scrolling when the view becomes visible. */\n\tif (successful) {\n\t\t[self.backingView resetScrollerPositionTo:scrolledToBottom];\n\t}\n\n\tvoid (^callbackHandler)(BOOL) = [self.jumpToLineCallbacks objectForKey:lineNumber];\n\n\tif (callbackHandler == nil) {\n\t\treturn;\n\t}\n\n\t/* Remove callback handler first incase the callback handler\n\t tries to jump to same line number again for some reason. */\n\t[self.jumpToLineCallbacks removeObjectForKey:lineNumber];\n\n\tcallbackHandler(successful);\n}\n\n- (void)notifyLinesAddedToView:(NSArray<NSString *> *)lineNumbers\n{\n\tNSParameterAssert(lineNumbers != nil);\n\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn;\n\t}\n\n\tself.activeLineCount += lineNumbers.count;\n\n\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureNewMessagePostedEvent] == NO) {\n\t\treturn;\n\t}\n\n\tfor (NSString *lineNumber in lineNumbers) {\n\t\t[THOPluginDispatcher dequeueDidPostNewMessageWithLineNumber:lineNumber forViewController:self];\n\t}\n}\n\n- (void)notifyLinesRemovedFromView:(NSArray<NSString *> *)lineNumbers\n{\n\tNSParameterAssert(lineNumbers != nil);\n\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn;\n\t}\n\n\tself.activeLineCount -= lineNumbers.count;\n}\n\n- (void)notifyHistoricLogWillDeleteLines:(NSArray<NSString *> *)lineNumbers\n{\n\tNSParameterAssert(lineNumbers != nil);\n\n\t/* It is possible for this method to be invoked before loaded is YES\n\t such as when performing a clear. */\n\tif (/* self.loaded == NO || */ self.terminating) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.highlightedLineNumbers) {\n\t\t[self.highlightedLineNumbers removeObjectsInArray:lineNumbers];\n\t}\n}\n\n#pragma mark -\n#pragma mark Inline Media\n\n- (void)processingInlineMediaPayloadSucceeded:(ICLPayload *)payload\n{\n\t[self _evaluateFunction:@\"_InlineMediaLoader.processPayload\" withArguments:@[payload.javaScriptObject]];\n}\n\n- (void)processingInlineMediaPayload:(ICLPayload *)payload failedWithError:(NSError *)error\n{\n\tLogToConsoleError(\"Processing request for '%{public}@' at '%{public}@' failed with error: %{public}@\",\n\t\tpayload.uniqueIdentifier, payload.lineNumber, error.localizedDescription);\n}\n\n- (void)processInlineMedia:(NSArray<AHHyperlinkScannerResult *> *)mediaLinks atLineNumber:(NSString *)lineNumber\n{\n\tNSParameterAssert(mediaLinks != nil);\n\tNSParameterAssert(lineNumber != nil);\n\n\tif (mediaLinks.count == 0) {\n\t\treturn;\n\t}\n\n\t/* Unique list */\n\tNSMutableArray<NSString *> *linksMatched = [NSMutableArray array];\n\n\tNSMutableArray<AHHyperlinkScannerResult *> *linksToProcess = [NSMutableArray array];\n\n\tfor (AHHyperlinkScannerResult *link in mediaLinks) {\n\t\tif ([linksMatched containsObject:link.stringValue]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[linksToProcess addObject:link];\n\t}\n\n\t[linksToProcess enumerateObjectsUsingBlock:^(AHHyperlinkScannerResult *link, NSUInteger index, BOOL *stop) {\n\t\t[self processInlineMediaAtAddress:link.stringValue\n\t\t\t\t\t withUniqueIdentifier:link.uniqueIdentifier\n\t\t\t\t\t\t\t atLineNumber:lineNumber\n\t\t\t\t\t\t\t\t\tindex:index];\n\t}];\n}\n\n- (void)processInlineMediaAtAddress:(NSString *)address withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index\n{\n\tNSParameterAssert(address != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(lineNumber != nil);\n\n\tIRCTreeItem *associatedItem = self.associatedItem;\n\n\t[TVCLogControllerInlineMediaSharedInstance()\n\t\t\t processAddress:address\n\t   withUniqueIdentifier:uniqueIdentifier\n\t\t\t   atLineNumber:lineNumber\n\t\t\t\t\t  index:index\n\t\t\t\t\tforItem:associatedItem];\n}\n\n#pragma mark -\n#pragma mark Manage Highlights\n\n- (NSUInteger)numberOfLines\n{\n\treturn self.activeLineCount;\n}\n\n- (BOOL)highlightAvailable:(BOOL)previous\n{\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn NO;\n\t}\n\n\t@synchronized(self.highlightedLineNumbers) {\n\t\treturn (self.highlightedLineNumbers.count > 0);\n\t}\n}\n\n- (void)nextHighlight\n{\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.highlightedLineNumbers) {\n\t\tif (self.highlightedLineNumbers.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ([self.highlightedLineNumbers containsObject:self.lastVisitedHighlight]) {\n\t\t\tNSUInteger hli_ci = [self.highlightedLineNumbers indexOfObject:self.lastVisitedHighlight];\n\n\t\t\tif (hli_ci == (self.highlightedLineNumbers.count - 1)) {\n\t\t\t\t/* Circle around back to the beginning of the list. */\n\t\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[0];\n\t\t\t} else {\n\t\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[(hli_ci + 1)];\n\t\t\t}\n\t\t} else {\n\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[0];\n\t\t}\n\n\t\t[self jumpToLine:self.lastVisitedHighlight];\n\t}\n}\n\n- (void)previousHighlight\n{\n\tif (self.loaded == NO || self.terminating) {\n\t\treturn;\n\t}\n\n\t@synchronized(self.highlightedLineNumbers) {\n\t\tif (self.highlightedLineNumbers.count == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ([self.highlightedLineNumbers containsObject:self.lastVisitedHighlight]) {\n\t\t\tNSInteger hli_ci = [self.highlightedLineNumbers indexOfObject:self.lastVisitedHighlight];\n\n\t\t\tif (hli_ci == 0) {\n\t\t\t\t/* Circle around back to the end of the list. */\n\t\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[(self.highlightedLineNumbers.count - 1)];\n\t\t\t} else {\n\t\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[(hli_ci - 1)];\n\t\t\t}\n\t\t} else {\n\t\t\tself.lastVisitedHighlight = self.highlightedLineNumbers[0];\n\t\t}\n\n\t\t[self jumpToLine:self.lastVisitedHighlight];\n\t}\n}\n\n- (void)clearWithReset:(BOOL)clearWithReset\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\t[self.printingQueue cancelOperationsForViewController:self];\n\n\tif (clearWithReset) {\n\t\t[self historicLogResetChannel];\n\t}\n\n\t@synchronized(self.highlightedLineNumbers) {\n\t\t[self.highlightedLineNumbers removeAllObjects];\n\t}\n\n\tself.activeLineCount = 0;\n\n\tself.lastVisitedHighlight = nil;\n\n\tself.oldestLineNumber = nil;\n\tself.newestLineNumber = nil;\n\n\tself.lastLine = nil;\n\n\tself.loaded = NO;\n\n\tself.reloadingHistory = NO;\n\n\tself.historyLoaded = NO;\n\n\tif (self.backingView.isUsingWebKit2 != [TVCLogView webKit2Enabled]) {\n\t\t[self rebuildBackingView];\n\t}\n\n\t[self loadInitialDocument];\n}\n\n- (void)clear\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\t[self clearWithReset:YES];\n}\n\n- (void)clearBackingView\n{\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\t[self clearWithReset:YES];\n}\n\n#pragma mark -\n#pragma mark History\n\n- (void)renderLogLinesBeforeLineNumber:(NSString *)lineNumber maximumNumberOfLines:(NSUInteger)maximumNumberOfLines completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock\n{\n\t[self _renderLogLinesAfter:NO lineNumber:lineNumber maximumNumberOfLines:maximumNumberOfLines completionBlock:completionBlock];\n}\n\n- (void)renderLogLinesAfterLineNumber:(NSString *)lineNumber maximumNumberOfLines:(NSUInteger)maximumNumberOfLines completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock\n{\n\t[self _renderLogLinesAfter:YES lineNumber:lineNumber maximumNumberOfLines:maximumNumberOfLines completionBlock:completionBlock];\n}\n\n- (void)_renderLogLinesAfter:(BOOL)after lineNumber:(NSString *)lineNumber maximumNumberOfLines:(NSUInteger)maximumNumberOfLines completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock\n{\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(maximumNumberOfLines > 0);\n\tNSParameterAssert(completionBlock != nil);\n\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tvoid (^historicLogCompletionBlock)(NSArray *) = ^(NSArray<TVCLogLine *> *entries) {\n\t\t\tif ([operation isCancelled]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self _renderLogLinesAfterLineNumberPostFlight:entries completionBlock:completionBlock];\n\t\t};\n\n\t\tif (after == NO) {\n\t\t\t[TVCLogControllerHistoricLogSharedInstance()\n\t\t\t fetchEntriesForItem:self.associatedItem\n\t\t  beforeUniqueIdentifier:lineNumber\n\t\t\t\t\t  fetchLimit:maximumNumberOfLines\n\t\t\t\t\t limitToDate:nil\n\t\t\t withCompletionBlock:historicLogCompletionBlock];\n\t\t} else {\n\t\t\t[TVCLogControllerHistoricLogSharedInstance()\n\t\t\t fetchEntriesForItem:self.associatedItem\n\t\t   afterUniqueIdentifier:lineNumber\n\t\t\t\t\t  fetchLimit:maximumNumberOfLines\n\t\t\t\t\t limitToDate:nil\n\t\t\t withCompletionBlock:historicLogCompletionBlock];\n\t\t}\n\t};\n\n\t_enqueueBlockStandalone(operationBlock)\n}\n\n- (void)renderLogLinesAfterLineNumber:(NSString *)lineNumberAfter beforeLineNumber:(NSString *)lineNumberBefore maximumNumberOfLines:(NSUInteger)maximumNumberOfLines completionBlock:(void (^)(NSArray<NSDictionary<NSString *,id> *> * _Nonnull))completionBlock\n{\n\tNSParameterAssert(lineNumberAfter != nil);\n\tNSParameterAssert(lineNumberBefore != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tvoid (^historicLogCompletionBlock)(NSArray *) = ^(NSArray<TVCLogLine *> *entries) {\n\t\t\tif ([operation isCancelled]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self _renderLogLinesAfterLineNumberPostFlight:entries completionBlock:completionBlock];\n\t\t};\n\n\t\t[TVCLogControllerHistoricLogSharedInstance()\n\t\t\t fetchEntriesForItem:self.associatedItem\n\t\t   afterUniqueIdentifier:lineNumberAfter\n\t\t  beforeUniqueIdentifier:lineNumberBefore\n\t\t\t\t\t  fetchLimit:maximumNumberOfLines\n\t\t\t withCompletionBlock:historicLogCompletionBlock];\n\t};\n\n\t_enqueueBlockStandalone(operationBlock)\n}\n\n- (void)renderLogLineAtLineNumber:(NSString *)lineNumber numberOfLinesBefore:(NSUInteger)numberOfLinesBefore numberOfLinesAfter:(NSUInteger)numberOfLinesAfter completionBlock:(void (^)(NSArray<NSDictionary<NSString *,id> *> * _Nonnull))completionBlock\n{\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tTVCLogControllerPrintingBlock operationBlock = ^(id operation) {\n\t\tvoid (^historicLogCompletionBlock)(NSArray *) = ^(NSArray<TVCLogLine *> *entries) {\n\t\t\tif ([operation isCancelled]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self _renderLogLinesAfterLineNumberPostFlight:entries completionBlock:completionBlock];\n\t\t};\n\n\t\t[TVCLogControllerHistoricLogSharedInstance()\n\t\t\t fetchEntriesForItem:self.associatedItem\n\t\t\twithUniqueIdentifier:lineNumber\n\t\t\t\tbeforeFetchLimit:numberOfLinesBefore\n\t\t\t\t afterFetchLimit:numberOfLinesAfter\n\t\t\t\t\t limitToDate:nil\n\t\t\t withCompletionBlock:historicLogCompletionBlock];\n\t};\n\n\t_enqueueBlockStandalone(operationBlock)\n}\n\n- (void)_renderLogLinesAfterLineNumberPostFlight:(NSArray<TVCLogLine *> *)logLines completionBlock:(void (^)(NSArray<NSDictionary<NSString *, id> *> *))completionBlock\n{\n\tNSParameterAssert(logLines != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSMutableArray<NSDictionary<NSString *, id> *> *renderedLogLines = [NSMutableArray arrayWithCapacity:logLines.count];\n\n\tNSMutableArray<THOPluginDidPostNewMessageConcreteObject *> *pluginObjects = nil;\n\n\tfor (TVCLogLine *logLine in logLines) {\n\t\t/* Render result info HTML */\n\t\tNSDictionary<NSString *, id> *resultInfo = nil;\n\n\t\tNSString *html = [self renderLogLine:logLine resultInfo:&resultInfo];\n\n\t\tif (html == nil) {\n\t\t\tLogToConsoleError(\"Failed to render log line %{public}@\", logLine.description);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Record information about rendering */\n\t\tNSString *lineNumber = logLine.uniqueIdentifier;\n\n\t\t[renderedLogLines addObject:@{\n\t\t\t@\"lineNumber\" : lineNumber,\n\t\t\t@\"html\" : html,\n\t\t\t@\"timestamp\" : @(logLine.receivedAt.timeIntervalSince1970)\n\t\t}];\n\n\t\t/* Add reference to plugin concrete object */\n\t\tTHOPluginDidPostNewMessageConcreteObject *pluginObject = resultInfo[@\"pluginConcreteObject\"];\n\n\t\tif (pluginObject) {\n\t\t\tif (pluginObjects == nil) {\n\t\t\t\tpluginObjects = [NSMutableArray array];\n\t\t\t}\n\n\t\t\t[pluginObjects addObject:pluginObject];\n\t\t}\n\t}\n\n\t/* Inform plugins of new content */\n\tfor (THOPluginDidPostNewMessageConcreteObject *pluginObject in pluginObjects) {\n\t\tpluginObject.isProcessedInBulk = YES;\n\n\t\t[THOPluginDispatcher enqueueDidPostNewMessage:pluginObject];\n\t}\n\n\t/* Finish */\n\tcompletionBlock([renderedLogLines copy]);\n}\n\n#pragma mark -\n#pragma mark Print\n\n- (void)print:(TVCLogLine *)logLine\n{\n\t[self print:logLine completionBlock:NULL];\n}\n\n- (void)print:(TVCLogLine *)logLine completionBlock:(nullable TVCLogControllerPrintOperationCompletionBlock)completionBlock\n{\n\tNSParameterAssert(logLine != nil);\n\n\tif (self.terminating) {\n\t\treturn;\n\t}\n\n\tif ([logLine isKindOfClass:[TVCLogLineMutable class]]) {\n\t\tlogLine = [logLine copy];\n\t}\n\n\tself.lastLine = logLine;\n\n\tTVCLogControllerPrintingBlock printBlock = ^(id operation) {\n\t\tNSDictionary<NSString *, id> *resultInfo = nil;\n\n\t\tNSString *html = [self renderLogLine:logLine resultInfo:&resultInfo];\n\n\t\tif (html == nil) {\n\t\t\tLogToConsoleError(\"Failed to render log line %{public}@\", logLine.description);\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSString *lineNumber = logLine.uniqueIdentifier;\n\n\t\tNSSet<IRCChannelUser *> *listOfUsers = resultInfo[TVCLogRendererResultsListOfUsersFoundAttribute];\n\n\t\tBOOL processInlineMedia = [resultInfo boolForKey:@\"processInlineMedia\"];\n\n\t\tBOOL highlighted = [resultInfo boolForKey:TVCLogRendererResultsKeywordMatchFoundAttribute];\n\n\t\tTHOPluginDidPostNewMessageConcreteObject *pluginObject = resultInfo[@\"pluginConcreteObject\"];\n\n\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\tif (self.terminating) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (self.oldestLineNumber == nil) {\n\t\t\t\tself.oldestLineNumber = lineNumber;\n\t\t\t}\n\n\t\t\tself.newestLineNumber = lineNumber;\n\n\t\t\tIRCClient *client = self.associatedClient;\n\t\t\tIRCChannel *channel = self.associatedChannel;\n\n\t\t\tif (highlighted) {\n\t\t\t\t@synchronized(self.highlightedLineNumbers) {\n\t\t\t\t\t[self.highlightedLineNumbers addObject:lineNumber];\n\t\t\t\t}\n\n\t\t\t\t[client cacheHighlightInChannel:channel withLogLine:logLine];\n\t\t\t}\n\n\t\t\tif (pluginObject) {\n\t\t\t\t[THOPluginDispatcher enqueueDidPostNewMessage:resultInfo[@\"pluginConcreteObject\"]];\n\t\t\t}\n\n\t\t\t[self appendToDocumentBody:html withLineNumbers:@[lineNumber]];\n\n\t\t\t/* TODO: Modify logic of inline media to only truly\n\t\t\t process images if the line is in fact on the WebView. */\n\t\t\t/* Begin processing inline media */\n\t\t\t/* We go through the inline media list here and pass to the loader now so\n\t\t\t that we know the links have hit the WebView before we even try loading them. */\n\t\t\tif (processInlineMedia) {\n\t\t\t\tNSArray<AHHyperlinkScannerResult *> *listOfLinks = resultInfo[TVCLogRendererResultsListOfLinksInBodyAttribute];\n\n\t\t\t\t[self processInlineMedia:listOfLinks atLineNumber:lineNumber];\n\t\t\t}\n\n\t\t\t/* Log this log line */\n\t\t\t/* If the channel is encrypted, then we refuse to write to\n\t\t\t the actual historic log so there is no trace of the chatter\n\t\t\t on the disk in the form of an unencrypted cache file. */\n\t\t\t/* Doing it this way does break the ability to reload chatter\n\t\t\t in the view as well as playback on restart, but the added\n\t\t\t security can be seen as a bonus. */\n\t\t\tif (self.encrypted == NO) {\n\t\t\t\t[TVCLogControllerHistoricLogSharedInstance() writeNewEntryWithLogLine:logLine forItem:self.associatedItem];\n\t\t\t}\n\n\t\t\t/* Redraw view if needed */\n\t\t\t[self.backingView redrawViewIfNeeded];\n\n\t\t\t/* Using information provided by conversation tracking we can update \n\t\t\t our internal array of favored nicknames for nick completion. */\n\t\t\tif (logLine.memberType == TVCLogLineMemberTypeLocalUser) {\n\t\t\t\t[listOfUsers.allObjects makeObjectsPerformSelector:@selector(outgoingConversation)];\n\t\t\t} else {\n\t\t\t\t[listOfUsers.allObjects makeObjectsPerformSelector:@selector(conversation)];\n\t\t\t}\n\n\t\t\tif (completionBlock == nil) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t TVCLogControllerPrintOperationContext *contextObject =\n\t\t\t[TVCLogControllerPrintOperationContext new];\n\n\t\t\tcontextObject.client = client;\n\t\t\tcontextObject.channel = channel;\n\t\t\tcontextObject.highlight = highlighted;\n\t\t\tcontextObject.logLine = logLine;\n\t\t\tcontextObject.lineNumber = lineNumber;\n\n\t\t\tcompletionBlock(contextObject);\n\t\t});\n\t};\n\n\t_enqueueBlock(printBlock)\n}\n\n- (nullable NSString *)renderLogLine:(TVCLogLine *)logLine resultInfo:(NSDictionary<NSString *, id> ** _Nullable)resultInfo\n{\n\tNSParameterAssert(logLine != nil);\n\n\t// ************************************************************************** /\n\n\tTVCLogLineType lineType = logLine.lineType;\n\n\tNSString *lineTypeString = logLine.lineTypeString;\n\n\tBOOL renderLinks = ([[TLOLinkParser bannedLineTypes] containsObject:lineTypeString] == NO);\n\n\tNSMutableDictionary<NSString *, id> *rendererAttributes = [NSMutableDictionary dictionary];\n\n\tif (logLine.rendererAttributes != nil) {\n\t\t[rendererAttributes addEntriesFromDictionary:logLine.rendererAttributes];\n\t}\n\n\t[rendererAttributes maybeSetObject:logLine.excludeKeywords forKey:TVCLogRendererConfigurationExcludedKeywordsAttribute];\n\t[rendererAttributes maybeSetObject:logLine.highlightKeywords forKey:TVCLogRendererConfigurationHighlightKeywordsAttribute];\n\n\t[rendererAttributes setBool:renderLinks forKey:TVCLogRendererConfigurationRenderLinksAttribute];\n\n\t[rendererAttributes setUnsignedInteger:logLine.lineType forKey:TVCLogRendererConfigurationLineTypeAttribute];\n\t[rendererAttributes setUnsignedInteger:logLine.memberType forKey:TVCLogRendererConfigurationMemberTypeAttribute];\n\n\tNSDictionary<NSString *, id> *rendererResults = nil;\n\n\tNSString *renderedBody =\n\t[TVCLogRenderer renderBody:logLine.messageBody\n\t\t\t forViewController:self\n\t\t\t\twithAttributes:rendererAttributes\n\t\t\t\t\tresultInfo:&rendererResults];\n\n\tif (renderedBody == nil) {\n\t\treturn nil;\n\t}\n\n\tNSMutableDictionary<NSString *, id> *resultInfoTemp = nil;\n\n\tif (resultInfo) {\n\t\tresultInfoTemp = [rendererResults mutableCopy];\n\t}\n\n\tBOOL highlighted = [rendererResults boolForKey:TVCLogRendererResultsKeywordMatchFoundAttribute];\n\n\tBOOL inlineMedia =\n\t\t(self.inlineMediaEnabledForView &&\n\t\t (lineType == TVCLogLineTypePrivateMessage || lineType == TVCLogLineTypeAction));\n\n\tNSString *lineNumber = logLine.uniqueIdentifier;\n\n\tNSDate *receivedAt = logLine.receivedAt;\n\n\t// ************************************************************************** /\n\n\tNSMutableDictionary<NSString *, id> *pathAttributes = [NSMutableDictionary new];\n\n\tpathAttributes[@\"activeStyleAbsolutePath\"] = self.baseURL.path;\n\n\tpathAttributes[@\"applicationResourcePath\"] = [TPCPathInfo applicationResources];\n\n\tNSMutableDictionary<NSString *, id> *templateAttributes = [pathAttributes mutableCopy];\n\n\t// ---- //\n\n\ttemplateAttributes[@\"timestamp\"] = @(receivedAt.timeIntervalSince1970);\n\n\ttemplateAttributes[@\"formattedTimestamp\"] = logLine.formattedTimestamp;\n\n\ttemplateAttributes[@\"localizedTimestamp\"] = TXFormatDateLongStyle(receivedAt, NO);\n\n\t// ---- //\n\n\tNSString *nickname = [logLine formattedNicknameInChannel:self.associatedChannel];\n\n\tif (nickname.length == 0) {\n\t\ttemplateAttributes[@\"isNicknameAvailable\"] = @(NO);\n\t} else {\n\t\ttemplateAttributes[@\"isNicknameAvailable\"] = @(YES);\n\n\t\ttemplateAttributes[@\"nicknameColorStyle\"] = logLine.nicknameColorStyle;\n\t\ttemplateAttributes[@\"nicknameColorStyleOverride\"] = @(logLine.nicknameColorStyleOverride);\n\n\t\ttemplateAttributes[@\"nicknameColorHashingEnabled\"] = @([TPCPreferences disableNicknameColorHashing] == NO);\n\n\t\ttemplateAttributes[@\"formattedNickname\"] = nickname.trim;\n\n\t\ttemplateAttributes[@\"nickname\"]\t= logLine.nickname;\n\t\ttemplateAttributes[@\"nicknameType\"]\t= logLine.memberTypeString;\n\t}\n\n\t// ---- //\n\n\ttemplateAttributes[@\"lineType\"] = lineTypeString;\n\n\ttemplateAttributes[@\"command\"] = logLine.command;\n\ttemplateAttributes[@\"rawCommand\"] = logLine.command; // Legacy key\n\n\t// ---- //\n\n\tNSString *classAttribute = nil;\n\n\tif (lineType == TVCLogLineTypePrivateMessage || lineType == TVCLogLineTypeAction || lineType == TVCLogLineTypeNotice) {\n\t\tclassAttribute = @\"text\";\n\t} else {\n\t\tclassAttribute = @\"event\";\n\t}\n\n\ttemplateAttributes[@\"lineClassAttribute\"] = classAttribute;\n\n\t// ---- //\n\n\tif (highlighted) {\n\t\ttemplateAttributes[@\"highlightAttribute\"] = @\"true\";\n\t} else {\n\t\ttemplateAttributes[@\"highlightAttribute\"] = @\"false\";\n\t}\n\n\t// ---- //\n\n\ttemplateAttributes[@\"message\"] = logLine.messageBody;\n\n\ttemplateAttributes[@\"formattedMessage\"]\t= renderedBody;\n\n\ttemplateAttributes[@\"isHighlight\"] = @(highlighted);\n\n\ttemplateAttributes[@\"isRemoteMessage\"] = @(logLine.memberType == TVCLogLineMemberTypeNormal);\n\n\t// ---- //\n\n\tif (logLine.isEncrypted) {\n\t\ttemplateAttributes[@\"isEncrypted\"] = @(YES);\n\t}\n\n\t// ---- //\n\n\tNSString *serverName = self.associatedClient.networkNameAlt;\n\n\tif (serverName) {\n\t\ttemplateAttributes[@\"configuredServerName\"] = serverName;\n\t}\n\n\t// ---- //\n\n\ttemplateAttributes[@\"inlineMediaEnabled\"] = @(inlineMedia);\n\n\ttemplateAttributes[@\"lineNumber\"] = lineNumber;\n\n\ttemplateAttributes[@\"lineRenderTime\"] = @([NSDate timeIntervalSince1970]);\n\n\t// ---- //\n\n\tif (logLine.isFirstForDay && [TPCPreferences showDateChanges]) {\n\t\ttemplateAttributes[@\"showDateIndicator\"] = @(YES);\n\n\t\ttemplateAttributes[@\"dateIndicatorMessage\"] = [self dateIndicatorWithDate:receivedAt];\n\t}\n\n\tif ([lineNumber isEqualToString:self.newestLineNumberFromPreviousSession]) {\n\t\ttemplateAttributes[@\"showSessionIndicator\"] = @(YES);\n\n\t\ttemplateAttributes[@\"sessionIndicatorMessage\"] = TXTLS(@\"TVCMainWindow[4yo-mk]\");\n\t}\n\n\t// ************************************************************************** /\n\n\tif (resultInfoTemp) {\n\t\tresultInfoTemp[@\"processInlineMedia\"] = @(inlineMedia);\n\n\t\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureNewMessagePostedEvent]) {\n\t\t\tNSArray<AHHyperlinkScannerResult *> *listOfLinks = rendererResults[TVCLogRendererResultsListOfLinksInBodyAttribute];\n\n\t\t\t THOPluginDidPostNewMessageConcreteObject *pluginConcreteObject =\n\t\t\t[THOPluginDidPostNewMessageConcreteObject new];\n\n\t\t\tpluginConcreteObject.keywordMatchFound = highlighted;\n\n\t\t\tpluginConcreteObject.lineType = lineType;\n\t\t\tpluginConcreteObject.memberType = logLine.memberType;\n\n\t\t\tpluginConcreteObject.senderNickname = logLine.nickname;\n\n\t\t\tpluginConcreteObject.receivedAt = receivedAt;\n\n\t\t\tpluginConcreteObject.lineNumber = lineNumber;\n\n\t\t\tpluginConcreteObject.messageContents = rendererResults[TVCLogRendererResultsOriginalBodyWithoutEffectsAttribute];\n\n\t\t\tpluginConcreteObject.listOfHyperlinks = listOfLinks;\n\n\t\t\tpluginConcreteObject.listOfUsers = rendererResults[TVCLogRendererResultsListOfUsersFoundAttribute];\n\n\t\t\tresultInfoTemp[@\"pluginConcreteObject\"] = pluginConcreteObject;\n\t\t}\n\t}\n\n\t// ************************************************************************** /\n\n\tif ( resultInfo) {\n\t\t*resultInfo = [resultInfoTemp copy];\n\t}\n\n\t// ************************************************************************** /\n\n\tGRMustacheTemplate *template = [theme() templateWithLineType:lineType];\n\n\tNSString *html = [TVCLogRenderer renderTemplate:template attributes:templateAttributes];\n\n\treturn html;\n}\n\n#pragma mark -\n#pragma mark Initial Document\n\n- (BOOL)usesCustomScrollers\n{\n\tNSScrollerStyle preferredScrollerStyle = [NSScroller preferredScrollerStyle];\n\n\tBOOL onlyShowDuringScrolling = (preferredScrollerStyle == NSScrollerStyleOverlay);\n\n\tBOOL usesCustomScrollers = [TPCPreferences themeChannelViewUsesCustomScrollers];\n\n\tBOOL usingWebKit2 = self.backingView.isUsingWebKit2;\n\n\treturn (onlyShowDuringScrolling == NO && usesCustomScrollers && usingWebKit2);\n}\n\n- (NSString *)initialDocument\n{\n\tNSMutableDictionary *templateTokens = [self generateOverrideStyle];\n\n\ttemplateTokens[@\"applicationResourcePath\"] = [TPCPathInfo applicationResources];\n\n\ttemplateTokens[@\"applicationTemplatesPath\"] = theme().applicationTemplateRepositoryPath;\n\n\ttemplateTokens[@\"activeStyleAbsolutePath\"] = self.baseURL.path;\n\n\ttemplateTokens[@\"activeStyleCSSFiles\"] = theme().temporaryCSSFilePaths;\n\ttemplateTokens[@\"activeStyleJSFiles\"] = theme().temporaryJSFilePaths;\n\n\ttemplateTokens[@\"cacheToken\"] = themeController().cacheToken;\n\n\ttemplateTokens[@\"configuredServerName\"] = self.associatedClient.networkNameAlt;\n\n\ttemplateTokens[@\"isReloadingStyle\"] = @(self.reloadingTheme);\n\n\ttemplateTokens[@\"operatingSystemVersion\"] = [XRSystemInformation systemStandardVersion];\n\n\tTVCMainWindowAppearance *appearance = self.attachedWindow.userInterfaceObjects;\n\n\ttemplateTokens[@\"appearanceDescription\"] = appearance.shortAppearanceDescription;\n\ttemplateTokens[@\"sidebarInversionIsEnabled\"] = @(appearance.isDarkAppearance);\n\n\ttemplateTokens[@\"userConfiguredTextEncoding\"] = [NSString charsetRepFromStringEncoding:self.associatedClient.config.primaryEncoding];\n\n\ttemplateTokens[@\"userStyleSheetRules\"] = [TPCPreferences themeUserStyleSheetRules];\n\n\ttemplateTokens[@\"usesCustomScrollers\"] = @([self usesCustomScrollers]);\n\n\tIRCChannel *channel = self.associatedChannel;\n\n\tif (channel) {\n\t\ttemplateTokens[@\"isChannelView\"] = @(channel.isChannel);\n\t\ttemplateTokens[@\"isPrivateMessageView\"] = @(channel.isPrivateMessage);\n\t\ttemplateTokens[@\"isUtilityView\"] = @(channel.isUtility);\n\n\t\ttemplateTokens[@\"channelName\"] = channel.name;\n\n\t\ttemplateTokens[@\"viewTypeToken\"] = channel.channelTypeString;\n\t} else {\n\t\ttemplateTokens[@\"viewTypeToken\"] = @\"server\";\n\t}\n\n\tif ([TPCPreferences rightToLeftFormatting]) {\n\t\ttemplateTokens[@\"textDirectionToken\"] = @\"rtl\";\n\t} else {\n\t\ttemplateTokens[@\"textDirectionToken\"] = @\"ltr\";\n\t}\n\n\tif ([themeSettings() underlyingWindowColorIsDark]) {\n\t\ttemplateTokens[@\"appearanceToken\"] = @\"dark\";\n\t} else {\n\t\ttemplateTokens[@\"appearanceToken\"] = @\"light\";\n\t}\n\n\treturn [TVCLogRenderer renderTemplateNamed:@\"baseLayout\" attributes:templateTokens];\n}\n\n- (NSMutableDictionary<NSString *, id> *)generateOverrideStyle\n{\n\tNSMutableDictionary<NSString *, id> *templateTokens = [NSMutableDictionary dictionary];\n\n\t// ---- //\n\n\tNSFont *channelFont = themeSettings().themeChannelViewFont;\n\n\tif (channelFont == nil) {\n\t\tchannelFont = [TPCPreferences themeChannelViewFont];\n\t}\n\n\ttemplateTokens[@\"userConfiguredFontName\"] =   channelFont.fontName;\n\ttemplateTokens[@\"userConfiguredFontSize\"] = @(channelFont.pointSize * (72.0 / 96.0));\n\n\t// ---- //\n\n\tdouble indentOffset = themeSettings().indentationOffset;\n\n\tif (round(indentOffset) < 0.0 || [TPCPreferences rightToLeftFormatting]) {\n\t\ttemplateTokens[@\"nicknameIndentationAvailable\"] = @(NO);\n\t} else {\n\t\ttemplateTokens[@\"nicknameIndentationAvailable\"] = @(YES);\n\n\t\tNSString *timeFormat = themeSettings().themeTimestampFormat;\n\n\t\tif (timeFormat == nil) {\n\t\t\ttimeFormat = [TPCPreferences themeTimestampFormat];\n\t\t}\n\n\t\tNSString *time = TXFormattedTimestamp([NSDate date], timeFormat);\n\n\t\tNSSize textSize = [time sizeWithAttributes:@{NSFontAttributeName : channelFont}];\n\n\t\ttemplateTokens[@\"predefinedTimestampWidth\"] = @(textSize.width + indentOffset);\n\t}\n\n\t// ---- //\n\n\treturn templateTokens;\n}\n\n#pragma mark -\n#pragma mark LogView Delegate\n\n- (void)logViewWebViewFinishedLoading\n{\n\tif (self.loaded == NO) {\n\t\tself.loaded = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\tself.viewLoadedTimestamp = [NSDate timeIntervalSince1970];\n\n\tIRCChannel *channel = self.associatedChannel;\n\n\tNSString *viewType = nil;\n\n\tif (channel) {\n\t\tviewType = channel.channelTypeString;\n\t} else {\n\t\tviewType = @\"server\";\n\t}\n\n\t[self _evaluateFunction:@\"Textual.viewInitiated\" withArguments:@[\n\t\t NSDictionaryNilValue(viewType),\n\t\t NSDictionaryNilValue(self.associatedClient.uniqueIdentifier),\n\t\t NSDictionaryNilValue(channel.uniqueIdentifier),\n\t\t NSDictionaryNilValue(channel.name)\n\t]];\n\n\tdouble textSizeMultiplier = self.attachedWindow.textSizeMultiplier;\n\n\tNSUInteger scrollbackLimit = [TPCPreferences scrollbackVisibleLimit];\n\n\t[self _evaluateFunction:@\"_Textual.viewFinishedLoading\"\n\t\t\t  withArguments:\n\t @[\n\t\t  @{\n\t\t\t  @\"selected\" : @(self.selected),\n\t\t\t  @\"visible\" : @(self.visible),\n\t\t\t  @\"reloadingTheme\" : @(self.reloadingTheme), // TODO: Fix this always being false\n\t\t\t  @\"textSizeMultiplier\" : @(textSizeMultiplier),\n\t\t\t  @\"scrollbackLimit\" : @(scrollbackLimit)\n\t\t  }\n\t  ]];\n\n\t[self setInitialTopic];\n\n\t[self reloadHistory];\n\n\t[RZNotificationCenter() postNotificationName:TVCLogControllerViewFinishedLoadingNotification object:self];\n\n\t[self.printingQueue updateReadinessState:self];\n}\n\n- (void)logViewWebViewClosedUnexpectedly\n{\n\t[self clearBackingView];\n}\n\n- (void)logViewWebViewKeyDown:(NSEvent *)e\n{\n\t[self.attachedWindow redirectKeyDown:e];\n}\n\n- (void)logViewWebViewReceivedDropWithFile:(NSString *)filename\n{\n\t[menuController() memberSendDroppedFilesToSelectedChannel:@[filename]];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogControllerPrintOperationContext\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogLine.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"TXGlobalModels.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"TLOFileLoggerPrivate.h\"\n#import \"TVCLogLineInternal.h\"\n#import \"TVCLogLineXPCPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TVCLogLineUndefinedNicknameFormat = @\"<%@%n>\";\nNSString * const TVCLogLineActionNicknameFormat\t= @\"%@ \";\nNSString * const TVCLogLineNoticeNicknameFormat\t= @\"-%@-\";\n\nNSString * const TVCLogLineSpecialNoticeMessageFormat = @\"[%@]: %@\";\n\nNSString * const TVCLogLineDefaultCommandValue = @\"-100\";\n\n@interface TVCLogLine ()\n@property (readonly, copy) NSDictionary<NSString *, id> *dictionaryValue;\n@end\n\n@implementation TVCLogLine\n\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_END\n\n- (nullable instancetype)initWithData:(NSData *)data\n{\n\tNSParameterAssert(data != nil);\n\n\tif ((self = [super init])) {\n\t\treturn [NSKeyedUnarchiver unarchiveObjectWithData:data];\n\t}\n\n\treturn nil;\n}\n\n+ (TVCLogLine *)logLineFromXPCObject:(TVCLogLineXPC *)xpcObject\n{\n\tNSParameterAssert(xpcObject != nil);\n\n\t/* In earlier versions of the historic log database, the unique identifier was\n\t not stored in the archived data of the log line. We need a unique identifier now,\n\t which the database automatically creates if none is present, but it does it without\n\t unarchiving the data because the process does not have this class. It therefore just\n\t attaches the unique identifier to the XPC object. We can then write it out here. */\n\t/* We check if the object's unique identifier is nil before setting the database's\n\t value because the value may have already been unarchived if it is present. */\n\tTVCLogLine *object = [NSKeyedUnarchiver unarchiveObjectWithData:xpcObject.data];\n\n\tif (object->_uniqueIdentifier == nil) {\n\t\tobject->_uniqueIdentifier = [xpcObject.uniqueIdentifier copy];\n\t}\n\n\treturn [object copy];\n}\n\n- (BOOL)populateWithDecoder:(NSCoder *)aDecoder\n{\n\tself->_receivedAt = [aDecoder decodeObjectOfClass:[NSDate class] forKey:@\"receivedAt\"];\n\n\tself->_excludeKeywords = [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [NSString class], nil]\n\t\t\t\t\t\t\t\t\t\t\t\t   forKey:@\"excludeKeywords\"];\n\n\tself->_highlightKeywords = [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [NSString class], nil]\n\t\t\t\t\t\t\t\t\t\t\t\t\t forKey:@\"highlightKeywords\"];\n\n\tself->_rendererAttributes = [aDecoder decodeDictionaryForKey:@\"rendererAttributes\"];\n\n\tself->_isEncrypted = [aDecoder decodeBoolForKey:@\"isEncrypted\"];\n\tself->_isFirstForDay = [aDecoder decodeBoolForKey:@\"isFirstForDay\"];\n\n\tself->_command = [aDecoder decodeStringForKey:@\"command\"];\n\tself->_messageBody = [aDecoder decodeStringForKey:@\"messageBody\"];\n\tself->_nickname = [aDecoder decodeStringForKey:@\"nickname\"];\n\n\tself->_lineType = [aDecoder decodeIntegerForKey:@\"lineType\"];\n\tself->_memberType = [aDecoder decodeIntegerForKey:@\"memberType\"];\n\n\tself->_uniqueIdentifier = [aDecoder decodeStringForKey:@\"uniqueIdentifier\"];\n\n\tself->_sessionIdentifier = [aDecoder decodeIntegerForKey:@\"sessionIdentifier\"];\n\n\t[self computeNicknameColorStyle];\n\n\treturn YES;\n}\n\n- (void)populateDefaultsPostflight\n{\n\t[self populateDefaultUniqueIdentifier];\n\t[self populateDefaultSessionIdentifier];\n\n\tSetVariableIfNil(self->_command, TVCLogLineDefaultCommandValue)\n\tSetVariableIfNil(self->_messageBody, @\"\")\n\tSetVariableIfNil(self->_receivedAt, [NSDate date])\n\n\tif (self->_lineType == TVCLogLineTypeActionNoHighlight) {\n\t\tself->_lineType = TVCLogLineTypeAction;\n\n\t\tself->_highlightKeywords = nil;\n\t} else if (self->_lineType == TVCLogLineTypePrivateMessageNoHighlight) {\n\t\tself->_lineType = TVCLogLineTypePrivateMessage;\n\n\t\tself->_highlightKeywords = nil;\n\t}\n}\n\n- (void)populateDefaultUniqueIdentifier\n{\n\tif (self->_uniqueIdentifier != nil) {\n\t\treturn;\n\t}\n\n\tself->_uniqueIdentifier = [self.class newUniqueIdentifier];\n}\n\n- (void)populateDefaultSessionIdentifier\n{\n\tif (self->_sessionIdentifier != 0) {\n\t\treturn;\n\t}\n\n\tself->_sessionIdentifier = [self.class currentSessionIdentifier];\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder\n{\n\t[aCoder encodeObject:self.command forKey:@\"command\"];\n\t[aCoder encodeObject:self.messageBody forKey:@\"messageBody\"];\n\n\t[aCoder maybeEncodeObject:self.excludeKeywords forKey:@\"excludeKeywords\"];\n\t[aCoder maybeEncodeObject:self.highlightKeywords forKey:@\"highlightKeywords\"];\n\t[aCoder maybeEncodeObject:self.rendererAttributes forKey:@\"rendererAttributes\"];\n\t[aCoder maybeEncodeObject:self.nickname forKey:@\"nickname\"];\n\n\t[aCoder encodeBool:self.isEncrypted forKey:@\"isEncrypted\"];\n\t[aCoder encodeBool:self.isFirstForDay forKey:@\"isFirstForDay\"];\n\n\t[aCoder encodeObject:self.receivedAt forKey:@\"receivedAt\"];\n\n\t[aCoder encodeInteger:self.lineType forKey:@\"lineType\"];\n\t[aCoder encodeInteger:self.memberType forKey:@\"memberType\"];\n\n\t[aCoder encodeObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[aCoder encodeInteger:self.sessionIdentifier forKey:@\"sessionIdentifier\"];\n}\n\n+ (BOOL)supportsSecureCoding\n{\n\treturn YES;\n}\n\n- (TVCLogLineXPC *)xpcObjectForTreeItem:(IRCTreeItem *)treeItem\n{\n\tNSParameterAssert(treeItem != nil);\n\n\tNSData *data = [NSKeyedArchiver archivedDataWithRootObject:self];\n\n\tTVCLogLineXPC *xpcObject =\n\t[[TVCLogLineXPC alloc] initWithLogLineData:data\n\t\t\t\t\t\t\t  uniqueIdentifier:self.uniqueIdentifier\n\t\t\t\t\t\t\t\tviewIdentifier:treeItem.uniqueIdentifier\n\t\t\t\t\t\t\t sessionIdentifier:self.sessionIdentifier];\n\n\t return xpcObject;\n}\n\n+ (NSString *)newUniqueIdentifier\n{\n\tNSString *printIdentifier = [NSString stringWithUUID]; // Example: 68753A44-4D6F-1226-9C60-0050E4C00067\n\n\treturn [printIdentifier substringFromIndex:19]; // Example: 9C60-0050E4C00067\n}\n\n+ (NSUInteger)currentSessionIdentifier\n{\n\tstatic NSUInteger sessionIdentifier = 0;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsessionIdentifier = TXRandomNumber(999999);\n\t});\n\n\treturn sessionIdentifier;\n}\n\n- (BOOL)fromCurrentSession\n{\n\treturn (self.sessionIdentifier == [self.class currentSessionIdentifier]);\n}\n\n+ (nullable NSString *)stringForLineType:(TVCLogLineType)type\n{\n#define _dv(lineType, returnValue)\t\t\tcase (lineType): { return (returnValue); break; }\n\n\tswitch (type) {\n\t\t_dv(TVCLogLineTypeAction, @\"action\")\n\t\t_dv(TVCLogLineTypeActionNoHighlight, @\"action\")\n\t\t_dv(TVCLogLineTypeCTCP, @\"ctcp\")\n\t\t_dv(TVCLogLineTypeCTCPQuery, @\"ctcp\")\n\t\t_dv(TVCLogLineTypeCTCPReply, @\"ctcp\")\n\t\t_dv(TVCLogLineTypeDCCFileTransfer, @\"dcc-file-transfer\")\n\t\t_dv(TVCLogLineTypeDebug, @\"debug\")\n\t\t_dv(TVCLogLineTypeInvite, @\"invite\")\n\t\t_dv(TVCLogLineTypeJoin, @\"join\")\n\t\t_dv(TVCLogLineTypeKick, @\"kick\")\n\t\t_dv(TVCLogLineTypeKill, @\"kill\")\n\t\t_dv(TVCLogLineTypeMode, @\"mode\")\n\t\t_dv(TVCLogLineTypeNick, @\"nick\")\n\t\t_dv(TVCLogLineTypeNotice, @\"notice\")\n\t\t_dv(TVCLogLineTypeOffTheRecordEncryptionStatus, @\"off-the-record-encryption-status\")\n\t\t_dv(TVCLogLineTypePart, @\"part\")\n\t\t_dv(TVCLogLineTypePrivateMessage, @\"privmsg\")\n\t\t_dv(TVCLogLineTypePrivateMessageNoHighlight, @\"privmsg\")\n\t\t_dv(TVCLogLineTypeQuit, @\"quit\")\n\t\t_dv(TVCLogLineTypeTopic, @\"topic\")\n\t\t_dv(TVCLogLineTypeWebsite, @\"website\")\n\n\t\tdefault:\n\t\t{\n\t\t\treturn nil;\n\t\t}\n\t}\n\n#undef _dv\n}\n\n+ (NSString *)stringForMemberType:(TVCLogLineMemberType)type\n{\n\tif (type == TVCLogLineMemberTypeLocalUser) {\n\t\treturn @\"myself\";\n\t} else {\n\t\treturn @\"normal\";\n\t}\n}\n\n- (nullable NSString *)lineTypeString\n{\n\treturn [self.class stringForLineType:self.lineType];\n}\n\n- (NSString *)memberTypeString\n{\n\treturn [self.class stringForMemberType:self.memberType];\n}\n\n- (NSString *)formattedTimestamp\n{\n\treturn [self formattedTimestampWithFormat:nil];\n}\n\n- (NSString *)formattedTimestampWithFormat:(nullable NSString *)format\n{\n\tif (format.length == 0) {\n\t\tformat = themeSettings().themeTimestampFormat;\n\t}\n\n\tif (format.length == 0) {\n\t\tformat = [TPCPreferences themeTimestampFormat];\n\t}\n\n\tif (format.length == 0) {\n\t\tformat = [TPCPreferences themeTimestampFormatDefault];\n\t}\n\n\tNSString *time = TXFormattedTimestamp(self.receivedAt, format);\n\n\treturn time;\n}\n\n- (nullable NSString *)formattedNicknameInChannel:(nullable IRCChannel *)channel\n{\n\treturn [self formattedNicknameInChannel:channel withFormat:nil];\n}\n\n- (nullable NSString *)formattedNicknameInChannel:(nullable IRCChannel *)channel withFormat:(nullable NSString *)format\n{\n\tif (self.nickname == nil) {\n\t\treturn nil;\n\t}\n\n\tif (format == nil) {\n\t\tif (self.lineType == TVCLogLineTypeAction) {\n\t\t\treturn [NSString stringWithFormat:TVCLogLineActionNicknameFormat, self.nickname];\n\t\t} else if (self.lineType == TVCLogLineTypeNotice) {\n\t\t\treturn [NSString stringWithFormat:TVCLogLineNoticeNicknameFormat, self.nickname];\n\t\t}\n\t}\n\n\treturn [channel.associatedClient formatNickname:self.nickname inChannel:channel withFormat:format];\n}\n\n- (NSString *)renderedBodyForTranscriptLog\n{\n\treturn [self renderedBodyForTranscriptLogInChannel:nil];\n}\n\n- (NSString *)renderedBodyForTranscriptLogInChannel:(nullable IRCChannel *)channel\n{\n\tNSMutableString *s = [NSMutableString string];\n\n\tNSString *timeFormatted = [self formattedTimestampWithFormat:TLOFileLoggerISOStandardClockFormat];\n\n\tif (timeFormatted) {\n\t\t[s appendString:timeFormatted];\n\t\t[s appendString:@\" \"];\n\t}\n\n\tNSString *nicknameFormatted = nil;\n\n\tif (self.lineType == TVCLogLineTypeAction) {\n\t\tnicknameFormatted = [self formattedNicknameInChannel:channel withFormat:TLOFileLoggerActionNicknameFormat];\n\t} else if (self.lineType == TVCLogLineTypeNotice) {\n\t\tnicknameFormatted = [self formattedNicknameInChannel:channel withFormat:TLOFileLoggerNoticeNicknameFormat];\n\t} else {\n\t\tnicknameFormatted = [self formattedNicknameInChannel:channel withFormat:TLOFileLoggerUndefinedNicknameFormat];\n\t}\n\n\tif (nicknameFormatted) {\n\t\t[s appendString:nicknameFormatted];\n\t\t[s appendString:@\" \"];\n\t}\n\n\t[s appendString:self.messageBody];\n\n\treturn s.stripIRCEffects;\n}\n\n- (void)computeNicknameColorStyle\n{\n\tif (self.nickname != nil &&\n\t\t(self.lineType == TVCLogLineTypePrivateMessage ||\n\t\t self.lineType == TVCLogLineTypePrivateMessageNoHighlight ||\n\t\t self.lineType == TVCLogLineTypeAction ||\n\t\t self.lineType == TVCLogLineTypeActionNoHighlight))\n\t{\n\t\tBOOL isOverride = NO;\n\n\t\tself->_nicknameColorStyle =\n\t\t[IRCUserNicknameColorStyleGenerator nicknameColorStyleForString:self.nickname isOverride:&isOverride];\n\n\t\tself->_nicknameColorStyleOverride = isOverride;\n\t} else {\n\t\tself->_nicknameColorStyle = nil;\n\t}\n}\n\n- (void)populateDuringCopy:(__kindof XRPortablePropertyObject *)newObject mutableCopy:(BOOL)mutableCopy\n{\n\tTVCLogLine *object = (TVCLogLine *)newObject;\n\n\tobject->_uniqueIdentifier = self->_uniqueIdentifier;\n\n\tobject->_isEncrypted = self->_isEncrypted;\n\tobject->_isFirstForDay = self->_isFirstForDay;\n\n\tobject->_excludeKeywords = self->_excludeKeywords;\n\tobject->_highlightKeywords = self->_highlightKeywords;\n\n\tobject->_rendererAttributes = self->_rendererAttributes;\n\n\tobject->_receivedAt = self->_receivedAt;\n\n\tobject->_command = self->_command;\n\tobject->_messageBody = self->_messageBody;\n\tobject->_nickname = self->_nickname;\n\tobject->_nicknameColorStyle = self->_nicknameColorStyle;\n\n\tobject->_nicknameColorStyleOverride = self->_nicknameColorStyleOverride;\n\n\tobject->_lineType = self->_lineType;\n\tobject->_memberType = self->_memberType;\n\n\tobject->_sessionIdentifier = self->_sessionIdentifier;\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [TVCLogLineMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogLineMutable\n\n@dynamic command;\n@dynamic excludeKeywords;\n@dynamic highlightKeywords;\n@dynamic rendererAttributes;\n@dynamic isEncrypted;\n@dynamic isFirstForDay;\n@dynamic lineType;\n@dynamic memberType;\n@dynamic messageBody;\n@dynamic nickname;\n@dynamic receivedAt;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [TVCLogLine self];\n}\n\n- (void)setIsEncrypted:(BOOL)isEncrypted\n{\n\tif (self->_isEncrypted != isEncrypted) {\n\t\tself->_isEncrypted = isEncrypted;\n\t}\n}\n\n- (void)setIsFirstForDay:(BOOL)isFirstForDay\n{\n\tif (self->_isFirstForDay != isFirstForDay) {\n\t\tself->_isFirstForDay = isFirstForDay;\n\t}\n}\n\n- (void)setExcludeKeywords:(nullable NSArray<NSString *> *)excludeKeywords\n{\n\tif (self->_excludeKeywords != excludeKeywords) {\n\t\tself->_excludeKeywords = [excludeKeywords copy];\n\t}\n}\n\n- (void)setHighlightKeywords:(nullable NSArray<NSString *> *)highlightKeywords\n{\n\tif (self->_highlightKeywords != highlightKeywords) {\n\t\tself->_highlightKeywords = [highlightKeywords copy];\n\t}\n}\n\n- (void)setRendererAttributes:(nullable NSDictionary<NSString *, id> *)rendererAttributes\n{\n\tif (self->_rendererAttributes != rendererAttributes) {\n\t\tself->_rendererAttributes = [rendererAttributes copy];\n\t}\n}\n\n- (void)setReceivedAt:(NSDate *)receivedAt\n{\n\tNSParameterAssert(receivedAt != nil);\n\n\tif (self->_receivedAt != receivedAt) {\n\t\tself->_receivedAt = [receivedAt copy];\n\t}\n}\n\n- (void)setCommand:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tif (self->_command != command) {\n\t\tself->_command = [command copy];\n\t}\n}\n\n- (void)setMessageBody:(NSString *)messageBody\n{\n\tNSParameterAssert(messageBody != nil);\n\n\tif (self->_messageBody != messageBody) {\n\t\tself->_messageBody = [messageBody copy];\n\t}\n}\n\n- (void)setNickname:(nullable NSString *)nickname\n{\n\tif (self->_nickname != nickname) {\n\t\tself->_nickname = [nickname copy];\n\n\t\t[self computeNicknameColorStyle];\n\t}\n}\n\n- (void)setMemberType:(TVCLogLineMemberType)memberType\n{\n\tif (self->_memberType != memberType) {\n\t\tself->_memberType = memberType;\n\t}\n}\n\n- (void)setLineType:(TVCLogLineType)lineType\n{\n\tif (self->_lineType != lineType) {\n\t\tself->_lineType = lineType;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogPolicy.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"IRCChannel.h\"\n#import \"TDCAlert.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOpenLink.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCThemeController.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogPolicyPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Specific menu items are gathered and inserted at specific locations */\n#define _WebKit1MenuItemTagInspectElement\t\t\t2024\n#define _WebKit1MenuItemTagLookupInDictionary\t\tWebMenuItemTagLookUpInDictionary\n#define _WebKit1MenuItemTagSearchWithGoogle\t\t\tWebMenuItemTagSearchWeb\n\n#define _WebKit2MenuItemTagInspectElement\t\t\t57\n#define _WebKit2MenuItemTagLookupInDictionary\t\t22\n#define _WebKit2MenuItemTagSearchWithGoogle\t\t\t21\n\n@implementation TVCLogPolicy\n\n- (NSArray<NSMenuItem *> *)constructContextMenuItemsForWebView:(TVCLogView *)webView defaultMenuItems:(NSArray<NSMenuItem *> *)defaultMenuItems\n{\n\tTVCLogController *viewController = webView.viewController;\n\n\tBOOL isWebKit2 = webView.isUsingWebKit2;\n\n\tNSMutableArray<NSMenuItem *> *menuItems = [NSMutableArray array];\n\n\tif (self.anchorURL)\n\t{\n\t\tNSMenu *urlMenu = menuController().channelViewURLMenu;\n\n\t\tfor (NSMenuItem *item in urlMenu.itemArray) {\n\t\t\tNSMenuItem *newItem = [item copy];\n\n\t\t\t[newItem setUserInfo:self.anchorURL recursively:YES];\n\n\t\t\t[menuItems addObject:newItem];\n\t\t}\n\n\t\tself.anchorURL = nil;\n\t}\n\telse if (self.nickname)\n\t{\n\t\tif (viewController.associatedChannel == nil ||\n\t\t\tviewController.associatedChannel.isUtility)\n\t\t{\n\t\t\tNSMenuItem *noActionMenuItem =\n\t\t\t[[NSMenuItem alloc] initWithTitle:TXTLS(@\"BasicLanguage[7kc-mo]\")\n\t\t\t\t\t\t\t\t\t   action:nil\n\t\t\t\t\t\t\t\tkeyEquivalent:@\"\"];\n\n\t\t\t[menuItems addObject:noActionMenuItem];\n\t\t} else {\n\t\t\tNSMenu *memberMenu = menuController().userControlMenu;\n\n\t\t\tfor (NSMenuItem *item in memberMenu.itemArray) {\n\t\t\t\tNSMenuItem *newItem = [item copy];\n\n\t\t\t\t[newItem setUserInfo:self.nickname recursively:YES];\n\n\t\t\t\t[menuItems addObject:newItem];\n\t\t\t}\n\t\t}\n\n\t\tself.nickname = nil;\n\t}\n\telse if (self.channelName)\n\t{\n\t\tNSMenu *chanMenu = menuController().channelViewChannelNameMenu;\n\n\t\tfor (NSMenuItem *item in chanMenu.itemArray) {\n\t\t\tNSMenuItem *newItem = [item copy];\n\n\t\t\t[newItem setUserInfo:self.channelName recursively:YES];\n\n\t\t\t[menuItems addObject:newItem];\n\t\t}\n\n\t\tself.channelName = nil;\n\t}\n\telse\n\t{\n\t\tNSMenu *menu = menuController().channelViewGeneralMenu;\n\n\t\tNSMenuItem *inspectElementItem = nil;\n\t\tNSMenuItem *lookupInDictionaryItem = nil;\n\t\tNSMenuItem *searchWithGoogleItem = nil;\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\tfor (NSMenuItem *item in defaultMenuItems) {\n\t\t\tif ((item.tag == _WebKit1MenuItemTagLookupInDictionary && isWebKit2 == NO) ||\n\t\t\t\t(item.tag == _WebKit2MenuItemTagLookupInDictionary && isWebKit2))\n\t\t\t{\n\t\t\t\tlookupInDictionaryItem = [item copy];\n\t\t\t} else if ((item.tag == _WebKit1MenuItemTagInspectElement && isWebKit2 == NO) ||\n\t\t\t\t\t   (item.tag == _WebKit2MenuItemTagInspectElement && isWebKit2))\n\t\t\t{\n\t\t\t\tinspectElementItem = [item copy];\n\t\t\t} else if ((item.tag == _WebKit1MenuItemTagSearchWithGoogle && isWebKit2 == NO) ||\n\t\t\t\t\t   (item.tag == _WebKit2MenuItemTagSearchWithGoogle && isWebKit2))\n\t\t\t{\n\t\t\t\tsearchWithGoogleItem = [item copy];\n\t\t\t}\n\t\t}\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n\t\tfor (NSMenuItem *item in menu.itemArray) {\n\t\t\tNSMenuItem *newItem = [item copy];\n\n\t\t\tif (newItem.tag == MTWKGeneralSearchWithGoogle) {\n\t\t\t\tif (searchWithGoogleItem != nil) {\n\t\t\t\t\t[menuItems addObject:searchWithGoogleItem];\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else if (newItem.tag == MTWKGeneralLookUpInDictionary) {\n\t\t\t\tif (lookupInDictionaryItem != nil) {\n\t\t\t\t\t[menuItems addObject:lookupInDictionaryItem];\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t[menuItems addObject:newItem];\n\t\t}\n\n\t\tif ([TPCPreferences developerModeEnabled]) {\n\t\t\t[menuItems addObject:[NSMenuItem separatorItem]];\n\n\t\t\t[menuItems addObject:\n\t\t\t [NSMenuItem menuItemWithTitle:TXTLS(@\"BasicLanguage[6cw-ni]\")\n\t\t\t\t\t\t\t\t\ttarget:menuController()\n\t\t\t\t\t\t\t\t\taction:@selector(copyLogAsHtml:)]];\n\n\t\t\t[menuItems addObject:\n\t\t\t [NSMenuItem menuItemWithTitle:TXTLS(@\"BasicLanguage[ngd-ms]\")\n\t\t\t\t\t\t\t\t\ttarget:menuController()\n\t\t\t\t\t\t\t\t\taction:@selector(forceReloadTheme:)]];\n\n\t\t\tif (inspectElementItem == nil) {\n\t\t\t\tif (isWebKit2) {\n\t\t\t\t\t[menuItems addObject:\n\t\t\t\t\t [NSMenuItem menuItemWithTitle:TXTLS(@\"BasicLanguage[tfj-m9]\")\n\t\t\t\t\t\t\t\t\t\t\ttarget:menuController()\n\t\t\t\t\t\t\t\t\t\t\taction:@selector(openWebInspector:)]];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t[menuItems addObject:inspectElementItem];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn [menuItems copy];\n}\n\n- (NSMenu *)constructContextMenuForWebView:(TVCLogView *)webView withDefaultMenuItems:(NSArray<NSMenuItem *> *)defaultMenuItems\n{\n\tNSMenu *contextMenu = [[NSMenu alloc] initWithTitle:TXLocalizationNotNeeded(@\"Context Menu\")];\n\n\tNSArray *menuItems = [self constructContextMenuItemsForWebView:webView defaultMenuItems:defaultMenuItems];\n\n\tfor (NSMenuItem *menuItem in menuItems) {\n\t\t[contextMenu addItem:menuItem];\n\t}\n\n\treturn contextMenu;\n}\n\n- (void)displayContextMenuInWebView:(TVCLogView *)webView\n{\n\tif (webView.isUsingWebKit2 == NO) {\n\t\treturn;\n\t}\n\n\tNSMenu *contextMenu = [self constructContextMenuForWebView:webView withDefaultMenuItems:@[]];\n\n\tNSView *webViewBacking = webView.webView;\n\n\tNSWindow *webViewWindow = webViewBacking.window;\n\n\tNSPoint mouseLocationGlobal = [NSEvent mouseLocation];\n\n\tNSRect mouseLocationLocal =\n\t[webViewWindow convertRectFromScreen:NSMakeRect(mouseLocationGlobal.x, mouseLocationGlobal.y, 0, 0)];\n\n\tNSEvent *event = [NSEvent mouseEventWithType:NSEventTypeRightMouseUp\n\t\t\t\t\t\t\t\t\t\tlocation:mouseLocationLocal.origin\n\t\t\t\t\t\t\t\t   modifierFlags:0\n\t\t\t\t\t\t\t\t\t   timestamp:0\n\t\t\t\t\t\t\t\t\twindowNumber:webViewWindow.windowNumber\n\t\t\t\t\t\t\t\t\t\t context:nil\n\t\t\t\t\t\t\t\t\t eventNumber:0\n\t\t\t\t\t\t\t\t\t  clickCount:0\n\t\t\t\t\t\t\t\t\t\tpressure:0];\n\n\t[NSMenu popUpContextMenu:contextMenu withEvent:event forView:webViewBacking];\n}\n\n#pragma mark -\n#pragma mark WebKit Delegate\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\n- (NSArray<NSMenuItem *> *)webView1:(WebView *)webView logView:(TVCLogView *)logView contextMenuWithDefaultMenuItems:(NSArray *)defaultMenuItems\n{\n\treturn [self constructContextMenuItemsForWebView:logView defaultMenuItems:defaultMenuItems];\n}\n\n- (void)webView1:(WebView *)webView logView:(TVCLogView *)logView resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource\n{\n\t[challenge.sender cancelAuthenticationChallenge:challenge];\n}\n\n- (NSUInteger)webView1:(WebView *)webView logView:(TVCLogView *)logView dragDestinationActionMaskForDraggingInfo:(id<NSDraggingInfo>)draggingInfo\n{\n\tNSPasteboard *pboard = [draggingInfo draggingPasteboard];\n\n\tif ([pboard.types containsObject:NSFilenamesPboardType]) {\n\t\treturn WebDragDestinationActionAny;\n\t}\n\n\treturn WebDragDestinationActionNone;\n}\n\n- (void)webView1:(WebView *)webView logView:(TVCLogView *)logView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener\n{\n\tNSInteger action = [actionInformation integerForKey:WebActionNavigationTypeKey];\n\n\tif (action == WebNavigationTypeLinkClicked) {\n\t\t[listener ignore];\n\n\t\tNSURL *actionURL = actionInformation[WebActionOriginalURLKey];\n\n\t\t[self openWebpage:actionURL];\n\t} else {\n\t\t[listener use];\n\t}\n}\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n#pragma mark -\n#pragma mark WebKit2 Delegate\n\n- (void)webView2:(WKWebView *)webView logView:(TVCLogView *)logView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nonnull))completionHandler\n{\n\tNSString *authenticationMethod = challenge.protectionSpace.authenticationMethod;\n\n\tif ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {\n\t\tcompletionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);\n\t} else {\n\t\tcompletionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);\n\t}\n}\n\n- (void)webView2:(WKWebView *)webView logView:(TVCLogView *)logView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler\n{\n\tWKNavigationType action = navigationAction.navigationType;\n\n\tif (action == WKNavigationTypeLinkActivated) {\n\t\tNSURL *actionURL = navigationAction.request.URL;\n\n\t\tdecisionHandler(WKNavigationActionPolicyCancel);\n\n\t\t[self openWebpage:actionURL];\n\t} else {\n\t\tdecisionHandler(WKNavigationActionPolicyAllow);\n\t}\n}\n\n- (NSMenu *)webView2:(WKWebView *)webView logView:(TVCLogView *)logView contextMenuWithDefaultMenu:(NSMenu *)defaultMenu\n{\n\treturn [self constructContextMenuForWebView:logView withDefaultMenuItems:defaultMenu.itemArray];\n}\n\n#pragma mark -\n#pragma mark Shared\n\n- (void)channelNameDoubleClicked\n{\n\t[menuController() joinChannelClicked:self.channelName];\n\n\tself.channelName = nil;\n}\n\n- (void)nicknameDoubleClicked\n{\n\tmenuController().pointedNickname = self.nickname;\n\n\t[menuController() memberInChannelViewDoubleClicked:nil];\n\n\tself.nickname = nil;\n}\n\n- (void)topicBarDoubleClicked\n{\n\t[menuController() showChannelModifyTopicSheet:nil];\n}\n\n- (void)openWebpage:(NSURL *)webpageURL\n{\n\tNSParameterAssert(webpageURL != nil);\n\n\tBOOL openInBackground = [TPCPreferences openBrowserInBackground];\n\n\tNSUInteger keyboardKeys = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\tif ((keyboardKeys & NSEventModifierFlagCommand) == NSEventModifierFlagCommand) {\n\t\topenInBackground = !openInBackground;\n\t}\n\n\tif ([webpageURL.scheme isEqualToString:@\"http\"] ||\n\t\t[webpageURL.scheme isEqualToString:@\"https\"] ||\n\t\t[webpageURL.scheme isEqualToString:@\"textual\"])\n\t{\n\t\t[TLOpenLink open:webpageURL inBackground:openInBackground];\n\n\t\treturn;\n\t}\n\n\tNSString *applicationName = [RZWorkspace() nameOfApplicationToOpenURL:webpageURL];\n\n\tBOOL openLink =\n\t[TDCAlert modalAlertWithMessage:TXTLS(@\"Prompts[5oq-vv]\", webpageURL.absoluteString)\n\t\t\t\t\t\t\t  title:TXTLS(@\"Prompts[2ul-cl]\", applicationName)\n\t\t\t\t\t  defaultButton:TXTLS(@\"Prompts[mvh-ms]\")\n\t\t\t\t\talternateButton:TXTLS(@\"Prompts[99q-gg]\")\n\t\t\t\t\t suppressionKey:@\"open_non_http_url_warning\"\n\t\t\t\t\tsuppressionText:nil];\n\n\tif (openLink == NO) {\n\t\treturn;\n\t}\n\n\t[TLOpenLink open:webpageURL inBackground:openInBackground];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogRenderer.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"GTMEncodeHTML.h\"\n#import \"NSColorHelper.h\"\n#import \"NSStringHelper.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCChannelUser.h\"\n#import \"IRCColorFormat.h\"\n#import \"IRCUser.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"THOUnicodeHelper.h\"\n#import \"TLOLinkParser.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogLine.h\"\n#import \"TVCLogRenderer.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogRenderer ()\n@property (nonatomic, copy, nullable) NSString *body;\n@property (nonatomic, copy, nullable) id finalResult;\n@property (nonatomic, strong, nullable) NSMutableAttributedString *bodyWithAttributes;\n@property (nonatomic, strong, nullable) NSMutableDictionary<NSString *, id> *renderedBodyOpenAttributes;\n@property (nonatomic, copy) NSDictionary<NSString *, id> *rendererAttributes;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, id> *outputDictionary;\n@property (nonatomic, weak) TVCLogController *viewController;\n@property (nonatomic, assign) TVCLogLineType lineType;\n@property (nonatomic, assign) TVCLogLineMemberType memberType;\n@property (nonatomic, assign) BOOL escapeBody;\n@end\n\nNSString * const TVCLogRendererFormattingForegroundColorAttribute = @\"TVCLogRendererFormattingForegroundColorAttribute\";\nNSString * const TVCLogRendererFormattingBackgroundColorAttribute = @\"TVCLogRendererFormattingBackgroundColorAttribute\";\nNSString * const TVCLogRendererFormattingBoldTextAttribute = @\"TVCLogRendererFormattingBoldTextAttribute\";\nNSString * const TVCLogRendererFormattingItalicTextAttribute = @\"TVCLogRendererFormattingItalicTextAttribute\";\nNSString * const TVCLogRendererFormattingMonospaceTextAttribute = @\"TVCLogRendererFormattingMonospaceTextAttribute\";\nNSString * const TVCLogRendererFormattingStrikethroughTextAttribute = @\"TVCLogRendererFormattingStrikethroughTextAttribute\";\nNSString * const TVCLogRendererFormattingUnderlineTextAttribute = @\"TVCLogRendererFormattingUnderlineTextAttribute\";\nNSString * const TVCLogRendererFormattingChannelNameAttribute = @\"TVCLogRendererFormattingChannelNameAttribute\";\nNSString * const TVCLogRendererFormattingConversationTrackingAttribute = @\"TVCLogRendererFormattingConversationTrackingAttribute\";\nNSString * const TVCLogRendererFormattingKeywordHighlightAttribute = @\"TVCLogRendererFormattingKeywordHighlightAttribute\";\nNSString * const TVCLogRendererFormattingURLAttribute = @\"TVCLogRendererFormattingURLAttribute\";\n\nNSString * const TVCLogRendererConfigurationRenderLinksAttribute = @\"TVCLogRendererConfigurationRenderLinksAttribute\";\nNSString * const TVCLogRendererConfigurationLineTypeAttribute = @\"TVCLogRendererConfigurationLineTypeAttribute\";\nNSString * const TVCLogRendererConfigurationMemberTypeAttribute = @\"TVCLogRendererConfigurationMemberTypeAttribute\";\nNSString * const TVCLogRendererConfigurationHighlightKeywordsAttribute = @\"TVCLogRendererConfigurationHighlightKeywordsAttribute\";\nNSString * const TVCLogRendererConfigurationExcludedKeywordsAttribute = @\"TVCLogRendererConfigurationExcludedKeywordsAttribute\";\nNSString * const TVCLogRendererConfigurationDoNotEscapeBodyAttribute = @\"TVCLogRendererConfigurationDoNotEscapeBodyAttribute\";\n\nNSString * const TVCLogRendererConfigurationAttributedStringPreferredFontAttribute = @\"TVCLogRendererConfigurationAttributedStringPreferredFontAttribute\";\nNSString * const TVCLogRendererConfigurationAttributedStringPreferredFontColorAttribute = @\"TVCLogRendererConfigurationAttributedStringPreferredFontColorAttribute\";\n\nNSString * const TVCLogRendererResultsListOfLinksInBodyAttribute = @\"TVCLogRendererResultsListOfLinksInBodyAttribute\";\nNSString * const TVCLogRendererResultsListOfLinksMappedInBodyAttribute = @\"TVCLogRendererResultsListOfLinksMappedInBodyAttribute\";\nNSString * const TVCLogRendererResultsKeywordMatchFoundAttribute = @\"TVCLogRendererResultsKeywordMatchFoundAttribute\";\nNSString * const TVCLogRendererResultsListOfUsersFoundAttribute = @\"TVCLogRendererResultsListOfUsersFoundAttribute\";\nNSString * const TVCLogRendererResultsOriginalBodyWithoutEffectsAttribute = @\"TVCLogRendererResultsOriginalBodyWithoutEffectsAttribute\";\n\n@implementation TVCLogRenderer\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\tself->_outputDictionary = [NSMutableDictionary dictionary];\n\t}\n\n\treturn self;\n}\n\n- (void)buildEffectsDictionary\n{\n\tNSString *body = self->_body;\n\n\tNSUInteger bodyLength = body.length;\n\n\tUniChar charactersIn[bodyLength];\n\n\t[body getCharacters:charactersIn range:body.range];\n\n\tNSMutableAttributedString *bodyWithAttributes = [[NSMutableAttributedString alloc] initWithString:body attributes:nil];\n\n\t[bodyWithAttributes beginEditing];\n\n\tNSUInteger characterOffset = 0;\n\n\tfor (NSUInteger i = 0; i < bodyLength; i++) {\n\t\tUniChar character = charactersIn[i];\n\n\t\tNSUInteger characterPosition = (i - characterOffset);\n\n\t\tif (character < 0x20) {\n\t\t\tswitch (character) {\n\t\t\t\tcase IRCTextFormatterEffectBoldCharacter:\n\t\t\t\t{\n\t\t\t\t\tif (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingBoldTextAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingBoldTextAttribute startingAt:characterPosition];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingBoldTextAttribute value:@(YES) startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterEffectColorAsDigitCharacter:\n\t\t\t\tcase IRCTextFormatterEffectColorAsHexCharacter:\n\t\t\t\t{\n\t\t\t\t\tid foregroundColor = nil;\n\t\t\t\t\tid backgroundColor = nil;\n\n\t\t\t\t\tNSUInteger colorOffset = [bodyWithAttributes.string\n\t\t\t\t\t\t\t\t\t\t\t  colorComponentsOfCharacter:character\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  startingAt:characterPosition\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t foregroundColor:&foregroundColor\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t backgroundColor:&backgroundColor];\n\n\t\t\t\t\tif (foregroundColor != nil) {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingForegroundColorAttribute value:foregroundColor startingAt:characterPosition];\n\t\t\t\t\t} else if (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingForegroundColorAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingForegroundColorAttribute startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\tif (backgroundColor != nil) {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingBackgroundColorAttribute value:backgroundColor startingAt:characterPosition];\n\t\t\t\t\t} else if (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingBackgroundColorAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t/* We only strip the background color if there is no longer a foreground color. A end character. */\n\t\t\t\t\t\tif (foregroundColor == nil) {\n\t\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingBackgroundColorAttribute startingAt:characterPosition];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\ti += (colorOffset - 1); // For loop will increase this by one so we minus by one\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, colorOffset)];\n\n\t\t\t\t\tcharacterOffset += colorOffset;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterTerminatingCharacter:\n\t\t\t\t{\n\t\t\t\t\t[bodyWithAttributes resetAttributesStaringAt:characterPosition];\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterEffectItalicCharacter:\n\t\t\t\tcase IRCTextFormatterEffectItalicCharacterOld:\n\t\t\t\t{\n\t\t\t\t\tif (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingItalicTextAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingItalicTextAttribute startingAt:characterPosition];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingItalicTextAttribute value:@(YES) startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterEffectMonospaceCharacter:\n\t\t\t\t{\n\t\t\t\t\tif (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingMonospaceTextAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingMonospaceTextAttribute startingAt:characterPosition];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingMonospaceTextAttribute value:@(YES) startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterEffectStrikethroughCharacter:\n\t\t\t\t{\n\t\t\t\t\tif (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingStrikethroughTextAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingStrikethroughTextAttribute startingAt:characterPosition];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingStrikethroughTextAttribute value:@(YES) startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcase IRCTextFormatterEffectUnderlineCharacter:\n\t\t\t\t{\n\t\t\t\t\tif (characterPosition > 0 && [bodyWithAttributes isAttributeSet:TVCLogRendererFormattingUnderlineTextAttribute atIndex:characterPosition]) {\n\t\t\t\t\t\t[bodyWithAttributes removeAttribute:TVCLogRendererFormattingUnderlineTextAttribute startingAt:characterPosition];\n\t\t\t\t\t} else {\n\t\t\t\t\t\t[bodyWithAttributes addAttribute:TVCLogRendererFormattingUnderlineTextAttribute value:@(YES) startingAt:characterPosition];\n\t\t\t\t\t}\n\n\t\t\t\t\t[bodyWithAttributes deleteCharactersInRange:NSMakeRange(characterPosition, 1)];\n\n\t\t\t\t\tcharacterOffset++;\n\n\t\t\t\t\tcontinue;\n\t\t\t\t} // case\n\t\t\t} // switch\n\t\t} // character < 0x20\n\t} // for loop\n\n\t[bodyWithAttributes endEditing];\n\n\tNSString *stringWithoutEffects = bodyWithAttributes.string;\n\n\tself->_outputDictionary[TVCLogRendererResultsOriginalBodyWithoutEffectsAttribute] = stringWithoutEffects;\n\n\tself->_body = stringWithoutEffects;\n\n\tself->_bodyWithAttributes = bodyWithAttributes;\n}\n\n- (BOOL)isRenderingPRIVMSG\n{\n\treturn (self->_lineType == TVCLogLineTypePrivateMessage || self->_lineType == TVCLogLineTypeAction);\n}\n\n- (BOOL)isRenderingPRIVMSG_or_NOTICE\n{\n\treturn (self->_lineType == TVCLogLineTypePrivateMessage || self->_lineType == TVCLogLineTypeAction || self->_lineType == TVCLogLineTypeNotice);\n}\n\n- (BOOL)scanForKeywords\n{\n\treturn ([self isRenderingPRIVMSG] && self->_memberType == TVCLogLineMemberTypeNormal);\n}\n\n- (void)stripDangerousUnicodeCharactersFromBody\n{\n\tif ([TPCPreferences automaticallyFilterUnicodeTextSpam] == NO) {\n\t\treturn;\n\t}\n\n\tif (self->_lineType != TVCLogLineTypeAction\t\t\t&&\n\t\tself->_lineType != TVCLogLineTypeCTCP\t\t\t&&\n\t\tself->_lineType != TVCLogLineTypeCTCPQuery\t\t&&\n\t\tself->_lineType != TVCLogLineTypeCTCPReply\t\t&&\n\t\tself->_lineType != TVCLogLineTypeDCCFileTransfer\t&&\n\t\tself->_lineType != TVCLogLineTypeNotice\t\t\t&&\n\t\tself->_lineType != TVCLogLineTypePrivateMessage\t&&\n\t\tself->_lineType != TVCLogLineTypeTopic)\n\t{\n\t\treturn;\n\t}\n\n\tself->_body =\n\t[XRRegularExpression string:self->_body\n\t\t\t\treplacedByRegex:@\"([\\\\p{InCombining_Diacritical_Marks}]{3,})\"\n\t\t\t\t\t withString:CS_UnicodeReplacementCharacter];\n}\n\n- (void)buildListOfLinksInBody\n{\n\tBOOL renderLinks = [self->_rendererAttributes boolForKey:TVCLogRendererConfigurationRenderLinksAttribute];\n\n\tif (renderLinks == NO) {\n\t\treturn;\n\t}\n\n\tNSMutableDictionary<NSString *, NSString *> *linksMapped = [NSMutableDictionary dictionary];\n\n\tNSArray *links = [TLOLinkParser locateLinksInString:self->_body];\n\n\tfor (AHHyperlinkScannerResult *link in links) {\n\t\tNSRange linkRange = link.range;\n\n\t\tNSString *linkString = link.stringValue;\n\n\t\t[self->_bodyWithAttributes addAttribute:TVCLogRendererFormattingURLAttribute value:link range:linkRange];\n\n\t\tif (linksMapped[linkString] == nil) {\n\t\t\tlinksMapped[linkString] = link.uniqueIdentifier;\n\t\t}\n\t}\n\n\tself->_outputDictionary[TVCLogRendererResultsListOfLinksInBodyAttribute] = links;\n\tself->_outputDictionary[TVCLogRendererResultsListOfLinksMappedInBodyAttribute] = [linksMapped copy];\n}\n\n- (void)matchKeywords\n{\n\tif ([self scanForKeywords] == NO) {\n\t\treturn;\n\t}\n\n\tid excludedKeywords = [self->_rendererAttributes arrayForKey:TVCLogRendererConfigurationExcludedKeywordsAttribute];\n\tid highlightKeywords = [self->_rendererAttributes arrayForKey:TVCLogRendererConfigurationHighlightKeywordsAttribute];\n\n\tif ([highlightKeywords count] == 0) {\n\t\tself->_outputDictionary[TVCLogRendererResultsKeywordMatchFoundAttribute] = @(NO);\n\n\t\treturn;\n\t}\n\n\tNSMutableArray<NSValue *> *excludeRanges = [NSMutableArray array];\n\n\tfor (NSString *excludeKeyword in excludedKeywords) {\n\t\t[self->_body enumerateMatchesOfString:excludeKeyword withBlock:^(NSRange range, BOOL *stop) {\n\t\t\t[excludeRanges addObject:[NSValue valueWithRange:range]];\n\t\t} options:NSCaseInsensitiveSearch];\n\t}\n\n\tBOOL foundKeyword = NO;\n\n\tswitch ([TPCPreferences highlightMatchingMethod]) {\n\t\tcase TXNicknameHighlightMatchTypeExact:\n\t\tcase TXNicknameHighlightMatchTypePartial:\n\t\t{\n\t\t\tfoundKeyword = [self matchKeywordsUsingNormalMatching:highlightKeywords excludedRanges:excludeRanges];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TXNicknameHighlightMatchTypeRegularExpression:\n\t\t{\n\t\t\tfoundKeyword = [self matchKeywordsUsingRegularExpression:highlightKeywords excludedRanges:excludeRanges];\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tself->_outputDictionary[TVCLogRendererResultsKeywordMatchFoundAttribute] = @(foundKeyword);\n}\n\n- (BOOL)matchKeywordsUsingNormalMatching:(NSArray<NSString *> *)keywords excludedRanges:(NSArray<NSValue *> *)excludedRanges\n{\n\tNSParameterAssert(keywords != nil);\n\tNSParameterAssert(excludedRanges != nil);\n\n\tNSString *body = self->_body;\n\n\t__block BOOL foundKeyword = NO;\n\n\tfor (NSString *keyword in keywords) {\n\t\t[body enumerateMatchesOfString:keyword withBlock:^(NSRange range, BOOL *stop) {\n\t\t\tfor (NSValue *excludedRange in excludedRanges) {\n\t\t\t\tif (NSIntersectionRange(range, excludedRange.rangeValue).length > 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ([TPCPreferences highlightMatchingMethod] == TXNicknameHighlightMatchTypeExact) {\n\t\t\t\tif ([self sectionOfBodyIsSurroundedByNonAlphabeticals:range] == NO) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ([self->_bodyWithAttributes isAttributeSet:TVCLogRendererFormattingURLAttribute inRange:range] == NO) {\n\t\t\t\t[self->_bodyWithAttributes addAttribute:TVCLogRendererFormattingKeywordHighlightAttribute value:@(YES) range:range];\n\n\t\t\t\tfoundKeyword = YES;\n\n\t\t\t\t*stop = YES;\n\t\t\t}\n\t\t} options:NSCaseInsensitiveSearch];\n\n\t\tif (foundKeyword) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn foundKeyword;\n}\n\n- (BOOL)matchKeywordsUsingRegularExpression:(NSArray<NSString *> *)keywords excludedRanges:(NSArray<NSValue *> *)excludedRanges\n{\n\tNSParameterAssert(keywords != nil);\n\tNSParameterAssert(excludedRanges != nil);\n\n\tNSString *body = self->_body;\n\n\tBOOL foundKeyword = NO;\n\n\tfor (NSString *keyword in keywords) {\n\t\tNSRange range = [XRRegularExpression string:body rangeOfRegex:keyword withoutCase:YES];\n\n\t\tif (range.location == NSNotFound) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tBOOL enabled = YES;\n\n\t\tfor (NSValue *excludedRange in excludedRanges) {\n\t\t\tif (NSIntersectionRange(range, excludedRange.rangeValue).length > 0) {\n\t\t\t\tenabled = NO;\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (enabled == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ([self->_bodyWithAttributes isAttributeSet:TVCLogRendererFormattingURLAttribute inRange:range] == NO) {\n\t\t\t[self->_bodyWithAttributes addAttribute:TVCLogRendererFormattingKeywordHighlightAttribute value:@(YES) range:range];\n\n\t\t\tfoundKeyword = YES;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn foundKeyword;\n}\n\n- (void)findAllChannelNames\n{\n\tif ([self isRenderingPRIVMSG_or_NOTICE] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *body = self->_body;\n\n\t[body enumerateMatchesOfString:@\"#([a-zA-Z0-9\\\\#\\\\-]+)\" withBlock:^(NSRange range, BOOL *stop) {\n\t\tif ([self sectionOfBodyIsSurroundedByNonAlphabeticals:range] == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ([self->_bodyWithAttributes isAttributeSet:TVCLogRendererFormattingURLAttribute inRange:range] == NO) {\n\t\t\t[self->_bodyWithAttributes addAttribute:TVCLogRendererFormattingChannelNameAttribute value:@(YES) range:range];\n\t\t}\n\t} options:(NSCaseInsensitiveSearch | NSRegularExpressionSearch)];\n}\n\n- (BOOL)sectionOfBodyIsSurroundedByNonAlphabeticals:(NSRange)range\n{\n\tNSString *body = self->_body;\n\n\tNSUInteger bodyLength = body.length;\n\n\tUniChar aa = [body characterAtIndex:range.location];\n\n\tif (CS_StringIsBase10Numeric(aa) || [THOUnicodeHelper isAlphabeticalCodePoint:aa]) {\n\t\tNSInteger leftLocation = (range.location - 1);\n\n\t\tif (leftLocation >= 0 && leftLocation < bodyLength) {\n\t\t\tUniChar bb = [body characterAtIndex:leftLocation];\n\n\t\t\tif (CS_StringIsBase10Numeric(bb) || [THOUnicodeHelper isAlphabeticalCodePoint:bb]) {\n\t\t\t\treturn NO;\n\t\t\t}\n\t\t}\n\t}\n\n\tUniChar cc = [body characterAtIndex:(NSMaxRange(range) - 1)];\n\n\tif (CS_StringIsBase10Numeric(cc) || [THOUnicodeHelper isAlphabeticalCodePoint:cc]) {\n\t\tNSInteger rightLocation = NSMaxRange(range);\n\n\t\tif (rightLocation < bodyLength) {\n\t\t\tUniChar dd = [body characterAtIndex:rightLocation];\n\n\t\t\tif (CS_StringIsBase10Numeric(dd) || [THOUnicodeHelper isAlphabeticalCodePoint:dd]) {\n\t\t\t\treturn NO;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)scanBodyForChannelMembers\n{\n\tif ([self isRenderingPRIVMSG] == NO) {\n\t\treturn;\n\t}\n\n\tNSString *body = self->_body;\n\n\tNSUInteger bodyLength = body.length;\n\n\tif (bodyLength == 0) {\n\t\tself->_outputDictionary[TVCLogRendererResultsListOfUsersFoundAttribute] = [NSSet set];\n\n\t\treturn;\n\t}\n\n\tIRCChannel *channel = self->_viewController.associatedChannel;\n\n\tNSArray<IRCChannelUser *> *users = channel.memberList;\n\n\t__block NSUInteger totalNicknameCount = 0;\n\t__block NSUInteger totalNicknameLength = 0;\n\n\tNSMutableSet<IRCChannelUser *> *userSet = [NSMutableSet set];\n\n\tfor (IRCChannelUser *user in users) {\n\t\t[body enumerateMatchesOfString:user.user.nickname withBlock:^(NSRange range, BOOL *stop) {\n\t\t\tif ([self sectionOfBodyIsSurroundedByNonAlphabeticals:range] == NO) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ([self->_bodyWithAttributes isAttributeSet:TVCLogRendererFormattingURLAttribute inRange:range] == NO) {\n\t\t\t\t[self->_bodyWithAttributes addAttribute:TVCLogRendererFormattingConversationTrackingAttribute value:@(YES) range:range];\n\n\t\t\t\tif ([userSet containsObject:user] == NO) {\n\t\t\t\t\t[userSet addObject:user];\n\t\t\t\t}\n\n\t\t\t\tif ([self->_bodyWithAttributes isAttributeSet:TVCLogRendererFormattingKeywordHighlightAttribute inRange:range] == NO) {\n\t\t\t\t\ttotalNicknameCount += 1;\n\t\t\t\t\ttotalNicknameLength += range.length;\n\t\t\t\t}\n\t\t\t}\n\t\t} options:NSCaseInsensitiveSearch];\n\t}\n\n\t/* Calculate how much of the message is just nicknames.\n\t This is used when trying to stop highlight spam.\n\t Textual counts anything above 75% spam. */\n\tif ([TPCPreferences automaticallyDetectHighlightSpam]) {\n\t\tdouble nicknamePercent = (((double)totalNicknameLength / bodyLength) * 100.0);\n\n\t\tif ((nicknamePercent > 75.0 && totalNicknameCount > 10) ||\n\t\t\t(nicknamePercent > 50.0 && totalNicknameCount > 20))\n\t\t{\n\t\t\tself->_outputDictionary[TVCLogRendererResultsKeywordMatchFoundAttribute] = @(NO);\n\t\t}\n\t}\n\n\tself->_outputDictionary[TVCLogRendererResultsListOfUsersFoundAttribute] = [userSet copy];\n}\n\n#pragma mark -\n\n- (NSDictionary<NSString *, id> *)appKitAttributesFromRendererAttributes:(NSDictionary<NSString *, id> *)attributesIn\n{\n\tNSParameterAssert(attributesIn != nil);\n\n\tNSMutableDictionary<NSString *, id> *attributesOut = [NSMutableDictionary dictionary];\n\n\tNSFont *defaultFont = self->_rendererAttributes[TVCLogRendererConfigurationAttributedStringPreferredFontAttribute];\n\n\tNSColor *defaultFontColor = self->_rendererAttributes[TVCLogRendererConfigurationAttributedStringPreferredFontColorAttribute];\n\n\tNSFont *boldItalicFont = defaultFont;\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingMonospaceTextAttribute]) {\n\t\tboldItalicFont = [RZFontManager() convertFont:boldItalicFont toFamily:@\"Menlo\"];\n\n\t\tattributesOut[IRCTextFormatterMonospaceAttributeName] = @(YES);\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingBoldTextAttribute]) {\n\t\tboldItalicFont = [RZFontManager() convertFont:boldItalicFont toHaveTrait:NSBoldFontMask];\n\n\t\tattributesOut[IRCTextFormatterBoldAttributeName] = @(YES);\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingItalicTextAttribute]) {\n\t\tboldItalicFont = [RZFontManager() convertFont:boldItalicFont toHaveTrait:NSItalicFontMask];\n\n\t\tif ([boldItalicFont fontTraitSet:NSItalicFontMask] == NO) {\n\t\t\tboldItalicFont = boldItalicFont.convertToItalics;\n\t\t}\n\n\t\tattributesOut[IRCTextFormatterItalicAttributeName] = @(YES);\n\t}\n\n\tif (boldItalicFont) {\n\t\tattributesOut[NSFontAttributeName] = boldItalicFont;\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingStrikethroughTextAttribute]) {\n\t\tattributesOut[NSStrikethroughStyleAttributeName] = @(NSUnderlineStyleSingle);\n\n\t\tattributesOut[IRCTextFormatterStrikethroughAttributeName] = @(YES);\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingUnderlineTextAttribute]) {\n\t\tattributesOut[NSUnderlineStyleAttributeName] = @(NSUnderlineStyleSingle);\n\n\t\tattributesOut[IRCTextFormatterUnderlineAttributeName] = @(YES);\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingForegroundColorAttribute]) {\n\t\tid foregroundColor = attributesIn[TVCLogRendererFormattingForegroundColorAttribute];\n\n\t\tattributesOut[NSForegroundColorAttributeName] = [self.class mapColor:foregroundColor];\n\n\t\tattributesOut[IRCTextFormatterForegroundColorAttributeName] = foregroundColor;\n\t} else {\n\t\tif (defaultFontColor) {\n\t\t\tattributesOut[NSForegroundColorAttributeName] = defaultFontColor;\n\t\t}\n\t}\n\n\tif ([attributesIn containsKey:TVCLogRendererFormattingBackgroundColorAttribute]) {\n\t\tid backgroundColor = attributesIn[TVCLogRendererFormattingBackgroundColorAttribute];\n\n\t\tattributesOut[NSBackgroundColorAttributeName] = [self.class mapColor:backgroundColor];\n\n\t\tattributesOut[IRCTextFormatterBackgroundColorAttributeName] = backgroundColor;\n\t}\n\n\treturn [attributesOut copy];\n}\n\n- (nullable NSString *)renderStringAsHTML:(NSString *)string withAttributes:(NSDictionary<NSString *, id> *)stringAttributes inRange:(NSRange)attributesRange isFirstFragment:(BOOL)isFirstFragment isLastFragment:(BOOL)isLastFragment\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(stringAttributes != nil);\n\n\tNSString *html = nil;\n\n\tNSString *fragment = [string substringWithRange:attributesRange];\n\n\tNSMutableDictionary<NSString *, id> *templateTokens = [NSMutableDictionary dictionary];\n\n\tif ([stringAttributes containsKey:TVCLogRendererFormattingURLAttribute])\n\t{\n\t\tAHHyperlinkScannerResult *link = stringAttributes[TVCLogRendererFormattingURLAttribute];\n\n\t\tNSString *linkLocation = link.stringValue;\n\n\t\tif (self->_viewController.inlineMediaEnabledForView) {\n\t\t\tNSDictionary *linksMapped = self->_outputDictionary[TVCLogRendererResultsListOfLinksMappedInBodyAttribute];\n\n\t\t\tNSString *uniqueIdentifier = linksMapped[linkLocation];\n\n\t\t\tif (uniqueIdentifier) {\n\t\t\t\ttemplateTokens[@\"anchorInlineMediaAvailable\"] = @(YES);\n\t\t\t\ttemplateTokens[@\"anchorInlineMediaUniqueID\"] = uniqueIdentifier;\n\t\t\t}\n\t\t}\n\n\t\ttemplateTokens[@\"anchorLocation\"] = linkLocation;\n\n\t\ttemplateTokens[@\"anchorTitle\"] = [self.class escapeString:fragment];\n\n\t\thtml = [self.class renderTemplateNamed:@\"renderedStandardAnchorLinkResource\" attributes:templateTokens];\n\t}\n\telse if ([stringAttributes containsKey:TVCLogRendererFormattingChannelNameAttribute])\n\t{\n\t\ttemplateTokens[@\"channelName\"] = [self.class escapeString:fragment];\n\n\t\thtml = [self.class renderTemplateNamed:@\"renderedChannelNameLinkResource\" attributes:templateTokens];\n\t}\n\telse if ([stringAttributes containsKey:TVCLogRendererFormattingConversationTrackingAttribute])\n\t{\n\t\tif ([TPCPreferences disableNicknameColorHashing]) {\n\t\t\ttemplateTokens[@\"inlineNicknameMatchFound\"] = @(NO);\n\t\t} else {\n\t\t\tIRCChannel *channel = self->_viewController.associatedChannel;\n\n\t\t\tIRCChannelUser *member = [channel findMember:fragment];\n\n\t\t\tNSString *nickname = member.user.nickname;\n\n\t\t\tif (nickname.length > 1) {\n\t\t\t\tNSString *modeSymbol = @\"\";\n\n\t\t\t\tif ([TPCPreferences conversationTrackingIncludesUserModeSymbol]) {\n\t\t\t\t\tNSString *modeSymbolTemp = member.mark;\n\n\t\t\t\t\tif (attributesRange.location > 0) {\n\t\t\t\t\t\tNSString *leftCharacter = [string stringCharacterAtIndex:(attributesRange.location - 1)];\n\n\t\t\t\t\t\tif ([leftCharacter isEqualToString:modeSymbolTemp] == NO) {\n\t\t\t\t\t\t\tmodeSymbol = modeSymbolTemp;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmodeSymbol = modeSymbolTemp;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tNSString *nicknameColorStyle = [IRCUserNicknameColorStyleGenerator nicknameColorStyleForString:nickname];\n\n\t\t\t\ttemplateTokens[@\"inlineNicknameMatchFound\"] = @(YES);\n\n\t\t\t\ttemplateTokens[@\"inlineNicknameColorStyle\"] = nicknameColorStyle;\n\n\t\t\t\ttemplateTokens[@\"inlineNicknameUserModeSymbol\"] = modeSymbol;\n\t\t\t}\n\t\t}\n\n\t\thtml = [self.class escapeString:fragment];\n\t}\n\n\tBOOL escapeBody = self.escapeBody;\n\n\ttemplateTokens[@\"messageFragmentEscaped\"] = @(escapeBody);\n\n\tif (html == nil) {\n\t\tif (escapeBody) {\n\t\t\thtml = [self.class escapeString:fragment];\n\t\t} else {\n\t\t\thtml = fragment;\n\t\t}\n\t}\n\n\t// --- //\n\n\tif (self->_renderedBodyOpenAttributes == nil) {\n\t\tself->_renderedBodyOpenAttributes = [NSMutableDictionary dictionary];\n\t}\n\n\tvoid (^processToggleEffectsAttribute)(NSString *, NSString *) = ^(NSString *effectAttribute, NSString *effectTokenName)\n\t{\n\t\tif ([stringAttributes containsKey:effectAttribute]) {\n\t\t\ttemplateTokens[effectTokenName] = @(YES); // backwards compatibility\n\n\t\t\tif ([self->_renderedBodyOpenAttributes boolForKey:effectAttribute] == NO) {\n\t\t\t\t[self->_renderedBodyOpenAttributes setBool:YES forKey:effectAttribute];\n\n\t\t\t\tNSString *openedTokenName = [NSString stringWithFormat:@\"%@Opened\", effectTokenName];\n\n\t\t\t\ttemplateTokens[openedTokenName] = @(YES);\n\t\t\t}\n\n\t\t\tif (isLastFragment) {\n\t\t\t\tNSString *closedTokenName = [NSString stringWithFormat:@\"%@ClosedAtEnd\", effectTokenName];\n\n\t\t\t\ttemplateTokens[closedTokenName] = @(YES);\n\t\t\t}\n\t\t} else {\n\t\t\tif ([self->_renderedBodyOpenAttributes boolForKey:effectAttribute]) {\n\t\t\t\t[self->_renderedBodyOpenAttributes removeObjectForKey:effectAttribute];\n\n\t\t\t\tNSString *closedTokenName = [NSString stringWithFormat:@\"%@ClosedAtStart\", effectTokenName];\n\n\t\t\t\ttemplateTokens[closedTokenName] = @(YES);\n\t\t\t}\n\t\t}\n\t};\n\n\tprocessToggleEffectsAttribute(TVCLogRendererFormattingBoldTextAttribute, @\"fragmentIsBold\");\n\tprocessToggleEffectsAttribute(TVCLogRendererFormattingItalicTextAttribute, @\"fragmentIsItalicized\");\n\tprocessToggleEffectsAttribute(TVCLogRendererFormattingMonospaceTextAttribute, @\"fragmentIsMonospace\");\n\tprocessToggleEffectsAttribute(TVCLogRendererFormattingStrikethroughTextAttribute, @\"fragmentIsStruckthrough\");\n\tprocessToggleEffectsAttribute(TVCLogRendererFormattingUnderlineTextAttribute, @\"fragmentIsUnderlined\");\n\n\t// --- //\n\n\tid foregroundColorNew = stringAttributes[TVCLogRendererFormattingForegroundColorAttribute];\n\tid backgroundColorNew = stringAttributes[TVCLogRendererFormattingBackgroundColorAttribute];\n\n\tid foregroundColorOld = self->_renderedBodyOpenAttributes[TVCLogRendererFormattingForegroundColorAttribute];\n\tid backgroundColorOld = self->_renderedBodyOpenAttributes[TVCLogRendererFormattingBackgroundColorAttribute];\n\n\tNSString *foregroundColor = nil;\n\tNSString *backgroundColor = nil;\n\n\tBOOL setNewColors = YES;\n\n\tif (foregroundColorOld || backgroundColorOld)\n\t{\n\t\t/* There is no need to open a new HTML segment if the color hasn't changed. */\n\t\tif ([foregroundColorNew isEqual:foregroundColorOld] &&\n\t\t\t [backgroundColorNew isEqual:backgroundColorOld])\n\t\t{\n\t\t\tsetNewColors = NO;\n\t\t} else {\n\t\t\ttemplateTokens[@\"fragmentTextColorClosedAtStart\"] = @(isFirstFragment == NO);\n\t\t\ttemplateTokens[@\"fragmentTextColorClosedAtEnd\"] = @(isLastFragment);\n\t\t}\n\n\t\tif (foregroundColorOld && foregroundColorNew == nil) {\n\t\t\t[self->_renderedBodyOpenAttributes removeObjectForKey:TVCLogRendererFormattingForegroundColorAttribute];\n\t\t}\n\n\t\tif (backgroundColorOld && backgroundColorNew == nil) {\n\t\t\t[self->_renderedBodyOpenAttributes removeObjectForKey:TVCLogRendererFormattingBackgroundColorAttribute];\n\t\t}\n\t}\n\n\tif (setNewColors && foregroundColorNew) {\n\t\tself->_renderedBodyOpenAttributes[TVCLogRendererFormattingForegroundColorAttribute] = foregroundColorNew;\n\n\t\tBOOL usesStyleTag = NO;\n\n\t\tforegroundColor = [self.class stringValueForColor:foregroundColorNew usesStyleTag:&usesStyleTag];\n\n\t\ttemplateTokens[@\"fragmentTextColorOpened\"] = @(YES);\n\t\ttemplateTokens[@\"fragmentForegroundColor\"] = foregroundColor;\n\t\ttemplateTokens[@\"fragmentForegroundColorIsSet\"] = @(YES);\n\t\ttemplateTokens[@\"fragmentTextColorUsesStyleTag\"] = @(usesStyleTag);\n\n\t\t// backwards compatibility\n\t\ttemplateTokens[@\"fragmentTextColorIsSet\"] = @(YES);\n\t\ttemplateTokens[@\"fragmentTextColor\"] = templateTokens[@\"fragmentForegroundColor\"];\n\t}\n\n\tif (setNewColors && backgroundColorNew) {\n\t\tself->_renderedBodyOpenAttributes[TVCLogRendererFormattingBackgroundColorAttribute] = backgroundColorNew;\n\n\t\tBOOL usesStyleTag = NO;\n\n\t\tbackgroundColor =  [self.class stringValueForColor:backgroundColorNew usesStyleTag:&usesStyleTag];\n\n\t\ttemplateTokens[@\"fragmentTextColorOpened\"] = @(YES);\n\t\ttemplateTokens[@\"fragmentBackgroundColor\"] = backgroundColor;\n\t\ttemplateTokens[@\"fragmentBackgroundColorIsSet\"] = @(YES);\n\t\ttemplateTokens[@\"fragmentTextColorUsesStyleTag\"] = @(usesStyleTag);\n\n\t\t// backwards compatibility\n\t\ttemplateTokens[@\"fragmentTextColorIsSet\"] = @(YES);\n\t}\n\n\tif ([self isRenderingPRIVMSG_or_NOTICE]) {\n\t\ttemplateTokens[@\"fragmentIsSpoiler\"] = @(setNewColors && [foregroundColor isEqualToString:backgroundColor]);\n\t} else {\n\t\ttemplateTokens[@\"fragmentIsSpoiler\"] = @(NO);\n\t}\n\n\t// --- //\n\n\t/* Escape spaces that are prefix and suffix characters */\n\tif (escapeBody) {\n\t\tif ([html hasPrefix:@\" \"]) {\n\t\t\thtml = [html stringByReplacingCharactersInRange:NSMakeRange(0, 1)\n\t\t\t\t\t\t\t\t\t\t\t\t withString:@\"&nbsp;\"];\n\t\t}\n\n\t\tif ([html hasSuffix:@\" \"]) {\n\t\t\thtml = [html stringByReplacingCharactersInRange:NSMakeRange((html.length - 1), 1)\n\t\t\t\t\t\t\t\t\t\t\t\t withString:@\"&nbsp;\"];\n\t\t}\n\t}\n\n\t// --- //\n\n\ttemplateTokens[@\"messageFragment\"] = html;\n\n\treturn [self.class renderTemplateNamed:@\"formattedMessageFragment\" attributes:templateTokens];\n}\n\n#pragma mark -\n\n- (void)renderFinalResultsAsHTML\n{\n\tNSMutableString *finalResult = [NSMutableString string];\n\n\tNSString *string = self->_bodyWithAttributes.string;\n\n\tNSUInteger stringLength = string.length;\n\n\t[self->_bodyWithAttributes\n\t enumerateAttributesInRange:NSMakeRange(0, stringLength)\n\t\t\t\t\t\toptions:0\n\t\t\t\t\t usingBlock:^(NSDictionary<NSString *, id> *attributes, NSRange range, BOOL *stop) {\n\t\t BOOL isFirstFragment = (range.location == 0);\n\t\t BOOL isLastFragment = ((range.location + range.length) == stringLength);\n\n\t\t NSString *html = [self renderStringAsHTML:string\n\t\t\t\t\t\t\t\t\twithAttributes:attributes\n\t\t\t\t\t\t\t\t\t\t   inRange:range\n\t\t\t\t\t\t\t\t   isFirstFragment:isFirstFragment\n\t\t\t\t\t\t\t\t\tisLastFragment:isLastFragment];\n\n\t\t if (html) {\n\t\t\t [finalResult appendString:html];\n\t\t }\n\t }];\n\n\tself.finalResult = finalResult;\n}\n\n- (void)renderFinalResultsForAttributedBody\n{\n\tNSMutableAttributedString *finalResult = [self->_bodyWithAttributes mutableCopy];\n\n\tNSString *string = self->_bodyWithAttributes.string;\n\n\t[self->_bodyWithAttributes\n\t\t enumerateAttributesInRange:NSMakeRange(0, string.length)\n\t\t\t\t\t\t\toptions:0\n\t\t\t\t\t\t usingBlock:^(NSDictionary<NSString *, id> *attributes, NSRange range, BOOL *stop) {\n\t\t\t NSDictionary *attributesToAdd = [self appKitAttributesFromRendererAttributes:attributes];\n\n\t\t\t [finalResult addAttributes:attributesToAdd range:range];\n\t\t }];\n\n\tself.finalResult = finalResult;\n}\n\n#pragma mark -\n\n- (void)cleanupResources\n{\n\tself->_body = nil;\n\tself->_bodyWithAttributes = nil;\n\tself->_renderedBodyOpenAttributes = nil;\n\tself->_viewController = nil;\n}\n\n+ (NSString *)renderBody:(NSString *)body forViewController:(TVCLogController *)viewController withAttributes:(NSDictionary<NSString *, id> *)inputDictionary resultInfo:(NSDictionary<NSString *, id> * _Nullable * _Nullable)outputDictionary\n{\n\tNSParameterAssert(body != nil);\n\tNSParameterAssert(viewController != nil);\n\tNSParameterAssert(inputDictionary != nil);\n\n\tif (body.length == 0) {\n\t\treturn @\"\";\n\t}\n\n\tTVCLogLineType lineType = [inputDictionary unsignedIntegerForKey:TVCLogRendererConfigurationLineTypeAttribute];\n\n\tTVCLogLineMemberType memberType = [inputDictionary unsignedIntegerForKey:TVCLogRendererConfigurationMemberTypeAttribute];\n\n\tBOOL escapeBody = ([inputDictionary boolForKey:TVCLogRendererConfigurationDoNotEscapeBodyAttribute] == NO);\n\n\tTVCLogRenderer *renderer = [self new];\n\n\trenderer.body =\n\t[THOPluginDispatcher willRenderMessage:body\n\t\t\t\t\t\t forViewController:viewController\n\t\t\t\t\t\t\t\t  lineType:lineType\n\t\t\t\t\t\t\t\tmemberType:memberType];\n\n\trenderer.lineType = lineType;\n\n\trenderer.memberType = memberType;\n\n\trenderer.escapeBody = escapeBody;\n\n\trenderer.rendererAttributes = inputDictionary;\n\n\trenderer.viewController = viewController;\n\n\t/* Call -stripDangerousUnicodeCharactersFromBody first because it modifies the body. */\n\t[renderer stripDangerousUnicodeCharactersFromBody];\n\n\t[renderer buildEffectsDictionary];\n\n\t[renderer buildListOfLinksInBody];\n\n\t[renderer matchKeywords];\n\n\t[renderer findAllChannelNames];\n\n\t[renderer scanBodyForChannelMembers];\n\n\tif ( outputDictionary) {\n\t\t*outputDictionary = [renderer.outputDictionary copy];\n\t}\n\n\t[renderer renderFinalResultsAsHTML];\n\n\t[renderer cleanupResources];\n\n\treturn renderer.finalResult;\n}\n\n+ (NSAttributedString *)renderBodyAsAttributedString:(NSString *)body withAttributes:(NSDictionary<NSString *, id> *)inputDictionary\n{\n\tNSParameterAssert(body != nil);\n\tNSParameterAssert(inputDictionary != nil);\n\n\tif (body.length == 0) {\n\t\treturn [NSAttributedString attributedString];\n\t}\n\n\tNSFont *defaultFont = inputDictionary[TVCLogRendererConfigurationAttributedStringPreferredFontAttribute];\n\n\tNSAssert((defaultFont != nil),\n\t\t@\"FATAL ERROR: TVCLogRenderer cannot be supplied with a nil 'TVCLogRendererAttributedStringPreferredFontAttribute' attribute when rendering an attributed string\");\n\n\tTVCLogRenderer *renderer = [self new];\n\n\trenderer.body = body;\n\n\trenderer.lineType = [inputDictionary unsignedIntegerForKey:TVCLogRendererConfigurationLineTypeAttribute];\n\n\trenderer.memberType = [inputDictionary unsignedIntegerForKey:TVCLogRendererConfigurationMemberTypeAttribute];\n\n\trenderer.rendererAttributes = inputDictionary;\n\n\t[renderer stripDangerousUnicodeCharactersFromBody];\n\n\t[renderer buildEffectsDictionary];\n\n\t[renderer renderFinalResultsForAttributedBody];\n\n\t[renderer cleanupResources];\n\n\treturn renderer.finalResult;\n}\n\n#pragma mark -\n\n+ (nullable NSString *)renderTemplateNamed:(NSString *)templateName\n{\n\treturn [self renderTemplateNamed:templateName attributes:nil];\n}\n\n+ (nullable NSString *)renderTemplateNamed:(NSString *)templateName attributes:(nullable NSDictionary<NSString *, id> *)templateTokens\n{\n\tNSParameterAssert(templateName != nil);\n\n\tGRMustacheTemplate *template = [theme() templateWithName:templateName];\n\n\tif (template == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self renderTemplate:template attributes:templateTokens];\n}\n\n+ (nullable NSString *)renderTemplate:(GRMustacheTemplate *)template\n{\n\treturn [self renderTemplate:template attributes:nil];\n}\n\n+ (nullable NSString *)renderTemplate:(GRMustacheTemplate *)template attributes:(nullable NSDictionary<NSString *, id> *)templateTokens\n{\n\tNSParameterAssert(template != nil);\n\n\tNSString *templateRender = [template renderObject:templateTokens error:NULL];\n\n\tif (templateRender == nil) {\n\t\treturn nil;\n\t}\n\n\treturn templateRender.removeAllNewlines;\n}\n\n+ (NSString *)escapeHTML:(NSString *)html\n{\n\tNSParameterAssert(html != nil);\n\n\tNSString *stringEscaped = html.gtm_stringByEscapingForHTML;\n\n\tif (stringEscaped == nil) {\n\t\tstringEscaped = @\"\";\n\t}\n\n\treturn stringEscaped;\n}\n\n+ (NSString *)escapeStringSimple:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tstring = [string stringByReplacingOccurrencesOfString:@\"\\t\" withString:@\"&nbsp;&nbsp;&nbsp;&nbsp;\"];\n\tstring = [string stringByReplacingOccurrencesOfString:@\"  \" withString:@\"&nbsp;&nbsp;\"];\n\n\treturn string;\n}\n\n+ (NSString *)escapeString:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tNSString *stringEscaped = [self escapeHTML:string];\n\n\treturn [self escapeStringSimple:stringEscaped];\n}\n\n+ (nullable NSString *)stringValueForColor:(id)color usesStyleTag:(BOOL *)usesStyleTag\n{\n\tNSParameterAssert(color != nil);\n\n\tif ([color isKindOfClass:[NSColor class]])\n\t{\n\t\t*usesStyleTag = YES;\n\n\t\treturn [color hexadecimalValue];\n\t}\n\telse if ([color isKindOfClass:[NSNumber class]])\n\t{\n\t\treturn [color stringValue];\n\t}\n\n\treturn nil;\n}\n\n+ (nullable NSColor *)mapColor:(id)color\n{\n\tNSParameterAssert(color != nil);\n\n\tif ([color isKindOfClass:[NSColor class]])\n\t{\n\t\treturn color;\n\t}\n\telse if ([color isKindOfClass:[NSNumber class]])\n\t{\n\t\treturn [self mapColorCode:[color unsignedIntegerValue]];\n\t}\n\n\treturn nil;\n}\n\n+ (NSColor *)mapColorCode:(NSUInteger)colorCode\n{\n\tNSParameterAssert(colorCode <= IRCTextFormatterEffectColorHighestDigit);\n\n\treturn [NSColor formatterColors][colorCode];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogScriptEventSink.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#include <objc/message.h>\n\n#import \"GTMEncodeHTML.h\"\n#import \"WebScriptObjectHelperPrivate.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"THOPluginManagerPrivate.h\"\n#import \"THOPluginProtocolPrivate.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCUserNicknameColorStyleGeneratorPrivate.h\"\n#import \"IRCWorld.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogPolicyPrivate.h\"\n#import \"TVCLogRenderer.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogViewInternalWK1.h\"\n#import \"TVCLogViewInternalWK2.h\"\n#import \"TVCLogScriptEventSinkPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogScriptEventSink ()\n@property (nonatomic, weak) TVCLogView *webView;\n@end\n\n@interface TVCLogScriptEventSinkContext : NSObject\n@property (nonatomic, weak) TVCLogView *webView;\n@property (readonly) TVCLogPolicy *webViewPolicy;\n@property (readonly) TVCLogController *viewController;\n@property (readonly) IRCClient *associatedClient;\n@property (readonly, nullable) IRCChannel *associatedChannel;\n@property (nonatomic, copy) NSString *caller;\n@property (nonatomic, copy, nullable) NSArray *arguments;\n@property (nonatomic, copy, nullable) void (^completionBlock)(id _Nullable returnValue);\n@end\n\n@implementation TVCLogScriptEventSink\n\n- (instancetype)init\n{\n\treturn [self initWithWebView:nil];\n}\n\n- (instancetype)initWithWebView:(nullable TVCLogView *)webView\n{\n\tif ((self = [super init])) {\n\t\tself.webView = webView;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector\n{\n\tif (selector == @selector(init) ||\n\t\tselector == @selector(initWithWebView:) ||\n\t\tselector == @selector(webView) ||\n\t\tselector == @selector(webViewPolicy) ||\n\t\tselector == @selector(associatedClient) ||\n\t\tselector == @selector(associatedChannel) ||\n\t\tselector == @selector(objectValueToCommon:) ||\n\t\tselector == @selector(userContentController:didReceiveScriptMessage:) ||\n\t\tselector == @selector(processInputData:inWebView:withSelector:) ||\n\t\tselector == @selector(processInputData:inWebView:withSelector:minimumArgumentCount:withValidation:))\n\t{\n\t\treturn YES;\n\t}\n\n\tif ([NSStringFromSelector(selector) hasPrefix:@\"_\"]) {\n\t\treturn NO;\n\t}\n\n\treturn NO;\n}\n\n+ (nullable NSString *)webScriptNameForSelector:(SEL)sel\n{\n\treturn nil;\n}\n\n- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)arguments\n{\n\tSEL handlerSelector = NSSelectorFromString([name stringByAppendingString:@\":inWebView:\"]);\n\n\tif ([self respondsToSelector:handlerSelector] == NO) {\n\t\treturn @(NO);\n\t}\n\n\tid argument = nil;\n\n\tif (arguments && arguments.count > 0) {\n\t\targument = arguments[0];\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\tif ([argument isKindOfClass:[WebScriptObject class]]) {\n\t\t\targument = [self.webView webScriptObjectToCommon:argument];\n\t\t}\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\t}\n\n\tNSMethodSignature *signature = [self methodSignatureForSelector:handlerSelector];\n\n\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t[invocation setTarget:self];\n\n\t[invocation setSelector:handlerSelector];\n\t[invocation setArgument:&argument atIndex:2];\n\n\tTVCLogView *webView = self.webView;\n\t[invocation setArgument:&webView atIndex:3];\n\n\t[invocation invoke];\n\n\treturn @(YES);\n}\n\n+ (BOOL)isKeyExcludedFromWebScript:(const char *)name\n{\n\treturn YES;\n}\n\n+ (nullable NSString *)webScriptNameForKey:(const char *)name\n{\n\treturn nil;\n}\n\n+ (nullable id)objectValueToCommon:(id)object\n{\n\tif ([object isKindOfClass:[NSNull class]] ||\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\t[object isKindOfClass:[WebUndefined class]])\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\t{\n\t\treturn nil;\n\t}\n\n\tif ([object isKindOfClass:[NSString class]]) {\n\t\treturn [object gtm_stringByUnescapingFromHTML];\n\t}\n\n\treturn object;\n}\n\n+ (NSString *)standardizeLineNumber:(NSString *)lineNumber\n{\n\tNSParameterAssert(lineNumber != nil);\n\n\tif ([lineNumber hasPrefix:@\"line-\"]) {\n\t\treturn [lineNumber substringFromIndex:5];\n\t}\n\n\treturn lineNumber;\n}\n\n+ (NSArray<NSString *> *)standardizeLineNumbers:(NSArray<NSString *> *)lineNumbers\n{\n\tNSParameterAssert(lineNumbers != nil);\n\n\tNSMutableArray<NSString *> *lineNumbersOut = [NSMutableArray arrayWithCapacity:lineNumbers.count];\n\n\tfor (NSString *lineNumber in lineNumbers) {\n\t\t[lineNumbersOut addObject:\n\t\t [self standardizeLineNumber:lineNumber]];\n\t}\n\n\treturn [lineNumbersOut copy];\n}\n\n- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message\n{\n\tNSString *handlerName = message.name;\n\n\tSEL handlerSelector = NSSelectorFromString([handlerName stringByAppendingString:@\":inWebView:\"]);\n\n\tif ([self respondsToSelector:handlerSelector] == NO) {\n\t\treturn;\n\t}\n\n\tif ([self.class isSelectorExcludedFromWebScript:handlerSelector]) {\n\t\treturn;\n\t}\n\n\tNSMethodSignature *signature = [self methodSignatureForSelector:handlerSelector];\n\n\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t[invocation setTarget:self];\n\t[invocation setSelector:handlerSelector];\n\n\tid body = message.body;\n\t[invocation setArgument:&body atIndex:2];\n\n\tWKWebView *webView = message.webView;\n\t[invocation setArgument:&webView atIndex:3];\n\n\t[invocation invoke];\n}\n\n- (void)processInputData:(id)inputData\n\t\t\t   forCaller:(NSString *)caller\n\t\t\t   inWebView:(id)webView\n\t\t\twithSelector:(SEL)selector\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:caller\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:selector\n\t  minimumArgumentCount:0\n\t\t\twithValidation:nil];\n}\n\n- (void)processInputData:(id)inputData\n\t\t\t   forCaller:(NSString *)caller\n\t\t\t   inWebView:(id)webView\n\t\t\twithSelector:(SEL)selector\n\tminimumArgumentCount:(NSUInteger)minimumArgumentCount\n\t\t  withValidation:(BOOL (NS_NOESCAPE ^ _Nullable)(NSUInteger argumentIndex, id argument))validateArgumentBlock\n{\n\tTVCLogView *intWebView = nil;\n\n\tif ([webView isKindOfClass:[TVCLogView class]]) {\n\t\tintWebView = webView;\n\t} else if ([webView isKindOfClass:[TVCLogViewInternalWK1 class]] ||\n\t\t\t   [webView isKindOfClass:[TVCLogViewInternalWK2 class]])\n\t{\n\t\tintWebView = [webView t_parentView];\n\t} else {\n\t\treturn;\n\t}\n\n\t/* -t_parentView in TVCLogViewInternalWK2 is maintained\n\t as a weak reference. That means that a race condition for\n\t WebKit2 is possible. A script event is received, is invoked\n\t on this function, and while it is waiting to be invoked,\n\t another thread deconstructs the parent view. */\n\tif (intWebView == nil) {\n\t\tLogToConsoleFault(\"(intWebView == nil) condition faulted. \\\n\t\t\t\t\t\t  Possible race condition. \\\n\t\t\t\t\t\t  Invoking '%{public}@'\", NSStringFromSelector(selector));\n\n\t\treturn;\n\t}\n\n\tNSInteger promiseIndex = (-1);\n\n\tNSArray *values = nil;\n\n\t/* Extract relevant information from inputData */\n\tif ([inputData isKindOfClass:[NSDictionary class]]) {\n\t\t/* Check that the object exists in the dictionary before\n\t\t setting the value. If the object does not exist and we\n\t\t do not do this, then -integerValue will return 0 which\n\t\t is considered a valid promiseIndex value. */\n\t\tid promiseIndexObj = [inputData valueForKey:@\"promiseIndex\"];\n\n\t\tif (promiseIndexObj) {\n\t\t\tif ([promiseIndexObj isKindOfClass:[NSNumber class]] == NO) {\n\t\t\t\t[self.class throwJavaScriptException:@\"'promiseIndex' must be a number\"\n\t\t\t\t\t\t\t\t\t\t   forCaller:caller\n\t\t\t\t\t\t\t\t\t\t   inWebView:intWebView];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpromiseIndex = [promiseIndexObj integerValue];\n\t\t}\n\n\t\t/* Values should always be in an array */\n\t\tif (minimumArgumentCount > 0) {\n\t\t\tid valuesObj = [inputData valueForKey:@\"values\"];\n\n\t\t\tif (valuesObj == nil || [valuesObj isKindOfClass:[NSArray class]] == NO) {\n\t\t\t\t[self.class throwJavaScriptException:@\"'values' must be an array\"\n\t\t\t\t\t\t\t\t\t\t   forCaller:caller\n\t\t\t\t\t\t\t\t\t\t   inWebView:intWebView];\n\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tvalues = valuesObj;\n\t\t\t}\n\t\t}\n\t}\n\telse if ([inputData isKindOfClass:[NSString class]] ||\n\t\t\t [inputData isKindOfClass:[NSNumber class]])\n\t{\n\t\tif (minimumArgumentCount > 0) {\n\t\t\tvalues = @[inputData];\n\t\t}\n\t}\n\telse if ([inputData isKindOfClass:[NSArray class]])\n\t{\n\t\tif (minimumArgumentCount > 0) {\n\t\t\tvalues = inputData;\n\t\t}\n\t}\n\telse if ([inputData isKindOfClass:[NSNull class]] ||\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\t\t [inputData isKindOfClass:[WebUndefined class]])\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\t{\n\t\tif (minimumArgumentCount > 0) {\n\t\t\tvalues = @[[NSNull null]];\n\t\t}\n\t}\n\n\t/* Perform validation if needed */\n\tif (minimumArgumentCount > 0 && values.count < minimumArgumentCount) {\n\t\t[self.class throwJavaScriptException:@\"Minimum number of arguments (%lu) condition not met\"\n\t\t\t\t\t\t\t\t   forCaller:caller\n\t\t\t\t\t\t\t\t   inWebView:intWebView, minimumArgumentCount];\n\n\t\treturn;\n\t}\n\n\tif (validateArgumentBlock) {\n\t\t__block BOOL validationPassed = YES;\n\n\t\t[values enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {\n\t\t\tif (validateArgumentBlock(index, object) == NO) {\n\t\t\t\tvalidationPassed = NO;\n\n\t\t\t\t*stop = YES;\n\t\t\t}\n\t\t}];\n\n\t\tif (validationPassed == NO) {\n\t\t\t[self.class throwJavaScriptException:@\"Invalid argument type(s)\"\n\t\t\t\t\t\t\t\t\t   forCaller:caller\n\t\t\t\t\t\t\t\t\t   inWebView:intWebView];\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Pass validated data to selector */\n\tTVCLogScriptEventSinkContext *context = [TVCLogScriptEventSinkContext new];\n\n\tcontext.webView = intWebView;\n\n\tcontext.caller = caller;\n\n\tcontext.arguments = values;\n\n\tvoid (^completionBlock)(id) = nil;\n\n\tif (promiseIndex >= 0) {\n\t\t__weak typeof(intWebView) intWebViewWeak = intWebView;\n\n\t\tcompletionBlock = ^(id _Nullable returnValue) {\n\t\t\tif (returnValue == nil) {\n\t\t\t\treturnValue = [NSNull null];\n\t\t\t}\n\n\t\t\t[intWebViewWeak evaluateFunction:@\"appInternal.promiseKept\"\n\t\t\t\t\t\t\t   withArguments:@[@(promiseIndex), returnValue]];\n\t\t};\n\t}\n\n\tcontext.completionBlock = completionBlock;\n\n\tNSMethodSignature *signature = [self methodSignatureForSelector:selector];\n\n\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t[invocation setTarget:self];\n\t[invocation setSelector:selector];\n\n\t[invocation setArgument:&context atIndex:2];\n\n\t[invocation invoke];\n}\n\n+ (void)logToJavaScriptConsole:(NSString *)message inWebView:(TVCLogView *)webView, ...\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(webView != nil);\n\t\n\tva_list arguments;\n\tva_start(arguments, webView);\n\n\t[self logToJavaScriptConsole:message inWebView:webView withArguments:arguments];\n\t\n\tva_end(arguments);\n}\n\n+ (void)logToJavaScriptConsole:(NSString *)message inWebView:(TVCLogView *)webView withArguments:(va_list)arguments\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(webView != nil);\n\tNSParameterAssert(arguments != NULL);\n\n\tNSString *messageFormatted = [[NSString alloc] initWithFormat:message arguments:arguments];\n\n\t[webView evaluateFunction:@\"console.log\" withArguments:@[messageFormatted]];\n}\n\n+ (void)throwJavaScriptException:(NSString *)message inWebView:(TVCLogView *)webView, ...\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(webView != nil);\n\n\tva_list arguments;\n\tva_start(arguments, webView);\n\t\n\t[self throwJavaScriptException:message\n\t\t\t\t\t\t forCaller:nil\n\t\t\t\t\t\t inWebView:webView\n\t\t\t\t\t withArguments:arguments];\n\t\n\tva_end(arguments);\n}\n\n+ (void)throwJavaScriptException:(NSString *)message forCaller:(nullable NSString *)caller inWebView:(TVCLogView *)webView, ...\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(webView != nil);\n\n\tva_list arguments;\n\tva_start(arguments, webView);\n\t\n\t[self throwJavaScriptException:message\n\t\t\t\t\t\t forCaller:caller\n\t\t\t\t\t\t inWebView:webView\n\t\t\t\t\t withArguments:arguments];\n\t\n\tva_end(arguments);\n}\n\n+ (void)throwJavaScriptException:(NSString *)message forCaller:(nullable NSString *)caller inWebView:(TVCLogView *)webView withArguments:(va_list)arguments\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(webView != nil);\n\tNSParameterAssert(arguments != NULL);\n\n\tNSString *messageFormatted = [[NSString alloc] initWithFormat:message arguments:arguments];\n\n\tif (caller) {\n\t\tmessageFormatted = [NSString stringWithFormat:@\"Bridged function %@ returned error: %@\", caller, messageFormatted];\n\t}\n\n\t[webView evaluateFunction:@\"console.error\" withArguments:@[messageFormatted]];\n}\n\n#pragma mark -\n#pragma mark Private Implementation\n\n- (void)channelIsActive:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.channelIsActive()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_channelIsActive:)];\n}\n\n- (void)channelMemberCount:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.channelMemberCount()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_channelMemberCount:)];\n}\n\n- (void)channelName:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.channelName()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_channelName:)];\n}\n\n- (void)channelNameDoubleClicked:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.channelNameDoubleClicked()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_channelNameDoubleClicked:)];\n}\n\n- (void)displayContextMenu:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.displayContextMenu()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_displayContextMenu:)];\n}\n\n- (void)copySelectionWhenPermitted:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.copySelectionWhenPermitted()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_copySelectionWhenPermitted:)];\n}\n\n- (void)encryptionAuthenticateUser:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.encryptionAuthenticateUser()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_encryptionAuthenticateUser:)];\n}\n\n- (void)inlineMediaEnabledForView:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.inlineMediaEnabledForView()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_inlineMediaEnabledForView:)];\n}\n\n- (void)loadInlineMedia:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.loadInlineMedia()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_loadInlineMedia:)\n\t  minimumArgumentCount:4\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex <= 2) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else {\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\t\t\t}];\n}\n\n- (void)localUserHostmask:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.localUserHostmask()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_localUserHostmask:)];\n}\n\n- (void)localUserNickname:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.localUserNickname()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_localUserNickname:)];\n}\n\n- (void)logToConsole:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.logToConsole()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_logToConsole:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)networkName:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.networkName()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_networkName:)];\n}\n\n- (void)nicknameColorStyleHash:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.nicknameColorStyleHash()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_nicknameColorStyleHash:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)nicknameDoubleClicked:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.nicknameDoubleClicked()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_nicknameDoubleClicked:)];\n}\n\n- (void)notifyJumpToLineCallback:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.notifyJumpToLineCallback()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_notifyJumpToLineCallback:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 1 ||\n\t\t\t\t\t\t   argumentIndex == 2)\n\t\t\t\t{\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)notifyLinesAddedToView:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.notifyLinesAddedToView()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_notifyLinesAddedToView:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSArray class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)notifyLinesRemovedFromView:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.notifyLinesRemovedFromView()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_notifyLinesRemovedFromView:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSArray class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)printDebugInformation:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.printDebugInformation()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_printDebugInformation:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)printDebugInformationToConsole:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.printDebugInformationToConsole()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_printDebugInformationToConsole:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)renderMessagesBefore:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.renderMessagesBefore()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_renderMessagesBefore:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 1) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)renderMessagesAfter:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.renderMessagesAfter()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_renderMessagesAfter:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 1) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)renderMessagesInRange:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.renderMessagesInRange()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_renderMessagesInRange:)\n\t  minimumArgumentCount:3\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0 ||\n\t\t\t\t\targumentIndex == 1)\n\t\t\t\t{\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 2) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)renderMessageWithSiblings:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.renderMessageWithSiblings()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_renderMessageWithSiblings:)\n\t  minimumArgumentCount:3\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 1 ||\n\t\t\t\t\t\t   argumentIndex == 2)\n\t\t\t\t{\n\t\t\t\t\treturn [argument isKindOfClass:[NSNumber class]];\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)retrievePreferencesWithMethodName:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.retrievePreferencesWithMethodName()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_retrievePreferencesWithMethodName:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)renderTemplate:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.renderTemplate()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_renderTemplate:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else if (argumentIndex == 1) {\n\t\t\t\t\treturn ([argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t\t[argument isKindOfClass:[NSDictionary class]]);\n\t\t\t\t}\n\n\t\t\t\treturn NO;\n\t\t\t}];\n}\n\n- (void)sendPluginPayload:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.sendPluginPayload()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_sendPluginPayload:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else {\n\t\t\t\t\treturn YES;\n\t\t\t\t}\n\t\t\t}];\n}\n\n- (void)serverAddress:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.serverAddress()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_serverAddress:)];\n}\n\n- (void)serverChannelCount:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.serverChannelCount()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_serverChannelCount:)];\n}\n\n- (void)serverIsConnected:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.serverIsConnected()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_serverIsConnected:)];\n}\n\n- (void)setAutomaticScrollingEnabled:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.setAutomaticScrollingEnabled()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_setAutomaticScrollingEnabled:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSNumber class]]);\n\t\t\t}];\n}\n\n- (void)setChannelName:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.setChannelName()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_setChannelName:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)setNickname:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.setNickname()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_setNickname:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)setSelection:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.setSelection()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_setSelection:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)setURLAddress:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.setURLAddress()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_setURLAddress:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn ([argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t}];\n}\n\n- (void)sidebarInversionIsEnabled:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.sidebarInversionIsEnabled()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_sidebarInversionIsEnabled:)];\n}\n\n- (void)appearance:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.appearance()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_appearance:)];\n}\n\n- (void)styleSettingsRetrieveValue:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.styleSettingsRetrieveValue()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_styleSettingsRetrieveValue:)\n\t  minimumArgumentCount:1\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t}];\n}\n\n- (void)styleSettingsSetValue:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.styleSettingsSetValue()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_styleSettingsSetValue:)\n\t  minimumArgumentCount:2\n\t\t\twithValidation:^BOOL(NSUInteger argumentIndex, id argument) {\n\t\t\t\tif (argumentIndex == 0) {\n\t\t\t\t\treturn [argument isKindOfClass:[NSString class]];\n\t\t\t\t} else {\n\t\t\t\t\treturn ([argument isKindOfClass:[NSArray class]] ||\n\t\t\t\t\t\t\t[argument isKindOfClass:[NSDictionary class]] ||\n\t\t\t\t\t\t\t[argument isKindOfClass:[NSNull class]] ||\n\t\t\t\t\t\t\t[argument isKindOfClass:[NSNumber class]] ||\n\t\t\t\t\t\t\t[argument isKindOfClass:[NSString class]]);\n\t\t\t\t}\n\t\t\t}];\n}\n\n- (void)topicBarDoubleClicked:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.topicBarDoubleClicked()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_topicBarDoubleClicked:)];\n}\n\n- (void)finishedLayingOutView:(id)inputData inWebView:(id)webView\n{\n\t[self processInputData:inputData\n\t\t\t\t forCaller:@\"app.finishedLayingOutView()\"\n\t\t\t\t inWebView:webView\n\t\t\t  withSelector:@selector(_finishedLayingOutView:)];\n}\n\n#pragma mark -\n#pragma mark Private Implementation\n\n- (void)_channelIsActive:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( @(context.associatedChannel.isActive) );\n}\n\n- (void)_channelMemberCount:(TVCLogScriptEventSinkContext *)context\n{\n\tIRCChannel *channel = context.associatedChannel;\n\n\tif (channel == nil || channel.isChannel == NO) {\n\t\t[self.class throwJavaScriptException:@\"View is not a channel\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tcontext.completionBlock( @(channel.numberOfMembers) );\n}\n\n- (void)_channelName:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( context.associatedChannel.name );\n}\n\n- (void)_channelNameDoubleClicked:(TVCLogScriptEventSinkContext *)context\n{\n\t[context.webViewPolicy channelNameDoubleClicked];\n}\n\n- (void)_displayContextMenu:(TVCLogScriptEventSinkContext *)context\n{\n\t[context.webViewPolicy displayContextMenuInWebView:context.webView];\n}\n\n- (void)_copySelectionWhenPermitted:(TVCLogScriptEventSinkContext *)context\n{\n\tif ([TPCPreferences copyOnSelect]) {\n\t\tNSString *selection = context.webView.selection;\n\n\t\tif (selection) {\n\t\t\tRZPasteboard().stringContent = selection;\n\n\t\t\tcontext.completionBlock( @(YES) );\n\t\t}\n\t}\n\n\tcontext.completionBlock( @(NO) );\n}\n\n- (void)_encryptionAuthenticateUser:(TVCLogScriptEventSinkContext *)context\n{\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tIRCClient *client = context.associatedClient;\n\n\tif (client.isLoggedIn == NO) {\n\t\treturn;\n\t}\n\n\tIRCChannel *channel = context.associatedChannel;\n\n\tif (channel == nil || channel.isPrivateMessage == NO) {\n\t\t[self.class throwJavaScriptException:@\"View is not a private message\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\t[client encryptionAuthenticateUser:channel.name];\n#endif\n}\n\n- (void)_inlineMediaEnabledForView:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( @(context.viewController.inlineMediaEnabledForView) );\n}\n\n- (void)_loadInlineMedia:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *address = [self.class objectValueToCommon:arguments[0]];\n\n\tif (address.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of address is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tNSString *uniqueIdentifier = [self.class objectValueToCommon:arguments[1]];\n\n\tif (uniqueIdentifier.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of unique identifier is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tNSString *lineNumber = [self.class objectValueToCommon:arguments[2]];\n\n\tlineNumber = [self.class standardizeLineNumber:lineNumber];\n\n\tif (lineNumber.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of line number is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tNSNumber *index = [self.class objectValueToCommon:arguments[3]];\n\n\t[context.viewController processInlineMediaAtAddress:address\n\t\t\t\t\t\t\t\t   withUniqueIdentifier:uniqueIdentifier\n\t\t\t\t\t\t\t\t\t\t   atLineNumber:lineNumber\n\t\t\t\t\t\t\t\t\t\t\t\t  index:index.unsignedIntegerValue];\n}\n\n- (void)_localUserHostmask:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( context.associatedClient.userHostmask );\n}\n\n- (void)_localUserNickname:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( context.associatedClient.userNickname );\n}\n\n- (void)_logToConsole:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *message = [self.class objectValueToCommon:arguments[0]];\n\n\tLogToConsole(\"JavaScript: %{public}@\", message);\n}\n\n- (void)_networkName:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( context.associatedClient.networkName );\n}\n\n- (void)_nicknameColorStyleHash:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *inputString = [self.class objectValueToCommon:arguments[0]];\n\n\tNSString *colorStyle = [self.class objectValueToCommon:arguments[1]];\n\n\tTPCThemeSettingsNicknameColorStyle colorStyleEnum;\n\n\tif ([colorStyle isEqualToString:@\"HSL-dark\"]) {\n\t\tcolorStyleEnum = TPCThemeSettingsNicknameColorStyleDark;\n\t} else if ([colorStyle isEqualToString:@\"HSL-light\"]) {\n\t\tcolorStyleEnum = TPCThemeSettingsNicknameColorStyleLight;\n\t} else {\n\t\t[self.class throwJavaScriptException:@\"Invalid style\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tcontext.completionBlock( [IRCUserNicknameColorStyleGenerator hashForString:inputString colorStyle:colorStyleEnum] );\n}\n\n- (void)_nicknameDoubleClicked:(TVCLogScriptEventSinkContext *)context\n{\n\t[context.webViewPolicy nicknameDoubleClicked];\n}\n\n- (void)_notifyJumpToLineCallback:(TVCLogScriptEventSinkContext *)context\n{\n\tvoid (^contextCompletionBlock)(id _Nullable) = context.completionBlock;\n\n\tNSArray *arguments = context.arguments;\n\n\tNSString *lineNumber = [self.class objectValueToCommon:arguments[0]];\n\n\tlineNumber = [self.class standardizeLineNumber:lineNumber];\n\n\tif (lineNumber.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of line number is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tBOOL successful = [[self.class objectValueToCommon:arguments[1]] boolValue];\n\n\tBOOL scrolledToBottom = [[self.class objectValueToCommon:arguments[2]] boolValue];\n\n\t[context.viewController notifyJumpToLine:lineNumber successful:successful scrolledToBottom:scrolledToBottom];\n}\n\n- (void)_notifyLinesAddedToView:(TVCLogScriptEventSinkContext *)context\n{\n\t[self _notifyLinesAdded:YES context:context];\n}\n\n- (void)_notifyLinesRemovedFromView:(TVCLogScriptEventSinkContext *)context\n{\n\t[self _notifyLinesAdded:NO context:context];\n}\n\n- (void)_notifyLinesAdded:(BOOL)added context:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tid lineNumbersUncut = [self.class objectValueToCommon:arguments[0]];\n\n\tif ([lineNumbersUncut isKindOfClass:[NSString class]]) {\n\t\tlineNumbersUncut = @[lineNumbersUncut];\n\t}\n\n\tNSArray *lineNumbers = [self.class standardizeLineNumbers:lineNumbersUncut];\n\n\tif (added) {\n\t\t[context.viewController notifyLinesAddedToView:[lineNumbers copy]];\n\t} else {\n\t\t[context.viewController notifyLinesRemovedFromView:[lineNumbers copy]];\n\t}\n}\n\n- (void)_printDebugInformation:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *message = [self.class objectValueToCommon:arguments[0]];\n\n\t[context.associatedClient printDebugInformation:message inChannel:context.associatedChannel];\n}\n\n- (void)_printDebugInformationToConsole:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *message = [self.class objectValueToCommon:arguments[0]];\n\n\t[context.associatedClient printDebugInformationToConsole:message];\n}\n\n- (void)_renderMessagesBefore:(TVCLogScriptEventSinkContext *)context\n{\n\t[self _renderMessagesAfter:NO context:context];\n}\n\n- (void)_renderMessagesAfter:(TVCLogScriptEventSinkContext *)context\n{\n\t[self _renderMessagesAfter:YES context:context];\n}\n\n- (void)_renderMessagesAfter:(BOOL)after context:(TVCLogScriptEventSinkContext *)context\n{\n\tvoid (^contextCompletionBlock)(id _Nullable) = context.completionBlock;\n\n\tNSArray *arguments = context.arguments;\n\n\tNSString *lineNumber = [self.class objectValueToCommon:arguments[0]];\n\n\tlineNumber = [self.class standardizeLineNumber:lineNumber];\n\n\tif (lineNumber.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of line number is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tNSInteger maximumNumberOfLines = [[self.class objectValueToCommon:arguments[1]] integerValue];\n\n\tif (maximumNumberOfLines <= 0) {\n\t\t[self.class throwJavaScriptException:@\"Maximum number of lines must be equal to 1 or greater\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tvoid (^renderCompletionBlock)(NSArray *) = ^(NSArray<NSDictionary<NSString *, id> *> *renderedLogLines) {\n\t\tcontextCompletionBlock(renderedLogLines);\n\t};\n\n\tif (after == NO) {\n\t\t[context.viewController renderLogLinesBeforeLineNumber:lineNumber\n\t\t\t\t\t\t\t\t\t\t  maximumNumberOfLines:maximumNumberOfLines\n\t\t\t\t\t\t\t\t\t\t\t   completionBlock:renderCompletionBlock];\n\t} else {\n\t\t[context.viewController renderLogLinesAfterLineNumber:lineNumber\n\t\t\t\t\t\t\t\t\t\t maximumNumberOfLines:maximumNumberOfLines\n\t\t\t\t\t\t\t\t\t\t\t  completionBlock:renderCompletionBlock];\n\t}\n}\n\n- (void)_renderMessagesInRange:(TVCLogScriptEventSinkContext *)context\n{\n\tvoid (^contextCompletionBlock)(id _Nullable) = context.completionBlock;\n\n\tNSArray *arguments = context.arguments;\n\n\tNSString *lineNumberAfter = [self.class objectValueToCommon:arguments[0]];\n\tNSString *lineNumberBefore = [self.class objectValueToCommon:arguments[1]];\n\n\tlineNumberAfter = [self.class standardizeLineNumber:lineNumberAfter];\n\tlineNumberBefore = [self.class standardizeLineNumber:lineNumberBefore];\n\n\tif (lineNumberAfter.length == 0 ||\n\t\tlineNumberBefore.length == 0)\n\t{\n\t\t[self.class throwJavaScriptException:@\"Length of line number is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tNSInteger maximumNumberOfLines = [[self.class objectValueToCommon:arguments[2]] integerValue];\n\n\tif (maximumNumberOfLines < 0) {\n\t\t[self.class throwJavaScriptException:@\"Maximum number of lines must be equal to 0 or greater\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tvoid (^renderCompletionBlock)(NSArray *) = ^(NSArray<NSDictionary<NSString *, id> *> *renderedLogLines) {\n\t\tcontextCompletionBlock(renderedLogLines);\n\t};\n\n\t[context.viewController renderLogLinesAfterLineNumber:lineNumberAfter\n\t\t\t\t\t\t\t\t\t\t beforeLineNumber:lineNumberBefore\n\t\t\t\t\t\t\t\t\t maximumNumberOfLines:maximumNumberOfLines\n\t\t\t\t\t\t\t\t\t\t  completionBlock:renderCompletionBlock];\n}\n\n- (void)_renderMessageWithSiblings:(TVCLogScriptEventSinkContext *)context\n{\n\tvoid (^contextCompletionBlock)(id _Nullable) = context.completionBlock;\n\n\tNSArray *arguments = context.arguments;\n\n\tNSString *lineNumber = [self.class objectValueToCommon:arguments[0]];\n\n\tlineNumber = [self.class standardizeLineNumber:lineNumber];\n\n\tif (lineNumber.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of line number is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tNSInteger numberOfLinesBefore = [[self.class objectValueToCommon:arguments[1]] integerValue];\n\tNSInteger numberOfLinesAfter = [[self.class objectValueToCommon:arguments[2]] integerValue];\n\n\tif (numberOfLinesBefore < 0 ||\n\t\tnumberOfLinesAfter < 0)\n\t{\n\t\t[self.class throwJavaScriptException:@\"Number of lines must be equal to 0 or greater\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontextCompletionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tvoid (^renderCompletionBlock)(NSArray *) = ^(NSArray<NSDictionary<NSString *, id> *> *renderedLogLines) {\n\t\tcontextCompletionBlock(renderedLogLines);\n\t};\n\n\t[context.viewController renderLogLineAtLineNumber:lineNumber\n\t\t\t\t\t\t\t\t  numberOfLinesBefore:numberOfLinesBefore\n\t\t\t\t\t\t\t\t   numberOfLinesAfter:numberOfLinesAfter\n\t\t\t\t\t\t\t\t\t  completionBlock:renderCompletionBlock];\n}\n\n- (void)_renderTemplate:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *templateName = [self.class objectValueToCommon:arguments[0]];\n\n\tif (templateName.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of template name is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontext.completionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tNSDictionary *templateAttributes = [self.class objectValueToCommon:arguments[1]];\n\n\tNSString *renderedTemplate = [TVCLogRenderer renderTemplateNamed:templateName attributes:templateAttributes];\n\n\tcontext.completionBlock( renderedTemplate );\n}\n\n- (void)_retrievePreferencesWithMethodName:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *methodName = [self.class objectValueToCommon:arguments[0]];\n\n\tSEL methodSelector = NSSelectorFromString(methodName);\n\n\tNSMethodSignature *methodSignature =\n\t[TPCPreferences methodSignatureForSelector:methodSelector];\n\n\tif (methodSignature == nil) {\n\t\t[self.class throwJavaScriptException:@\"Unknown method named: '%@'\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontext.completionBlock(nil);\n\n\t\treturn;\n\t} else if (strcmp(methodSignature.methodReturnType, @encode(void)) == 0) {\n\t\t[self.class throwJavaScriptException:@\"Method named '%@' does not return a value\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\tcontext.completionBlock(nil);\n\n\t\treturn;\n\t}\n\n\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];\n\n\tinvocation.target = [TPCPreferences class];\n\n\tinvocation.selector = methodSelector;\n\n\t[invocation invoke];\n\n\tvoid *returnValue;\n\n\t[invocation getReturnValue:&returnValue];\n\n\tcontext.completionBlock( [NSValue valueWithPrimitive:returnValue withType:methodSignature.methodReturnType] );\n}\n\n- (void)_sendPluginPayload:(TVCLogScriptEventSinkContext *)context\n{\n\tif ([sharedPluginManager() supportsFeature:THOPluginItemSupportedFeatureWebViewJavaScriptPayloads] == NO) {\n\t\t[self.class throwJavaScriptException:@\"There are no plugins loaded that support JavaScript payloads\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tNSArray *arguments = context.arguments;\n\n\tNSString *payloadLabel = [self.class objectValueToCommon:arguments[0]];\n\n\tif (payloadLabel.length == 0) {\n\t\t[self.class throwJavaScriptException:@\"Length of payload label is 0\"\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\n\t\treturn;\n\t}\n\n\tid payloadContents = [self.class objectValueToCommon:arguments[1]];\n\n\tTHOPluginWebViewJavaScriptPayloadConcreteObject *payloadObject =\n\t[THOPluginWebViewJavaScriptPayloadConcreteObject new];\n\n\tpayloadObject.payloadLabel = payloadLabel;\n\tpayloadObject.payloadContents = payloadContents;\n\n\t[THOPluginDispatcher didReceiveJavaScriptPayload:payloadObject fromViewController:context.viewController];\n}\n\n- (void)_serverAddress:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( context.associatedClient.serverAddress );\n}\n\n- (void)_serverChannelCount:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( @(context.associatedClient.channelCount) );\n}\n\n- (void)_serverIsConnected:(TVCLogScriptEventSinkContext *)context\n{\n\tcontext.completionBlock( @(context.associatedClient.isLoggedIn) );\n}\n\n- (void)_setAutomaticScrollingEnabled:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tBOOL enabled = [[self.class objectValueToCommon:arguments[0]] boolValue];\n\n\t[context.webView setAutomaticScrollingEnabled:enabled];\n}\n\n- (void)_setChannelName:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *value = [self.class objectValueToCommon:arguments[0]];\n\n\tcontext.webViewPolicy.channelName = value;\n}\n\n- (void)_setNickname:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *value = [self.class objectValueToCommon:arguments[0]];\n\n\tcontext.webViewPolicy.nickname = value;\n}\n\n- (void)_setSelection:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *selection = [self.class objectValueToCommon:arguments[0]];\n\n\tif (selection && selection.length == 0) {\n\t\tselection = nil;\n\t}\n\n\tcontext.webView.selection = selection;\n}\n\n- (void)_setURLAddress:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *value = [self.class objectValueToCommon:arguments[0]];\n\n\tcontext.webViewPolicy.anchorURL = value;\n}\n\n- (void)_sidebarInversionIsEnabled:(TVCLogScriptEventSinkContext *)context\n{\n\tTVCMainWindowAppearance *appearance = context.viewController.attachedWindow.userInterfaceObjects;\n\n\tcontext.completionBlock( @(appearance.isDarkAppearance) );\n}\n\n- (void)_appearance:(TVCLogScriptEventSinkContext *)context\n{\n\tTVCMainWindowAppearance *appearance = context.viewController.attachedWindow.userInterfaceObjects;\n\n\tcontext.completionBlock( appearance.shortAppearanceDescription );\n}\n\n- (void)_styleSettingsRetrieveValue:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *keyName = [self.class objectValueToCommon:arguments[0]];\n\n\tNSString *errorValue = nil;\n\n\tid result = [themeSettings() styleSettingsRetrieveValueForKey:keyName error:&errorValue];\n\n\tif (errorValue) {\n\t\t[self.class throwJavaScriptException:errorValue\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\t}\n\n\tcontext.completionBlock( result );\n}\n\n- (void)_styleSettingsSetValue:(TVCLogScriptEventSinkContext *)context\n{\n\tNSArray *arguments = context.arguments;\n\n\tNSString *keyName = [self.class objectValueToCommon:arguments[0]];\n\n\tid keyValue = [self.class objectValueToCommon:arguments[1]];\n\n\tNSString *errorValue = nil;\n\t\n\tBOOL result = [themeSettings() styleSettingsSetValue:keyValue forKey:keyName error:&errorValue];\n\n\tif (errorValue) {\n\t\t[self.class throwJavaScriptException:errorValue\n\t\t\t\t\t\t\t\t   forCaller:context.caller\n\t\t\t\t\t\t\t\t   inWebView:context.webView];\n\t}\n\n\tif (result) {\n\t\t[worldController() evaluateFunctionOnAllViews:@\"Textual.styleSettingDidChange\" arguments:@[keyName]];\n\t}\n\n\tcontext.completionBlock( @(result) );\n}\n\n- (void)_topicBarDoubleClicked:(TVCLogScriptEventSinkContext *)context\n{\n\t[context.webViewPolicy topicBarDoubleClicked];\n}\n\n- (void)_finishedLayingOutView:(TVCLogScriptEventSinkContext *)context\n{\n\t[context.webView setViewFinishedLayout];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogScriptEventSinkContext\n\n- (TVCLogController *)viewController\n{\n\treturn self.webView.viewController;\n}\n\n- (TVCLogPolicy *)webViewPolicy\n{\n\treturn self.webView.webViewPolicy;\n}\n\n- (IRCClient *)associatedClient\n{\n\treturn self.viewController.associatedClient;\n}\n\n- (nullable IRCChannel *)associatedChannel\n{\n\treturn self.viewController.associatedChannel;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCThemeControllerPrivate.h\"\n#import \"TPCPathInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogScriptEventSinkPrivate.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogViewInternalWK1.h\"\n#import \"TVCLogViewInternalWK2.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"WebScriptObjectHelperPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogView ()\n@property (nonatomic, strong) id webViewBacking;\n@property (nonatomic, readwrite, assign) BOOL isUsingWebKit2;\n@property (nonatomic, getter=isLayingOutView, readwrite) BOOL layingOutView;\n@end\n\n@implementation TVCLogView\n\nNSString * const TVCLogViewCommonUserAgentString = @\"Textual/1.0 (+https://help.codeux.com/textual/Inline-Media-Scanner-User-Agent.kb)\";\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithViewController:(TVCLogController *)viewController\n{\n\tNSParameterAssert(viewController != nil);\n\n\tif ((self = [super init])) {\n\t\tself.viewController = viewController;\n\n\t\t[self constructWebView];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\tself.webViewBacking = nil;\n}\n\n+ (BOOL)webKit2Enabled\n{\n\tif ([TVCLogViewInternalWK2 t_safeToUse] == NO) {\n\t\treturn NO;\n\t}\n\n\treturn [TPCPreferences webKit2Enabled];\n}\n\n- (void)constructWebView\n{\n\tBOOL isUsingWebKit2 = [self.class webKit2Enabled];\n\n\tself.isUsingWebKit2 = isUsingWebKit2;\n\n\tif (isUsingWebKit2) {\n\t\tself.webViewBacking = [[TVCLogViewInternalWK2 alloc] initWithHostView:self];\n\t} else {\n\t\tself.webViewBacking = [[TVCLogViewInternalWK1 alloc] initWithHostView:self];\n\t}\n}\n\n- (void)copyContentString\n{\n\t[self stringByEvaluatingFunction:@\"Textual.documentHTML\" completionHandler:^(NSString *result) {\n\t\tRZPasteboard().stringContent = result;\n\t}];\n}\n\n- (BOOL)hasSelection\n{\n\tNSString *selection = self.selection;\n\n\treturn (selection.length > 0);\n}\n\n- (void)clearSelection\n{\n\t[self evaluateFunction:@\"Textual.clearSelection\"];\n}\n\n- (void)print\n{\n\t// Printing is probably broken: <http://www.openradar.me/20217859>\n\n\t[self.webView print:nil];\n}\n\n- (BOOL)keyDown:(NSEvent *)e inView:(NSView *)view\n{\n\tNSParameterAssert(e != nil);\n\tNSParameterAssert(view != nil);\n\n\tNSUInteger m = e.modifierFlags;\n\n\tBOOL cmd = ((m & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);\n\tBOOL alt = ((m & NSEventModifierFlagOption) == NSEventModifierFlagOption);\n\tBOOL ctrl = ((m & NSEventModifierFlagControl) == NSEventModifierFlagControl);\n\n\tif (ctrl == NO && alt == NO && cmd == NO) {\n\t\t[self.viewController logViewWebViewKeyDown:e];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender\n{\n\tNSParameterAssert(sender != nil);\n\n\tNSURL *fileURL = [NSURL URLFromPasteboard:[sender draggingPasteboard]];\n\n\tif (fileURL) {\n\t\tNSString *filename = fileURL.path;\n\n\t\t[self.viewController logViewWebViewReceivedDropWithFile:filename];\n\t}\n\n\treturn NO;\n}\n\n- (void)informDelegateWebViewFinishedLoading\n{\n\t[self.viewController logViewWebViewFinishedLoading];\n}\n\n- (void)informDelegateWebViewClosedUnexpectedly\n{\n\t[self.viewController logViewWebViewClosedUnexpectedly];\n}\n\n- (void)setViewFinishedLayout\n{\n\tself.layingOutView = NO;\n}\n\n- (TVCLogPolicy *)webViewPolicy\n{\n\treturn [self.webViewBacking webViewPolicy];\n}\n\n- (NSView *)webView\n{\n\treturn self.webViewBacking;\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogView (TVCLogViewBackingProxy)\n\n+ (void)emptyCaches\n{\n\t[TVCLogViewInternalWK1 emptyCaches];\n\t[TVCLogViewInternalWK2 emptyCaches];\n}\n\n- (void)recreateTemporaryCopyOfThemeIfNecessary\n{\n\tif (mainWindow().reloadingTheme) {\n\t\treturn;\n\t}\n\n\tif ([TPCApplicationInfo timeIntervalSinceApplicationLaunch] < (2 * 60)) {\n\t\treturn;\n\t}\n\n\t[themeController() recreateTemporaryCopyOfThemeIfNecessary];\n}\n\n- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(baseURL != nil);\n\n\tself.layingOutView = YES;\n\n\t[self _loadHTMLString:string baseURL:baseURL];\n}\n\n- (void)_loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL\n{\n\tNSParameterAssert(string != nil);\n\tNSParameterAssert(baseURL != nil);\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\tif (self.isUsingWebKit2 == NO) {\n\t\tWebFrame *webViewFrame = [self.webViewBacking mainFrame];\n\n\t\t[webViewFrame loadHTMLString:string baseURL:baseURL];\n\n\t\treturn;\n\t}\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n\t[self recreateTemporaryCopyOfThemeIfNecessary];\n\n\tWKWebView *webView = self.webViewBacking;\n\n\tNSString *filename = [NSString stringWithFormat:@\"%@.html\", [NSString stringWithUUID]];\n\n\tNSURL *filePath = [baseURL URLByAppendingPathComponent:filename];\n\n\tNSError *fileWriteError = nil;\n\n\tif ([string writeToURL:filePath atomically:NO encoding:NSUTF8StringEncoding error:&fileWriteError] == NO) {\n\t\tLogToConsoleError(\"Failed to write temporary file: %{public}@\", fileWriteError.localizedDescription);\n\n\t\treturn;\n\t}\n\n\t[webView loadFileURL:filePath\n allowingReadAccessToURL:themeController().temporaryURL];\n}\n\n- (void)stopLoading\n{\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\tif (self.isUsingWebKit2 == NO) {\n\t\tWebFrame *webViewFrame = [self.webViewBacking mainFrame];\n\n\t\t[webViewFrame stopLoading];\n\n\t\treturn;\n\t}\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n\tWKWebView *webView = self.webViewBacking;\n\n\t[webView stopLoading];\n}\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward\n{\n\tNSParameterAssert(searchString != nil);\n\n\t[self.webViewBacking findString:searchString movingForward:movingForward];\n}\n\n- (void)enableOffScreenUpdates\n{\n//\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView enableOffScreenUpdates];\n//\t});\n}\n\n- (void)disableOffScreenUpdates\n{\n//\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView disableOffScreenUpdates];\n//\t});\n}\n\n- (void)redrawViewIfNeeded\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView redrawViewIfNeeded];\n\t});\n}\n\n- (void)redrawView\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView redrawView];\n\t});\n}\n\n- (void)resetScrollerPosition\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView resetScrollerPosition];\n\t});\n}\n\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView resetScrollerPositionTo:scrolledToBottom];\n\t});\n}\n\n- (void)saveScrollerPosition\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView saveScrollerPosition];\n\t});\n}\n\n- (void)restoreScrollerPosition\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[(id)self.webView restoreScrollerPosition];\n\t});\n}\n\n- (void)setAutomaticScrollingEnabled:(BOOL)automaticScrollingEnabled\n{\n//\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t[(id)self.webView setAutomaticScrollingEnabled:automaticScrollingEnabled];\n//\t});\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogView (TVCLogViewJavaScriptHandler)\n\n- (void)evaluateJavaScript:(NSString *)code\n{\n\t[self evaluateJavaScript:code completionHandler:nil];\n}\n\n- (void)evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable result))completionHandler\n{\n\tNSParameterAssert(code != nil);\n\n\tdispatch_block_t blockToPerform = ^{\n\t\t[self.webViewBacking _t_evaluateJavaScript:code completionHandler:completionHandler];\n\t};\n\n//\tif (self.isUsingWebKit2) {\n//\t\tblockToPerform();\n//\t} else {\n\t\tXRPerformBlockAsynchronouslyOnMainQueue(blockToPerform);\n//\t}\n}\n\n+ (NSString *)descriptionOfJavaScriptResult:(id)scriptResult\n{\n\tNSParameterAssert(scriptResult != nil);\n\n\tif ([scriptResult isKindOfClass:[NSString class]])\n\t{\n\t\treturn scriptResult;\n\t}\n\telse if ([scriptResult isKindOfClass:[NSArray class]] ||\n\t\t\t [scriptResult isKindOfClass:[NSDictionary class]])\n\t{\n\t\treturn [scriptResult description];\n\t}\n\telse if ([scriptResult isKindOfClass:[NSNumber class]])\n\t{\n\t\tif ([scriptResult isBooleanValue]) {\n\t\t\tif ([scriptResult boolValue]) {\n\t\t\t\treturn @\"true\";\n\t\t\t} else {\n\t\t\t\treturn @\"false\";\n\t\t\t}\n\t\t} else {\n\t\t\treturn [scriptResult stringValue];\n\t\t}\n\t}\n\telse if ([scriptResult isKindOfClass:[NSNull class]])\n\t{\n\t\treturn @\"null\";\n\t}\n\telse\n\t{\n\t\treturn @\"undefined\";\n\t}\n}\n\n+ (NSString *)escapeJavaScriptString:(NSString *)string\n{\n\tNSParameterAssert(string != nil);\n\n\tNSString *escapedString = string;\n\n\tescapedString = [escapedString stringByReplacingOccurrencesOfString:@\"\\\\\" withString:@\"\\\\\\\\\"];\n\tescapedString = [escapedString stringByReplacingOccurrencesOfString:@\"\\\"\" withString:@\"\\\\\\\"\"];\n\tescapedString = [escapedString stringByReplacingOccurrencesOfString:@\"\\r\" withString:@\"\\\\r\"];\n\tescapedString = [escapedString stringByReplacingOccurrencesOfString:@\"\\n\" withString:@\"\\\\n\"];\n\n\treturn escapedString;\n}\n\n- (void)evaluateFunction:(NSString *)function\n{\n\t[self evaluateFunction:function withArguments:nil completionHandler:nil];\n}\n\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments\n{\n\t[self evaluateFunction:function withArguments:arguments completionHandler:nil];\n}\n\n- (void)evaluateFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(id _Nullable result))completionHandler\n{\n\tNSParameterAssert(function != nil);\n\n\tNSString *compiledScript = [self compiledFunctionCall:function withArguments:arguments];\n\n\t[self evaluateJavaScript:compiledScript completionHandler:completionHandler];\n}\n\n- (void)booleanByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(BOOL result))completionHandler\n{\n\t[self booleanByEvaluatingFunction:function withArguments:nil completionHandler:completionHandler];\n}\n\n- (void)booleanByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(BOOL result))completionHandler\n{\n\t[self evaluateFunction:function withArguments:arguments completionHandler:^(id result) {\n\t\tBOOL resultBool = NO;\n\n\t\tif (result && [result isKindOfClass:[NSNumber class]]) {\n\t\t\tresultBool = [result boolValue];\n\t\t}\n\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(resultBool);\n\t\t}\n\t}];\n}\n\n- (void)stringByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSString * _Nullable result))completionHandler\n{\n\t[self stringByEvaluatingFunction:function withArguments:nil completionHandler:completionHandler];\n}\n\n- (void)stringByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSString * _Nullable result))completionHandler\n{\n\t[self evaluateFunction:function withArguments:arguments completionHandler:^(id result) {\n\t\tNSString *resultString = nil;\n\n\t\tif (result && [result isKindOfClass:[NSString class]]) {\n\t\t\tresultString = result;\n\t\t}\n\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(resultString);\n\t\t}\n\t}];\n}\n\n- (void)arrayByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSArray * _Nullable result))completionHandler\n{\n\t[self arrayByEvaluatingFunction:function withArguments:nil completionHandler:completionHandler];\n}\n\n- (void)arrayByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSArray * _Nullable result))completionHandler\n{\n\t[self evaluateFunction:function withArguments:arguments completionHandler:^(id result) {\n\t\tNSArray *resultArray = nil;\n\n\t\tif (result && [result isKindOfClass:[NSArray class]]) {\n\t\t\tresultArray = result;\n\t\t}\n\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(resultArray);\n\t\t}\n\t}];\n}\n\n- (void)dictionaryByEvaluatingFunction:(NSString *)function completionHandler:(void (^ _Nullable)(NSDictionary<NSString *, id> * _Nullable result))completionHandler\n{\n\t[self dictionaryByEvaluatingFunction:function withArguments:nil completionHandler:completionHandler];\n}\n\n- (void)dictionaryByEvaluatingFunction:(NSString *)function withArguments:(nullable NSArray *)arguments completionHandler:(void (^ _Nullable)(NSDictionary<NSString *, id> * _Nullable result))completionHandler\n{\n\t[self evaluateFunction:function withArguments:arguments completionHandler:^(id result) {\n\t\tNSDictionary *resultDictionary = nil;\n\n\t\tif (result && [result isKindOfClass:[NSDictionary class]]) {\n\t\t\tresultDictionary = result;\n\t\t}\n\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(resultDictionary);\n\t\t}\n\t}];\n}\n\n- (void)logToJavaScriptConsole:(NSString *)message, ...\n{\n\tNSParameterAssert(message != nil);\n\t\n\tva_list arguments;\n\tva_start(arguments, message);\n\t\n\t[TVCLogScriptEventSink logToJavaScriptConsole:message inWebView:self withArguments:arguments];\n\t\n\tva_end(arguments);\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCLogView (TVCLogViewJavaScriptHandlerPrivate)\n\n- (NSString *)compileJavaScriptDictionaryArgument:(NSDictionary<NSString *, id> *)objects\n{\n\tNSParameterAssert(objects != nil);\n\n\tNSMutableString *compiledScript = [NSMutableString string];\n\n\t[compiledScript appendString:@\"{\"];\n\n\tNSInteger lastIndex = (objects.count - 1);\n\n\t__block NSInteger currentIndex = 0;\n\n\t[objects enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {\n\t\t/* Perform check to make sure the key we are using is actually a string. */\n\t\tif ([key isKindOfClass:[NSString class]] == NO) {\n\t\t\tLogToConsoleDebug(\"Silently ignoring non-string key: %{public}@\", NSStringFromClass([key class]));\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Add key and value to new object. */\n\t\tNSString *keyString = [self.class escapeJavaScriptString:key];\n\n\t\tNSString *objectString = [self compileJavaScriptGenericArgument:object];\n\n\t\tif (currentIndex == lastIndex) {\n\t\t\t[compiledScript appendFormat:@\"\\\"%@\\\":%@\", keyString, objectString];\n\t\t} else {\n\t\t\t[compiledScript appendFormat:@\"\\\"%@\\\":%@, \", keyString, objectString];\n\t\t}\n\n\t\tcurrentIndex += 1;\n\t}];\n\n\t[compiledScript appendString:@\"}\"];\n\n\treturn [compiledScript copy];\n}\n\n- (NSString *)compileJavaScriptArrayArgument:(NSArray *)objects\n{\n\tNSParameterAssert(objects != nil);\n\n\tNSMutableString *compiledScript = [NSMutableString string];\n\n\t[compiledScript appendString:@\"[\"];\n\n\tNSInteger lastIndex = (objects.count - 1);\n\n\t[objects enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {\n\t\tNSString *objectString = [self compileJavaScriptGenericArgument:object];\n\n\t\tif (index == lastIndex) {\n\t\t\t[compiledScript appendString:objectString];\n\t\t} else {\n\t\t\t[compiledScript appendFormat:@\"%@,\", objectString];\n\t\t}\n\t}];\n\n\t[compiledScript appendString:@\"]\"];\n\n\treturn [compiledScript copy];\n}\n\n- (NSString *)compileJavaScriptGenericArgument:(id)object\n{\n\tNSParameterAssert(object != nil);\n\n\tif ([object isKindOfClass:[NSURL class]])\n\t{\n\t\tobject = [object absoluteString];\n\t}\n\n\tif ([object isKindOfClass:[NSString class]])\n\t{\n\t\tNSString *objectEscaped = [self.class escapeJavaScriptString:object];\n\n\t\treturn [NSString stringWithFormat:@\"\\\"%@\\\"\", objectEscaped];\n\t}\n\telse if ([object isKindOfClass:[NSNumber class]])\n\t{\n\t\tif ([object isBooleanValue]) {\n\t\t\tif ([object boolValue]) {\n\t\t\t\treturn @\"true\";\n\t\t\t} else {\n\t\t\t\treturn @\"false\";\n\t\t\t}\n\t\t} else {\n\t\t\treturn [object stringValue];\n\t\t}\n\t}\n\telse if ([object isKindOfClass:[NSArray class]])\n\t{\n\t\treturn [self compileJavaScriptArrayArgument:object];\n\t}\n\telse if ([object isKindOfClass:[NSDictionary class]])\n\t{\n\t\treturn [self compileJavaScriptDictionaryArgument:object];\n\t}\n\telse if ([object isKindOfClass:[NSNull class]])\n\t{\n\t\treturn @\"null\";\n\t}\n\telse\n\t{\n\t\treturn @\"undefined\";\n\t}\n}\n\n- (NSString *)compiledFunctionCall:(NSString *)function withArguments:(nullable NSArray *)arguments\n{\n\tNSParameterAssert(function != nil);\n\n\tNSMutableString *compiledScript = [NSMutableString string];\n\n\t[compiledScript appendFormat:@\"%@(\", function];\n\n\tif ( arguments) {\n\t\tNSUInteger argumentCount = arguments.count;\n\n\t\tfor (NSUInteger i = 0; i < argumentCount; i++) {\n\t\t\tNSString *argument = [self compileJavaScriptGenericArgument:arguments[i]];\n\n\t\t\t[compiledScript appendString:argument];\n\n\t\t\tif (i < (argumentCount - 1)) {\n\t\t\t\t[compiledScript appendString:@\",\"];\n\t\t\t}\n\t\t}\n\t}\n\n\t[compiledScript appendString:@\");\\n\"];\n\n\treturn [compiledScript copy];\n}\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n- (id)webScriptObjectToCommon:(WebScriptObject *)object\n{\n\tNSParameterAssert(object != nil);\n\n\tNSAssert((self.isUsingWebKit2 == NO),\n\t\t@\"Cannot use feature when WebKit2 is in use\");\n\n\tWebFrame *webViewFrame = [self.webViewBacking mainFrame];\n\n\tJSGlobalContextRef jsContextRef = webViewFrame.globalContext;\n\n\treturn [object toCommonInContext:jsContextRef];\n}\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogViewInternalWK1.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\n#include <objc/message.h>\n\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogPolicyPrivate.h\"\n#import \"TVCLogScriptEventSinkPrivate.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCWK1AutoScrollerPrivate.h\"\n#import \"TVCLogViewInternalWK1.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogViewInternalWK1 ()\n@property (nonatomic, strong) TVCWK1AutoScroller *autoScroller;\n@property (nonatomic, readwrite, strong) TVCLogScriptEventSink *webViewScriptSink;\n@end\n\nstatic WebPreferences *_sharedWebViewPreferences = nil;\nstatic TVCLogPolicy *_sharedWebPolicy = nil;\n\n@implementation TVCLogViewInternalWK1\n\n#pragma mark -\n#pragma mark Factory\n\n+ (void)_t_initialize\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t_sharedWebViewPreferences = [[WebPreferences alloc] initWithIdentifier:@\"TVCLogViewInternalWK1SharedWebPreferencesObject\"];\n\n\t\t_sharedWebViewPreferences.cacheModel = WebCacheModelDocumentViewer;\n\t\t_sharedWebViewPreferences.usesPageCache = NO;\n\n\t\tSEL selector = @selector(setShouldRespectImageOrientation:);\n\n\t\tif ([_sharedWebViewPreferences respondsToSelector:selector]) {\n\t\t\tNSMethodSignature *signature = [_sharedWebViewPreferences methodSignatureForSelector:selector];\n\n\t\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t\t[invocation setTarget:_sharedWebViewPreferences];\n\t\t\t[invocation setSelector:selector];\n\n\t\t\tBOOL yes = YES;\n\t\t\t[invocation setArgument:&yes atIndex:2];\n\n\t\t\t[invocation invoke];\n\t\t}\n\n\t\t_sharedWebPolicy = [TVCLogPolicy new];\n\t});\n}\n\n- (instancetype)initWithHostView:(TVCLogView *)hostView\n{\n\t[self.class _t_initialize];\n\n\tif ((self = [self initWithFrame:NSZeroRect])) {\n\t\t[self constructWebViewWithHostView:hostView];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)constructWebViewWithHostView:(TVCLogView *)hostView\n{\n\tNSParameterAssert(hostView != nil);\n\n\tself.t_parentView = hostView;\n\n\tTVCLogScriptEventSink *webViewScriptSink =\n\t[[TVCLogScriptEventSink alloc] initWithWebView:hostView];\n\n\tself.webViewScriptSink = webViewScriptSink;\n\n\tself.preferences = _sharedWebViewPreferences;\n\n\tself.translatesAutoresizingMaskIntoConstraints = NO;\n\n\tself.customUserAgent = TVCLogViewCommonUserAgentString;\n\n\tself.frameLoadDelegate = (id)self;\n\tself.policyDelegate = (id)self;\n\tself.resourceLoadDelegate = (id)self;\n\tself.UIDelegate = (id)self;\n\n\tself.shouldUpdateWhileOffscreen = NO;\n\n\t[self updateBackgroundColor];\n}\n\n- (void)dealloc\n{\n\tself.frameLoadDelegate = nil;\n\tself.policyDelegate = nil;\n\tself.resourceLoadDelegate = nil;\n\tself.UIDelegate = nil;\n}\n\n- (TVCLogPolicy *)webViewPolicy\n{\n\treturn _sharedWebPolicy;\n}\n\n#pragma mark -\n#pragma mark View Events\n\n- (void)keyDown:(NSEvent *)e\n{\n\tif ([self.t_parentView keyDown:e inView:self]) {\n\t\treturn;\n\t}\n\n\t[super keyDown:e];\n}\n\n- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender\n{\n\treturn [self.t_parentView performDragOperation:sender];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (void)emptyCaches\n{\n\tLogToConsoleDebug(\"WebKit cache cleared\");\n}\n\n- (void)updateBackgroundColor\n{\n\tNSColor *windowColor = themeSettings().underlyingWindowColor;\n\n\tif (windowColor == nil) {\n\t\twindowColor = [NSColor blackColor];\n\t}\n\n\t[(id)self setBackgroundColor:windowColor];\n}\n\n- (void)maybeInformDelegateWebViewFinishedLoading\n{\n\tif (self.t_viewHasLoaded == NO || self.t_viewHasScriptObject == NO) {\n\t\treturn;\n\t}\n\n\t[self.t_parentView performSelectorInCommonModes:@selector(informDelegateWebViewFinishedLoading) withObject:nil afterDelay:1.2];\n\n\t[self constructAutoScroller];\n}\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward\n{\n\tNSParameterAssert(searchString != nil);\n\n\t[self searchFor:searchString direction:movingForward caseSensitive:NO wrap:YES];\n}\n\n#pragma mark -\n#pragma mark View Configuration\n\n- (BOOL)maintainsInactiveSelection\n{\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark JavaScript\n\n- (void)_t_evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable))completionHandler\n{\n\tNSParameterAssert(code != nil);\n\n\tWebScriptObject *scriptObject = self.windowScriptObject;\n\n\tif (scriptObject == nil || [scriptObject isKindOfClass:[WebUndefined class]]) {\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(nil);\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\tid scriptResult = [scriptObject evaluateWebScript:code];\n\n\tif (scriptResult) {\n\t\tif ([scriptResult isKindOfClass:[NSNull class]] ||\n\t\t\t[scriptResult isKindOfClass:[WebUndefined class]])\n\t\t{\n\t\t\tif (completionHandler) {\n\t\t\t\tcompletionHandler(nil);\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse if ([scriptResult isKindOfClass:[WebScriptObject class]])\n\t\t{\n\t\t\tscriptResult = [self.t_parentView webScriptObjectToCommon:scriptResult];\n\t\t}\n\t}\n\n\tif (completionHandler) {\n\t\tcompletionHandler(scriptResult);\n\t}\n}\n\n#pragma mark -\n#pragma mark Scroll View\n\n- (void)enableOffScreenUpdates\n{\n\tself.shouldUpdateWhileOffscreen = YES;\n}\n\n- (void)disableOffScreenUpdates\n{\n\tself.shouldUpdateWhileOffscreen = NO;\n}\n\n- (void)redrawViewIfNeeded\n{\n\t/* The WebView is layer backed which means it is not redrawn unless it is told to do so.\n\t TVCWK1AutoScroller automatically tells it to do so if it scrolled programmatically or\n\t by the end user. When there is not enough content to scroll, the WebView is not redrawn\n\t because there is never a scroll event triggered. Therefore, this call exists to tell\n\t TVCWK1AutoScroller that we are interested in a redraw and it will then take appropriate\n\t actions depending on whether one is necessary or not. */\n\tif (self.t_parentView.viewController.visible == NO) {\n\t\treturn;\n\t}\n\n\tif (self.autoScroller.canScroll == NO) {\n\t\t[self.autoScroller redrawFrame];\n\t}\n}\n\n- (void)redrawView\n{\n\tif (self.t_parentView.viewController.visible == NO) {\n\t\treturn;\n\t}\n\n\t[self.autoScroller redrawFrame];\n}\n\n- (void)resetScrollerPosition\n{\n\t[self.autoScroller restoreScrollerPosition];\n}\n\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom\n{\n\t[self.autoScroller resetScrollerPositionTo:scrolledToBottom];\n}\n\n- (void)saveScrollerPosition\n{\n\t[self.autoScroller saveScrollerPosition];\n}\n\n- (void)restoreScrollerPosition\n{\n\t[self.autoScroller restoreScrollerPosition];\n}\n\n- (void)constructAutoScroller\n{\n\tWebFrameView *frameView = self.mainFrame.frameView;\n\n\tself.autoScroller = [[TVCWK1AutoScroller alloc] initWitFrameView:frameView];\n}\n\n- (void)setAutomaticScrollingEnabled:(BOOL)automaticScrollingEnabled\n{\n\tself.autoScroller.automaticScrollingEnabled = automaticScrollingEnabled;\n}\n\n#pragma mark -\n#pragma mark Web View Delegate\n\n- (NSArray *)webView:(WebView *)webView contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems\n{\n\tNSParameterAssert(webView == self);\n\n\treturn [_sharedWebPolicy webView1:webView logView:self.t_parentView contextMenuWithDefaultMenuItems:defaultMenuItems];\n}\n\n- (NSUInteger)webView:(WebView *)webView dragDestinationActionMaskForDraggingInfo:(id<NSDraggingInfo>)draggingInfo\n{\n\tNSParameterAssert(webView == self);\n\n\treturn [_sharedWebPolicy webView1:webView logView:self.t_parentView dragDestinationActionMaskForDraggingInfo:draggingInfo];\n}\n\n- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id <WebPolicyDecisionListener>)listener\n{\n\tNSParameterAssert(webView == self);\n\n\t[_sharedWebPolicy webView1:webView logView:self.t_parentView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener];\n}\n\n- (void)webView:(WebView *)webView resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)dataSource\n{\n\tNSParameterAssert(webView == self);\n\n\t[_sharedWebPolicy webView1:webView logView:self.t_parentView resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:dataSource];\n}\n\n- (void)webView:(WebView *)webView didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame\n{\n\tNSParameterAssert(webView == self);\n\n\tself.t_viewHasScriptObject = YES;\n\n\t[windowObject setValue:self.webViewScriptSink forKey:@\"TextualScriptSink\"];\n\n\t[self maybeInformDelegateWebViewFinishedLoading];\n}\n\n- (void)webView:(WebView *)webView didFinishLoadForFrame:(WebFrame *)frame\n{\n\tNSParameterAssert(webView == self);\n\n\tself.t_viewHasLoaded = YES;\n\n\t[self maybeInformDelegateWebViewFinishedLoading];\n\n\t[self updateBackgroundColor];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCLogViewInternalWK2.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"WKWebViewPrivate.h\"\n\n#include <objc/message.h>\n#include <objc/runtime.h>\n\n#import \"IRCChannel.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogPolicyPrivate.h\"\n#import \"TVCLogScriptEventSinkPrivate.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCLogViewInternalWK2.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _maximumProcessCount\t\t\t8\n#define _maximumViewInstances\t\t\t50\n\n@interface TVCLogViewInternalWK2 ()\n@property (nonatomic, assign) BOOL t_observingLoadingProperty;\n@end\n\n@implementation TVCLogViewInternalWK2\n\nstatic WKProcessPool *_sharedProcessPool = nil;\nstatic WKUserContentController *_sharedUserContentController = nil;\nstatic WKWebViewConfiguration *_sharedWebViewConfiguration = nil;\nstatic TVCLogPolicy *_sharedWebPolicy = nil;\nstatic TVCLogScriptEventSink *_sharedWebViewScriptSink = nil;\nstatic BOOL _safeToUseWebKit2 = YES;\nstatic NSUInteger _numberOfViews = 0;\n\n#pragma mark -\n#pragma mark Factory\n\n+ (void)_t_initialize\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t[self constructProcessPool];\n\n\t\t_sharedWebViewConfiguration = [WKWebViewConfiguration new];\n\n\t\t_sharedWebViewConfiguration.processPool = _sharedProcessPool;\n\n\t\t_sharedWebViewConfiguration._allowUniversalAccessFromFileURLs = YES;\n\n\t\tWKPreferences *preferences = _sharedWebViewConfiguration.preferences;\n\n\t\tpreferences._allowFileAccessFromFileURLs = YES;\n\t\tpreferences._developerExtrasEnabled = YES;\n\n\t\t_sharedWebViewScriptSink = [[TVCLogScriptEventSink alloc] initWithWebView:nil];\n\n\t\t_sharedUserContentController = [WKUserContentController new];\n\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"appearance\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"channelIsActive\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"channelMemberCount\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"channelName\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"channelNameDoubleClicked\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"displayContextMenu\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"copySelectionWhenPermitted\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"encryptionAuthenticateUser\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"inlineMediaEnabledForView\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"loadInlineMedia\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"localUserHostmask\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"localUserNickname\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"logToConsole\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"networkName\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"nicknameColorStyleHash\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"nicknameDoubleClicked\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"notifyLinesAddedToView\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"notifyLinesRemovedFromView\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"notifyJumpToLineCallback\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"printDebugInformation\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"printDebugInformationToConsole\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"renderMessagesBefore\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"renderMessagesAfter\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"renderMessagesInRange\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"renderMessageWithSiblings\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"renderTemplate\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"retrievePreferencesWithMethodName\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"sendPluginPayload\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"serverAddress\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"serverChannelCount\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"serverIsConnected\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"setChannelName\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"setNickname\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"setSelection\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"setURLAddress\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"sidebarInversionIsEnabled\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"styleSettingsRetrieveValue\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"styleSettingsSetValue\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"topicBarDoubleClicked\"];\n\t\t[_sharedUserContentController addScriptMessageHandler:(id)_sharedWebViewScriptSink name:@\"finishedLayingOutView\"];\n\n\t\t_sharedWebViewConfiguration.userContentController = _sharedUserContentController;\n\n\t\t_sharedWebPolicy = [TVCLogPolicy new];\n\t});\n}\n\n+ (void)constructProcessPool\n{\n\t/* What we are doing here is very dirty which means it is probably a good idea\n\t that we go above and beyond for error checking incase this stuff is changed. */\n\tWKProcessPool *sharedProcessPool = [WKProcessPool alloc];\n\n\tif ([TPCPreferences webKit2ProcessPoolSizeLimited] == NO) {\n\t\tgoto create_normal_pool;\n\t}\n\n\tif ([sharedProcessPool respondsToSelector:@selector(_initWithConfiguration:)] == NO) {\n\t\tgoto create_normal_pool;\n\t}\n\n\tClass processPoolConfigurationClass = objc_getClass(\"_WKProcessPoolConfiguration\");\n\n\tif (processPoolConfigurationClass) {\n\t\tid processPoolConfiguration = [processPoolConfigurationClass new];\n\n\t\tif (processPoolConfiguration == nil) {\n\t\t\tgoto create_normal_pool;\n\t\t} else if ([processPoolConfiguration respondsToSelector:@selector(setMaximumProcessCount:)] == NO) {\n\t\t\tgoto create_normal_pool;\n\t\t}\n\n\t\t[processPoolConfiguration setMaximumProcessCount:_maximumProcessCount];\n\n\t\t_sharedProcessPool = [sharedProcessPool _initWithConfiguration:processPoolConfiguration];\n\n\t\treturn;\n\t}\n\ncreate_normal_pool:\n\t_sharedProcessPool = [sharedProcessPool init];\n}\n\n- (instancetype)initWithHostView:(TVCLogView *)hostView\n{\n\t[self.class _t_initialize];\n\n\tif ((self = [self initWithFrame:NSZeroRect configuration:_sharedWebViewConfiguration])) {\n\t\t[self constructWebViewWithHostView:hostView];\n\n\t\t// It's not critical that this is thread safe\n\t\t_numberOfViews += 1;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)constructWebViewWithHostView:(TVCLogView *)hostView\n{\n\tNSParameterAssert(hostView != nil);\n\n\tself.t_parentView = hostView;\n\n\tself.allowsBackForwardNavigationGestures = NO;\n\tself.allowsMagnification = NO;\n\n\tself.translatesAutoresizingMaskIntoConstraints = NO;\n\n\tself.allowsLinkPreview = [TPCPreferences webKit2PreviewLinks];\n\n\tself.customUserAgent = TVCLogViewCommonUserAgentString;\n\n\tself.navigationDelegate = (id)self;\n\n\tself.UIDelegate = (id)self;\n}\n\n- (void)dealloc\n{\n\t_numberOfViews -= 1;\n\n\tself.navigationDelegate = nil;\n\n\tself.UIDelegate = nil;\n}\n\n- (TVCLogPolicy *)webViewPolicy\n{\n\treturn _sharedWebPolicy;\n}\n\n+ (BOOL)t_safeToUse\n{\n\t/* June 2024: WebKit2 was enabled by default for beta update users.\n\t One user who is in 200+ channels managed to enter WK2 into an endless\n\t termination loop. Probably resource exhaustion. I am still investigating\n\t the underlying cause of that. But given the extremes of the situation,\n\t this temporary fix may just end up being a permanent one. */\n\tif (_numberOfViews > _maximumViewInstances) {\n\t\treturn NO;\n\t}\n\n\treturn _safeToUseWebKit2;\n}\n\n#pragma mark -\n#pragma mark Load Overrides\n\n- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL\n{\n\t[self startObservingLoadingProperty];\n\n\treturn [super loadFileURL:URL allowingReadAccessToURL:readAccessURL];\n}\n\n- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL\n{\n\t[self startObservingLoadingProperty];\n\n\treturn [super loadHTMLString:string baseURL:baseURL];\n}\n\n- (void)stopLoading\n{\n\t[self stopObservingLoadingProperty];\n\n\t[super stopLoading];\n}\n\n#pragma mark -\n#pragma mark View Events\n\n- (void)keyDown:(NSEvent *)e\n{\n\tif ([self.t_parentView keyDown:e inView:self]) {\n\t\treturn;\n\t}\n\n\t[super keyDown:e];\n}\n\n- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender\n{\n\treturn [self.t_parentView performDragOperation:sender];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (void)emptyCaches\n{\n\tWKWebsiteDataStore *wk2WebsiteDataStore = _sharedWebViewConfiguration.websiteDataStore;\n\n\tif (wk2WebsiteDataStore == nil) {\n\t\treturn;\n\t}\n\n\tNSSet *itemsToRemove = [NSSet setWithArray:@[\n\t\tWKWebsiteDataTypeDiskCache,\n\t\tWKWebsiteDataTypeMemoryCache\n\t]];\n\n\t[wk2WebsiteDataStore removeDataOfTypes:itemsToRemove\n\t\t\t\t\t\t\t modifiedSince:[NSDate distantPast]\n\t\t\t\t\t\t completionHandler:^{\n\t\tLogToConsoleDebug(\"WebKit2 cache cleared\");\n\t}];\n}\n\n- (void)findString:(NSString *)searchString movingForward:(BOOL)movingForward\n{\n\tNSParameterAssert(searchString != nil);\n\n\t_WKFindOptions findOptions = (_WKFindOptionsCaseInsensitive\t| _WKFindOptionsShowOverlay\t| _WKFindOptionsShowFindIndicator | _WKFindOptionsWrapAround);\n\n\tif (movingForward == NO) {\n\t\tfindOptions |= _WKFindOptionsBackwards;\n\t}\n\n\tSEL selector = @selector(_findString:options:maxCount:);\n\n\tif ([self respondsToSelector:selector]) {\n\t\tNSMethodSignature *signature = [self methodSignatureForSelector:selector];\n\n\t\tNSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];\n\n\t\t[invocation setTarget:self];\n\t\t[invocation setSelector:selector];\n\n\t\t[invocation setArgument:&searchString atIndex:2];\n\t\t[invocation setArgument:&findOptions atIndex:3];\n\n\t\tNSUInteger one = 1;\n\t\t[invocation setArgument:&one atIndex:4];\n\n\t\t[invocation invoke];\n\t}\n}\n\n- (void)startObservingLoadingProperty\n{\n\tif (self.t_observingLoadingProperty) {\n\t\treturn;\n\t}\n\n\t[self addObserver:self forKeyPath:@\"loading\" options:NSKeyValueObservingOptionNew context:NULL];\n\n\tself.t_observingLoadingProperty = YES;\n}\n\n- (void)stopObservingLoadingProperty\n{\n\tif (self.t_observingLoadingProperty == NO) {\n\t\treturn;\n\t}\n\n\t[self removeObserver:self forKeyPath:@\"loading\"];\n\n\tself.t_observingLoadingProperty = NO;\n}\n\n- (void)maybeInformDelegateWebViewFinishedLoading\n{\n\tif (self.t_viewIsLoading == NO && self.t_viewIsNavigating == NO) {\n\t\t[self stopObservingLoadingProperty];\n\n\t\t[self.t_parentView performSelectorInCommonModes:@selector(informDelegateWebViewFinishedLoading) withObject:nil afterDelay:1.2];\n\t}\n}\n\n- (void)webViewClosedUnexpectedly\n{\n\t[self.t_parentView informDelegateWebViewClosedUnexpectedly];\n}\n\n#pragma mark -\n#pragma mark View Configuration\n\n- (BOOL)maintainsInactiveSelection\n{\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark JavaScript\n\n- (void)logEvaluateJavaScriptError:(NSError *)error\n{\n\tNSParameterAssert(error != nil);\n\n\tNSNumber *lineNumber = error.userInfo[@\"WKJavaScriptExceptionLineNumber\"];\n\tNSString *errorMessage = error.userInfo[@\"WKJavaScriptExceptionMessage\"];\n\tNSURL *sourceURL = error.userInfo[@\"WKJavaScriptExceptionSourceURL\"];\n\n\tNSString *channelName = self.t_parentView.viewController.associatedChannel.name;\n\n\tif (channelName == nil) {\n\t\tchannelName = @\"Server Console\";\n\t}\n\n\tif (lineNumber == nil || errorMessage == nil || sourceURL == nil) {\n\t\tLogToConsoleError(\"JavaScript Error in %{private}@: %{public}@\", channelName, error.localizedDescription);\n\n\t\treturn;\n\t}\n\n\tLogToConsoleError(\"A JavaScript error occurred in %{public}@ on line %{public}ld of %{public}@: %{public}@\",\n\t\tchannelName, lineNumber.unsignedIntegerValue, sourceURL.standardizedTildePath, errorMessage);\n}\n\n- (void)_t_evaluateJavaScript:(NSString *)code completionHandler:(void (^ _Nullable)(id _Nullable))completionHandler\n{\n\tNSParameterAssert(code != nil);\n\n\t[self evaluateJavaScript:code completionHandler:^(id result, NSError *error) {\n\t\tif (error) {\n\t\t\t[self logEvaluateJavaScriptError:error];\n\t\t}\n\n\t\tif (result) {\n\t\t\tif ([result isKindOfClass:[NSNull class]] ||\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t\t\t\t[result isKindOfClass:[WebUndefined class]])\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n\t\t\t{\n\t\t\t\tif (completionHandler) {\n\t\t\t\t\tcompletionHandler(nil);\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (completionHandler) {\n\t\t\tcompletionHandler(result);\n\t\t}\n\t}];\n}\n\n#pragma mark -\n#pragma mark Scroll View\n\n- (void)enableOffScreenUpdates\n{\n\n}\n\n- (void)disableOffScreenUpdates\n{\n\n}\n\n- (void)redrawViewIfNeeded\n{\n\n}\n\n- (void)redrawView\n{\n\n}\n\n- (void)resetScrollerPosition\n{\n\n}\n\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom\n{\n\n}\n\n- (void)saveScrollerPosition\n{\n\n}\n\n- (void)restoreScrollerPosition\n{\n\n}\n\n- (void)setAutomaticScrollingEnabled:(BOOL)automaticScrollingEnabled\n{\n\n}\n\n#pragma mark -\n#pragma mark Web View Delegate\n\n- (void)_webView:(WKWebView *)webView webContentProcessDidTerminateWithReason:(_WKProcessTerminationReason)reason\n{\n\tNSParameterAssert(webView == self);\n\n\tswitch (reason) {\n\t\tcase _WKProcessTerminationReasonExceededMemoryLimit:\n\t\t\tLogToConsoleError(\"WebView [%{public}@] terminated due to memory limit\", self.description);\n\n\t\t\tbreak;\n\t\tcase _WKProcessTerminationReasonExceededCPULimit:\n\t\t\tLogToConsoleError(\"WebView [%{public}@] terminated due to CPU limit\", self.description);\n\n\t\t\tbreak;\n\t\tcase _WKProcessTerminationReasonRequestedByClient:\n\t\t\tLogToConsoleDebug(\"WebView [%{public}@] terminated by client\", self.description);\n\n\t\t\tbreak;\n\t\tcase _WKProcessTerminationReasonCrash:\n\t\t\tLogToConsoleError(\"WebView [%{public}@] terminated due to crash\", self.description);\n\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tLogToConsoleError(\"WebView [%{public}@] terminated by other means: %{public}ld\", self.description, reason);\n\n\t\t\tbreak;\n\t}\n\n\tif (reason == _WKProcessTerminationReasonRequestedByClient) {\n\t\treturn;\n\t}\n\n\tLogToConsoleError(\"A WebKit process terminated for a reason not understood. Disabling WebKit2 until relaunch.\");\n\tLogStackTrace();\n\n\t_safeToUseWebKit2 = NO;\n\n\t[self webViewClosedUnexpectedly];\n}\n\n- (void)_webViewWebProcessDidBecomeUnresponsive:(WKWebView *)webView\n{\n\tNSParameterAssert(webView == self);\n\n\tLogToConsoleError(\"WebView [%{public}@] terminated due to unresponsive\", self.description);\n}\n\n- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView\n{\n\tNSParameterAssert(webView == self);\n\n\tLogToConsoleDebug(\"WebView [%{public}@] terminated\", self.description);\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tNSParameterAssert(object == self);\n\n\tif ([keyPath isEqualToString:@\"loading\"]) {\n\t\tself.t_viewIsLoading = self.loading;\n\n\t\t[self maybeInformDelegateWebViewFinishedLoading];\n\t}\n}\n\n- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler\n{\n\tNSParameterAssert(webView == self);\n\n\t[_sharedWebPolicy webView2:webView logView:self.t_parentView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler];\n}\n\n- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler\n{\n\tNSParameterAssert(webView == self);\n\n\t[_sharedWebPolicy webView2:webView logView:self.t_parentView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler];\n}\n\n- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation\n{\n\tNSParameterAssert(webView == self);\n\n\tself.t_viewIsNavigating = YES;\n}\n\n- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation\n{\n\tNSParameterAssert(webView == self);\n\n\tself.t_viewIsNavigating = NO;\n\n\t[self maybeInformDelegateWebViewFinishedLoading];\n}\n\n- (NSMenu *)_webView:(WKWebView *)webView contextMenu:(NSMenu *)menu forElement:(id)element\n{\n\tNSParameterAssert(webView == self);\n\n\treturn [_sharedWebPolicy webView2:webView logView:self.t_parentView contextMenuWithDefaultMenu:menu];\n}\n\n@end\n\n#pragma mark -\n#pragma mark WKView Swizzle\n\n/* I am not proud of this, but you have to admit, WebKit2 API is very limited... */\n@implementation NSView (WKiewSwizzle)\n\n+ (void)load\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tXRExchangeInstanceMethod(@\"WKView\", @\"performDragOperation:\", @\"__t_priv_performDragOperation:\");\n\t});\n}\n\n- (BOOL)__t_priv_performDragOperation:(id <NSDraggingInfo>)sender\n{\n\t/* Override drag and drop to allow files to be sent to a user instead\n\t of WebKit thinking that it should load the file as a resource. */\n\tNSView *superview = self.superview;\n\n\tif ([superview respondsToSelector:@selector(performDragOperation:)]) {\n\t\treturn [superview performDragOperation:sender];\n\t}\n\n\treturn [self __t_priv_performDragOperation:sender];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Channel View/TVCWK1AutoScroller.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\n#import \"TVCWK1AutoScrollerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCWK1AutoScroller ()\n{\n\tCGFloat _scrollHeightCurrentValue;\n\tCGFloat _scrollHeightPreviousValue;\n\tCGFloat _scrollPositionCurrentValue;\n\tCGFloat _scrollPositionPreviousValue;\n\tBOOL _userScrolled;\n\tBOOL _scrolledUpwards;\n\tBOOL _restoreScrollerPosition;\n/*\tNSRect _lastFrame; */\n}\n\n@property (nonatomic, weak) WebFrameView *frameView;\n@property (readonly) NSView *documentView;\n@end\n\n@implementation TVCWK1AutoScroller\n\n/* Maximum distance user can scroll up before automatic scrolling is disabled. */\nstatic CGFloat _userScrolledMinimum = 25.0;\n\n- (instancetype)initWitFrameView:(WebFrameView *)frameView\n{\n\tNSParameterAssert(frameView != nil);\n\n\tif ((self = [super init])) {\n\t\tself.frameView = frameView;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tWebFrameView *frameView = self.frameView;\n\n\tNSView *documentView = frameView.documentView;\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(webViewDidChangeFrame:)\n\t\t\t\t\t\t\t\t   name:NSViewFrameDidChangeNotification\n\t\t\t\t\t\t\t\t object:frameView];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(webViewDidChangeFrame:)\n\t\t\t\t\t\t\t\t   name:NSViewFrameDidChangeNotification\n\t\t\t\t\t\t\t\t object:documentView];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(webViewDidChangeBounds:)\n\t\t\t\t\t\t\t\t   name:NSViewBoundsDidChangeNotification\n\t\t\t\t\t\t\t\t object:documentView.enclosingScrollView.contentView];\n\n\tself->_automaticScrollingEnabled = YES;\n\n\tself->_scrollPositionCurrentValue = 0.0;\n\tself->_scrollPositionPreviousValue = 0.0;\n\n\tself->_userScrolled = NO;\n\n\tself->_restoreScrollerPosition = YES;\n}\n\n- (NSView *)documentView\n{\n\treturn self.frameView.documentView;\n}\n\n- (BOOL)viewingBottom\n{\n\tif (self->_userScrolled == NO) {\n\t\treturn YES;\n\t}\n\n\treturn [self viewIsScrolledToBottom:self.documentView];\n}\n\n- (BOOL)viewIsScrolledToBottom:(NSView *)aView\n{\n\tNSRect visibleRect = aView.visibleRect;\n\n\tCGFloat scrollHeight = (aView.frame.size.height - visibleRect.size.height);\n\n\tCGFloat scrollPosition = visibleRect.origin.y;\n\n\treturn CGFloatAreEqual(scrollHeight, scrollPosition);\n}\n\n- (void)resetScrollerPosition\n{\n\t[self resetScrollerPositionTo:NO];\n}\n\n- (void)resetScrollerPositionTo:(BOOL)scrolledToBottom\n{\n\tself->_restoreScrollerPosition = scrolledToBottom;\n}\n\n- (void)saveScrollerPosition\n{\n\tself->_restoreScrollerPosition = self.viewingBottom;\n}\n\n- (void)restoreScrollerPosition\n{\n\tif (self->_restoreScrollerPosition) {\n\t\tself->_restoreScrollerPosition = NO;\n\t} else {\n\t\treturn;\n\t}\n\n\t[self scrollViewToBottom:self.documentView];\n}\n\n- (void)scrollViewToBottom:(NSView *)aView\n{\n\tNSRect visibleRect = aView.visibleRect;\n\n\tvisibleRect.origin.y = (aView.frame.size.height - visibleRect.size.height);\n\n\t[aView scrollRectToVisible:visibleRect];\n}\n\n- (void)dealloc\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\tself.frameView = nil;\n}\n\n- (BOOL)canScroll\n{\n\tWebFrameView *frameView = self.frameView;\n\n\tNSRect frameRect = frameView.frame;\n\n\tNSRect contentRect = frameView.documentView.frame;\n\n\treturn (contentRect.size.height > frameRect.size.height);\n}\n\n- (void)redrawFrame\n{\n\t[self.documentView setNeedsLayout:YES];\n}\n\n- (void)webViewDidChangeBounds:(NSNotification *)aNotification\n{\n\t/* Context */\n\tNSView *documentView = self.documentView;\n\n\tNSRect visibleRect = documentView.visibleRect;\n\n\t/* The maximum scrollPosition can equal. The bottom */\n\tCGFloat scrollHeightCurrent = (documentView.frame.size.height - visibleRect.size.height);\n\n\tCGFloat scrollHeightPrevious = self->_scrollHeightPreviousValue;\n\n\t/* The current position. When at bottom, will == scrollHeight */\n\tCGFloat scrollPositionCurrent = visibleRect.origin.y;\n\n\tCGFloat scrollPositionPrevious = self->_scrollPositionPreviousValue;\n\n\t/* If nothing changed, we ignore the event.\n\t It is possible to receive a scroll event but nothing changes\n\t because we ignore elastic scrolling. User can reach bottom,\n\t elastic scroll, then bounce back. We get notification for\n\t both times we reach bottom, but values do not change. */\n\tif (CGFloatAreEqual(scrollHeightPrevious, scrollHeightCurrent) &&\n\t\tCGFloatAreEqual(scrollPositionPrevious, scrollPositionCurrent))\n\t{\n\t\treturn;\n\t}\n\n\t/* Even if user is elastic scrolling, we want to record\n\t the latest scroll height values. */\n\tself->_scrollHeightPreviousValue = scrollHeightPrevious;\n\tself->_scrollHeightCurrentValue = scrollHeightCurrent;\n\n\t/* Ignore elastic scrolling */\n\tif (scrollPositionCurrent < 0 ||\n\t\tscrollPositionCurrent > scrollHeightCurrent)\n\t{\n\t\treturn;\n\t}\n\n\t/* Only record scroll position changes if we weren't elastic scrolling. */\n\tself->_scrollPositionPreviousValue = scrollPositionPrevious;\n\tself->_scrollPositionCurrentValue = scrollPositionCurrent;\n\n\t/* Scrolled upwards? */\n\tBOOL scrolledUpwards = (scrollPositionCurrent < scrollPositionPrevious);\n\n\tself->_scrolledUpwards = scrolledUpwards;\n\n\t/* User scrolled above bottom? */\n\tBOOL userScrolled = ((scrollHeightCurrent - scrollPositionCurrent) > _userScrolledMinimum);\n\n\tif (self->_userScrolled != userScrolled) {\n\t\tself->_userScrolled = userScrolled;\n\n\t\tif (userScrolled) {\n\t\t\tLogToConsoleDebug(\"User scrolled above threshold. Disabled auto scroll\");\n\t\t} else {\n\t\t\tLogToConsoleDebug(\"Scrolled below threshold. Enabled auto scroll\");\n\t\t}\n\t}\n}\n\n- (void)webViewDidChangeFrame:(NSNotification *)aNotification\n{\n\t/* Never scroll if user scrolled up */\n\tif (self->_automaticScrollingEnabled == NO || self->_userScrolled) {\n\t\treturn;\n\t}\n\n\t[self scrollViewToBottom:self.documentView];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n\nTEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Errors/TVCAlert.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n        Please see Acknowledgements.pdf for additional informative.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCAlert.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TVCAlertLaunchedAs) {\n\tTVCAlertLaunchedAsNonblockingPanel = 0,\n\tTVCAlertLaunchedAsModal,\n\tTVCAlertLaunchedAsSheet\n};\n\n@interface TVCAlert ()\n@property (nonatomic, strong, readwrite) IBOutlet NSPanel *panel;\n@property (nonatomic, weak) IBOutlet NSImageView *iconImageView;\n@property (nonatomic, weak) IBOutlet NSImageView *warningIconImageView;\n@property (nonatomic, weak) IBOutlet NSTextField *messageTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *informativeTextField;\n@property (nonatomic, weak) IBOutlet NSButton *firstButton;\n@property (nonatomic, weak) IBOutlet NSButton *secondButton;\n@property (nonatomic, weak) IBOutlet NSButton *thirdButton;\n@property (nonatomic, weak, readwrite) IBOutlet NSButton *suppressionButton;\n@property (nonatomic, assign) BOOL alertFinished;\n@property (nonatomic, assign) BOOL alertImmutable;\n@property (nonatomic, assign) BOOL alertVisible;\n@property (nonatomic, assign) BOOL layoutPerformed;\n@property (nonatomic, assign) TVCAlertLaunchedAs launchedAs;\n@property (nonatomic, copy, nullable) TVCAlertCompletionBlock completionBlock;\n@property (nonatomic, copy, nullable) TVCAlertButtonClickedBlock firstButtonAction;\n@property (nonatomic, copy, nullable) TVCAlertButtonClickedBlock secondButtonAction;\n@property (nonatomic, copy, nullable) TVCAlertButtonClickedBlock thirdButtonAction;\n\n- (IBAction)buttonPressed:(id)sender;\n@end\n\n@implementation TVCAlert\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TVCAlert\" owner:self topLevelObjects:nil];\n\n\tself.panel.floatingPanel = YES;\n\n\tLogToConsoleDebug(\"[%{public}@] Creating alert host\", self);\n}\n\n- (void)showAlert\n{\n\t[self showAlertWithCompletionBlock:nil];\n}\n\n- (void)showAlertWithCompletionBlock:(nullable TVCAlertCompletionBlock)completionBlock\n{\n\t[self _showAlertInWindow:nil withCompletionBlock:completionBlock];\n}\n\n- (void)showAlertInWindow:(NSWindow *)window\n{\n\tNSParameterAssert(window != nil);\n\n\t[self showAlertInWindow:window withCompletionBlock:nil];\n}\n\n- (void)showAlertInWindow:(NSWindow *)window withCompletionBlock:(nullable TVCAlertCompletionBlock)completionBlock\n{\n\tNSParameterAssert(window != nil);\n\n\t[self _showAlertInWindow:window withCompletionBlock:completionBlock];\n}\n\n- (void)_showAlertInWindow:(nullable NSWindow *)window withCompletionBlock:(nullable TVCAlertCompletionBlock)completionBlock\n{\n\tNSAssert((self.alertFinished == NO),\n\t\t@\"Cannot show alert because it has already finished\");\n\n\t/* Bring window forward if -showAlert is called more than once */\n\tif (self.alertVisible) {\n\t\t[self.panel makeKeyAndOrderFront:nil];\n\n\t\treturn;\n\t}\n\n\t/* Do not allow changes to be made to the alert */\n\tself.alertImmutable = YES;\n\n\t/* Non-blocking alerts which are created through this initializer\n\t should not stay on top of other apps when app is not key. */\n\tif (window == nil) {\n\t\tself.window.hidesOnDeactivate = YES;\n\t}\n\n\t/* Perform layout */\n\t[self _layout];\n\n\t/* Present alert */\n\tself.completionBlock = completionBlock;\n\n\tself.alertVisible = YES;\n\n\tif (window) {\n\t\tLogToConsoleDebug(\"[%{public}@] Running alert sheet in window: %{public}@\", self, window);\n\t} else {\n\t\tLogToConsoleDebug(\"[%{public}@] Running non-blocking alert\", self);\n\t}\n\n\tif (window) {\n\t\tself.launchedAs = TVCAlertLaunchedAsSheet;\n\n\t\t[window beginSheet:self.panel\n\t\t completionHandler:^(NSModalResponse returnCode) {\n\t\t\t[self _alertSheetDidEndWithReturnCode:returnCode];\n\t\t}];\n\t} else {\n\t\tself.launchedAs = TVCAlertLaunchedAsNonblockingPanel;\n\n\t\t[self.panel makeKeyAndOrderFront:nil];\n\t}\n}\n\n- (TVCAlertResponseButton)runModal\n{\n\tNSAssert((self.alertFinished == NO),\n\t\t@\"Cannot show alert because it has already finished\");\n\n\t/* Do not allow this method to be called while modal is running */\n\tNSAssert((self.alertVisible == NO),\n\t\t@\"Cannot show alert because it's already visible\");\n\n\t/* Do not allow changes to be made to the alert */\n\tself.alertImmutable = YES;\n\n\t/* Perform layout */\n\t[self _layout];\n\n\t/* Present alert */\n\tself.alertVisible = YES;\n\n\tself.launchedAs = TVCAlertLaunchedAsModal;\n\n\tLogToConsoleDebug(\"[%{public}@] Running modal alert\", self);\n\n\treturn [NSApp runModalForWindow:self.panel];\n}\n\n#pragma mark -\n#pragma mark Layout\n\n- (void)_layout\n{\n\t/* Do not perform more than once */\n\tNSAssert((self.layoutPerformed == NO),\n\t\t@\"Cannot perform layout multiple times\");\n\n\t/* Context */\n\tself.warningIconImageView.hidden = (self.type != TVCAlertTypeWarning);\n\n\tNSView *contentView = self.panel.contentView;\n\n\tNSTextField *messageTextField = self.messageTextField;\n\tNSTextField *informativeTextField = self.informativeTextField;\n\n\tNSView *accessoryView = self.accessoryView;\n\n\tNSButton *suppressionButton = self.suppressionButton;\n\tBOOL showsSuppressionButton = self.showsSuppressionButton;\n\n\tNSView *firstButtonAnchor = nil;\n\n\t/* Toggle accessory view */\n\tif (accessoryView) {\n\t\t[contentView addSubview:accessoryView];\n\n\t\t[contentView addConstraints:\n\t\t @[\n\t\t   /* Align top of accessory view to bottom of informative text field */\n\t\t   [NSLayoutConstraint constraintWithItem:accessoryView\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t\t\trelatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t   toItem:informativeTextField\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeBottom\n\t\t\t\t\t\t\t\t\t   multiplier:1.0\n\t\t\t\t\t\t\t\t\t\t constant:16.0],\n\n\t\t   /* Align leading of accessory view to leading of message text field */\n\t\t   [NSLayoutConstraint constraintWithItem:accessoryView\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeLeading\n\t\t\t\t\t\t\t\t\t\trelatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t   toItem:messageTextField\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeLeading\n\t\t\t\t\t\t\t\t\t   multiplier:1.0\n\t\t\t\t\t\t\t\t\t\t constant:0.0],\n\n\t\t   /* Align trailing of accessory view to trailing of content view */\n\t\t   [NSLayoutConstraint constraintWithItem:contentView\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeTrailing\n\t\t\t\t\t\t\t\t\t\trelatedBy:NSLayoutRelationGreaterThanOrEqual\n\t\t\t\t\t\t\t\t\t\t   toItem:accessoryView\n\t\t\t\t\t\t\t\t\t\tattribute:NSLayoutAttributeTrailing\n\t\t\t\t\t\t\t\t\t   multiplier:1.0\n\t\t\t\t\t\t\t\t\t\t constant:20.0]\n\t\t   ]\n\t\t ];\n\n\t\tfirstButtonAnchor = accessoryView;\n\t}\n\n\t/* Toggle suppression button */\n\tif (showsSuppressionButton) {\n\t\tNSView *buttonAnchor = ((accessoryView) ?: informativeTextField);\n\n\t\t[contentView addConstraint:\n\t\t /* Align top of suppression button with top of anchor */\n\t\t [NSLayoutConstraint constraintWithItem:suppressionButton\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t toItem:buttonAnchor\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeBottom\n\t\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t\t   constant:16.0]\n\t\t ];\n\n\t\tfirstButtonAnchor = suppressionButton;\n\t} else {\n\t\t[suppressionButton removeFromSuperviewWithoutNeedingDisplay];\n\t}\n\n\t/* Add first button */\n\tNSAssert((self.firstButton.hidden == NO),\n\t\t@\"At least one button must be added to alert before presentation\");\n\n\tfirstButtonAnchor = ((firstButtonAnchor) ?: informativeTextField);\n\n\t[contentView addConstraint:\n\t /* Align top of first button with top of anchor */\n\t [NSLayoutConstraint constraintWithItem:self.firstButton\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:firstButtonAnchor\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeBottom\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:20.0]\n\t ];\n\n\t/* Remove buttons we aren't using */\n\t/* We do this because even when hidden, their constraints\n\t still apply to the layout. We could remove the constraints\n\t themselves, but this is an easier solution. */\n\tif (self.thirdButton.hidden) {\n\t\t[self.thirdButton removeFromSuperviewWithoutNeedingDisplay];\n\t}\n\n\tif (self.secondButton.hidden) {\n\t\t[self.secondButton removeFromSuperviewWithoutNeedingDisplay];\n\t}\n\n\t/* Update state */\n\tself.layoutPerformed = YES;\n\n\tLogToConsoleDebug(\"[%{public}@] Layout performed\", self);\n}\n\n#pragma mark -\n#pragma mark Buttons\n\n- (void)buttonPressed:(id)sender\n{\n\tNSInteger buttonClicked = [sender tag];\n\n\tLogToConsoleDebug(\"[%{public}@] Button pressed: %ld\", self, buttonClicked);\n\n\tTVCAlertButtonClickedBlock actionBlock = nil;\n\n\tif (buttonClicked == TVCAlertResponseButtonFirst) {\n\t\tactionBlock = self.firstButtonAction;\n\t} else if (buttonClicked == TVCAlertResponseButtonSecond) {\n\t\tactionBlock = self.secondButtonAction;\n\t} else if (buttonClicked == TVCAlertResponseButtonThird) {\n\t\tactionBlock = self.thirdButtonAction;\n\t}\n\n\tif (actionBlock != nil &&\n\t\tactionBlock(self, buttonClicked) == NO) {\n\n\t\tLogToConsoleDebug(\"[%{public}@] Button action block denied alert dismissal\", self);\n\n\t\treturn;\n\t}\n\n\t[self endAlertWithResponse:buttonClicked];\n}\n\n- (NSArray<NSButton *> *)buttons\n{\n\tNSMutableArray *buttons = [[NSMutableArray alloc] initWithCapacity:3];\n\n\tif (self.firstButton.hidden == NO) {\n\t\t[buttons addObject:self.firstButton];\n\t}\n\n\tif (self.secondButton.hidden == NO) {\n\t\t[buttons addObject:self.secondButton];\n\t}\n\n\tif (self.secondButton.hidden == NO) {\n\t\t[buttons addObject:self.secondButton];\n\t}\n\n\treturn [buttons copy];\n}\n\n- (NSButton *)setTitle:(NSString *)title forButton:(TVCAlertResponseButton)button\n{\n\tswitch (button) {\n\t\tcase TVCAlertResponseButtonFirst:\n\t\t\t[self setTitle:title forButtonAtIndex:0];\n\n\t\t\tbreak;\n\t\tcase TVCAlertResponseButtonSecond:\n\t\t\t[self setTitle:title forButtonAtIndex:1];\n\n\t\t\tbreak;\n\t\tcase TVCAlertResponseButtonThird:\n\t\t\t[self setTitle:title forButtonAtIndex:2];\n\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tNSAssert(NO, @\"Invalid button type\");\n\n\t\t\tbreak;\n\t}\n\n\treturn nil;\n}\n\n- (NSButton *)setTitle:(NSString *)title forButtonAtIndex:(NSUInteger)index\n{\n\tNSAssert((index >= 0 && index <= 2),\n\t\t@\"Index of button is out of bounds. \"\n\t\t\"Index: %lu, Range: 0 - 2\", index);\n\n\tNSButton *button = nil;\n\n\tif (index == 0) {\n\t\tbutton = self.firstButton;\n\t} else if (index == 1) {\n\t\tbutton = self.secondButton;\n\t} else if (index == 2) {\n\t\tbutton = self.thirdButton;\n\t}\n\n\treturn [self _setTitle:title forButton:button];\n}\n\n- (NSButton *)_setTitle:(NSString *)title forButton:(NSButton *)button\n{\n\tNSParameterAssert(title != nil);\n\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot add button because alert is immutable\");\n\n\tif (button.hidden) {\n\t\tbutton.hidden = NO;\n\t}\n\n\tbutton.title = title;\n\n\tbutton.accessibilityTitle = TXTLS(@\"Accessibility[wbj-gr]\", title);\n\n\treturn button;\n}\n\n- (void)setButtonClickedBlock:(nullable TVCAlertButtonClickedBlock)block forButton:(TVCAlertResponseButton)button\n{\n\tswitch (button) {\n\t\tcase TVCAlertResponseButtonFirst:\n\t\t\t[self setButtonClickedBlock:block forButtonAtIndex:0];\n\n\t\t\tbreak;\n\t\tcase TVCAlertResponseButtonSecond:\n\t\t\t[self setButtonClickedBlock:block forButtonAtIndex:1];\n\n\t\t\tbreak;\n\t\tcase TVCAlertResponseButtonThird:\n\t\t\t[self setButtonClickedBlock:block forButtonAtIndex:2];\n\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tNSAssert(NO, @\"Invalid button type\");\n\n\t\t\tbreak;\n\t}\n}\n\n- (void)setButtonClickedBlock:(nullable TVCAlertButtonClickedBlock)block forButtonAtIndex:(NSUInteger)index\n{\n\tNSAssert((self.alertFinished == NO),\n\t\t@\"Cannot set button clicked block because alert is finished\");\n\n\tNSAssert((index >= 0 && index <= 2),\n\t\t@\"Index of button is out of bounds. \"\n\t\t\"Index: %lu, Range: 0 - 2\", index);\n\n\tif (index == 0) {\n\t\tself.firstButtonAction = block;\n\t} else if (index == 1) {\n\t\tself.secondButtonAction = block;\n\t} else if (index == 2) {\n\t\tself.thirdButtonAction = block;\n\t}\n\n\tLogToConsoleDebug(\"[%{public}@] Setting button action block at index: %lu\", self, index);\n}\n\n- (void)endAlert\n{\n\t[self endAlertWithResponse:TVCAlertResponseButtonFirst];\n}\n\n- (void)endAlertWithResponse:(TVCAlertResponseButton)response\n{\n\tNSAssert((self.alertFinished == NO),\n\t\t@\"Cannot end alert because it has already finished\");\n\n\tNSAssert(self.alertVisible,\n\t\t@\"Cannot end alert because it isn't visible\");\n\n\tself.alertFinished = YES;\n\n\tswitch (self.launchedAs) {\n\t\tcase TVCAlertLaunchedAsNonblockingPanel:\n\t\t{\n\t\t\t[self _postCompletionBlockWithResponse:response];\n\n\t\t\t[self.panel orderOut:nil];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TVCAlertLaunchedAsSheet:\n\t\t{\n\t\t\t[NSApp endSheet:self.panel returnCode:response];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase TVCAlertLaunchedAsModal:\n\t\t{\n\t\t\t[NSApp stopModalWithCode:response];\n\n\t\t\t[self.panel orderOut:nil];\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tLogToConsoleDebug(\"[%{public}@] Alert dismissed\", self);\n\n\tself.alertVisible = NO;\n\n\t// Dereference completion block when finished because the\n\t// completion block may be the only reference to self.\n\tself.completionBlock = nil;\n}\n\n#pragma mark -\n#pragma mark Setter/Getter\n\n- (NSImage *)icon\n{\n\treturn self.iconImageView.image;\n}\n\n- (void)setIcon:(nullable NSImage *)icon\n{\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot change value because alert is immutable\");\n\n\tif (icon == nil) {\n\t\ticon = [NSImage imageNamed:@\"NSApplicationIcon\"];\n\t}\n\n\tself.iconImageView.image = icon;\n}\n\n- (NSString *)messageText\n{\n\treturn self.messageTextField.stringValue;\n}\n\n- (void)setMessageText:(NSString *)messageText\n{\n\tNSParameterAssert(messageText != nil);\n\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot change value because alert is immutable\");\n\n\tself.messageTextField.stringValue = messageText;\n}\n\n- (NSString *)informativeText\n{\n\treturn self.informativeTextField.stringValue;\n}\n\n- (void)setInformativeText:(NSString *)informativeText\n{\n\tNSParameterAssert(informativeText != nil);\n\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot change value because alert is immutable\");\n\n\tself.informativeTextField.stringValue = informativeText;\n}\n\n- (void)setShowsSuppressionButton:(BOOL)showsSuppressionButton\n{\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot change value because alert is immutable\");\n\n\tif (self->_showsSuppressionButton != showsSuppressionButton) {\n\t\tself->_showsSuppressionButton = showsSuppressionButton;\n\t}\n}\n\n- (void)setAccessoryView:(nullable NSView *)accessoryView\n{\n\tNSAssert((self.alertImmutable == NO),\n\t\t@\"Cannot change value because alert is immutable\");\n\n\tif (self->_accessoryView != accessoryView) {\n\t\tself->_accessoryView = accessoryView;\n\t}\n}\n\n- (NSWindow *)window\n{\n\treturn self.panel;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)_postCompletionBlockWithResponse:(TVCAlertResponseButton)response\n{\n\tif (self.completionBlock) {\n\t\tself.completionBlock(self, response);\n\t}\n}\n\n#pragma mark -\n#pragma mark Panel Delegate\n\n- (void)_alertSheetDidEndWithReturnCode:(NSInteger)returnCode\n{\n\t[self _postCompletionBlockWithResponse:returnCode];\n\n\t[self.panel orderOut:nil];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Errors/TVCErrorMessagePopover.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCErrorMessagePopoverPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _messageMaximumWidth \t\t\t330.0\n#define _messageHorizontalPadding\t\t5.0\n#define _messageVerticalPadding\t\t\t5.0\n#define _errorIconWidth\t\t\t\t\t15.0\n#define _errorIconHeight\t\t\t\t15.0\n#define _errorIconHorizontalPadding\t\t5.0\n#define _errorIconVerticalPadding\t\t6.0\n\n@interface TVCErrorMessagePopoverView : NSPopover\n@end\n\n@interface TVCErrorMessagePopover ()\n@property (nonatomic, strong, nullable) NSPopover *popover;\n@end\n\n@implementation TVCErrorMessagePopover\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithMessage:(NSString *)message relativeToView:(NSView *)view\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(view != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_message = [message copy];\n\n\t\tself->_view = view;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self close];\n}\n\n- (void)_createPopover\n{\n\t/* Create view controller */\n\tNSViewController *viewController = [NSViewController new];\n\n\t/* Create view */\n\tNSView *popoverView = [[NSView alloc] initWithFrame:NSZeroRect];\n\n\tpopoverView.translatesAutoresizingMaskIntoConstraints = NO;\n\n\tviewController.view = popoverView;\n\n\t/* Create image view */\n\tNSImageView *errorIcon = [NSImageView new];\n\n\terrorIcon.translatesAutoresizingMaskIntoConstraints = NO;\n\n\terrorIcon.editable = NO;\n\n\terrorIcon.image = [NSImage imageNamed:@\"ErroneousTextFieldValueIndicator\"];\n\n\t[errorIcon addConstraints:\n\t \t@[\n\t\t [NSLayoutConstraint constraintWithItem:errorIcon\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeWidth\n\t\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t toItem:nil\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeNotAnAttribute\n\t\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t\t   constant:_errorIconWidth],\n\n\t\t [NSLayoutConstraint constraintWithItem:errorIcon\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeHeight\n\t\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t toItem:nil\n\t\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeNotAnAttribute\n\t\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t\t   constant:_errorIconHeight]\n\t \t]\n\t ];\n\n\t[popoverView addSubview:errorIcon];\n\n\t[popoverView addConstraints:\n\t \t@[\n\t\t  [NSLayoutConstraint constraintWithItem:errorIcon\n\t\t\t\t\t\t\t\t\t   attribute:NSLayoutAttributeLeading\n\t\t\t\t\t\t\t\t\t   relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t  toItem:popoverView\n\t\t\t\t\t\t\t\t\t   attribute:NSLayoutAttributeLeading\n\t\t\t\t\t\t\t\t\t  multiplier:1.0\n\t\t\t\t\t\t\t\t\t\tconstant:_errorIconHorizontalPadding],\n\n\t\t  [NSLayoutConstraint constraintWithItem:errorIcon\n\t\t\t\t\t\t\t\t\t   attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t\t   relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t\t  toItem:popoverView\n\t\t\t\t\t\t\t\t\t   attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t\t  multiplier:1.0\n\t\t\t\t\t\t\t\t\t\tconstant:_errorIconVerticalPadding],\n\t\t]\n\t ];\n\n\t/* Create message */\n\tNSTextField *errorMessage = [NSTextField new];\n\n\terrorMessage.translatesAutoresizingMaskIntoConstraints = NO;\n\n\terrorMessage.editable = NO;\n\n\terrorMessage.bordered = NO;\n\terrorMessage.drawsBackground = NO;\n\n\terrorMessage.stringValue = self.message;\n\n\terrorMessage.cell.wraps = YES;\n\n\terrorMessage.preferredMaxLayoutWidth = _messageMaximumWidth;\n\n\t/* Add message */\n\t[popoverView addSubview:errorMessage];\n\n\t[popoverView addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:[errorIcon]-messageHorizontalPadding-[errorMessage]-messageHorizontalPadding-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:@{@\"messageHorizontalPadding\" : @(_messageHorizontalPadding)}\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(errorIcon, errorMessage)]];\n\n\t[popoverView addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-messageVerticalPadding-[errorMessage]-messageVerticalPadding-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:@{@\"messageVerticalPadding\" : @(_messageVerticalPadding)}\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(errorMessage)]];\n\n\t/* Create popover */\n\tNSPopover *popover = [TVCErrorMessagePopoverView new];\n\n\tpopover.delegate = (id)self;\n\n\tpopover.contentViewController = viewController;\n\n\tpopover.behavior = NSPopoverBehaviorTransient;\n\n\tpopover.animates = NO;\n\n\tself.popover = popover;\n}\n\n- (void)showRelativeToRect:(NSRect)rect\n{\n\t[self showRelativeToRect:rect preferredEdge:NSRectEdgeMaxY];\n}\n\n- (void)showRelativeToRect:(NSRect)rect preferredEdge:(NSRectEdge)preferredEdge\n{\n\tif (self.popover == nil) {\n\t\t[self _createPopover];\n\t}\n\n\t[self.popover showRelativeToRect:rect ofView:self.view preferredEdge:preferredEdge];\n}\n\n- (void)close\n{\n\tNSPopover *popover = self.popover;\n\n\tif (popover == nil) {\n\t\treturn;\n\t}\n\n\t[popover close];\n\n\tself.popover = nil;\n}\n\n- (void)popoverWillShow:(NSNotification *)notification\n{\n\tif ([self.delegate respondsToSelector:@selector(errorMessagePopoverWillShow:)]) {\n\t\t[self.delegate errorMessagePopoverWillShow:self];\n\t}\n}\n\n- (void)popoverDidShow:(NSNotification *)notification\n{\n\tif ([self.delegate respondsToSelector:@selector(errorMessagePopoverDidShow:)]) {\n\t\t[self.delegate errorMessagePopoverDidShow:self];\n\t}\n}\n\n- (void)popoverWillClose:(NSNotification *)notification\n{\n\tif ([self.delegate respondsToSelector:@selector(errorMessagePopoverWillClose:)]) {\n\t\t[self.delegate errorMessagePopoverWillClose:self];\n\t}\n}\n\n- (void)popoverDidClose:(NSNotification *)notification\n{\n\tif ([self.delegate respondsToSelector:@selector(errorMessagePopoverDidClose:)]) {\n\t\t[self.delegate errorMessagePopoverDidClose:self];\n\t}\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCErrorMessagePopoverView\n\n- (void)mouseDown:(NSEvent *)event\n{\n\t[self close];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Errors/TVCErrorMessagePopoverController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCErrorMessagePopoverPrivate.h\"\n#import \"TVCErrorMessagePopoverControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCErrorMessagePopoverController ()\n@property (nonatomic, strong, nullable) TVCErrorMessagePopover *visiblePopover;\n@end\n\n@implementation TVCErrorMessagePopoverController\n\n#pragma mark -\n#pragma mark Public\n\n+ (TVCErrorMessagePopoverController *)sharedController\n{\n\tstatic TVCErrorMessagePopoverController *sharedSelf = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsharedSelf = [self new];\n\t});\n\n\treturn sharedSelf;\n}\n\n- (void)showMessage:(NSString *)message forView:(NSView *)view\n{\n\tNSParameterAssert(message != nil);\n\tNSParameterAssert(view != nil);\n\n\tTVCErrorMessagePopover *popover = self.visiblePopover;\n\n\tBOOL popoverIsSame =\n\t(popover && popover.view == view && [popover.message isEqualToString:message]);\n\n\tif (popoverIsSame == NO) {\n\t\t/* Close message already on screen being tracked */\n\t\tif (popover) {\n\t\t\t[popover close];\n\t\t}\n\n\t\t/* Show message */\n\t\tpopover = [[TVCErrorMessagePopover alloc] initWithMessage:message relativeToView:view];\n\t}\n\n\t[popover showRelativeToRect:view.bounds];\n\n\tif (popoverIsSame == NO) {\n\t\tself.visiblePopover = popover;\n\t}\n}\n\n- (void)closeMessage\n{\n\t[self _closePopoverForView:nil];\n}\n\n- (void)closeMessageForView:(NSView *)view\n{\n\t[self _closePopoverForView:view];\n}\n\n#pragma mark -\n#pragma mark Private\n\n- (void)_closePopoverForView:(nullable NSView *)view\n{\n\tTVCErrorMessagePopover *popover = self.visiblePopover;\n\n\tif (popover == nil || (view && view != popover.view)) {\n\t\treturn;\n\t}\n\n\t[popover close];\n\n\tself.visiblePopover = nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCAutoExpandingTextField.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAutoExpandingTextField.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TVCAutoExpandingTextField\n\n- (NSSize)intrinsicContentSize\n{\n\tif (self.cell.wraps == NO) {\n\t\treturn super.intrinsicContentSize;\n\t}\n\n\tNSRect originalFrame = self.frame;\n\n\toriginalFrame.size.height = CGFLOAT_MAX;\n\n\tNSSize newFrameSize = [self.cell cellSizeForBounds:originalFrame];\n\n\treturn newFrameSize;\n}\n\n- (void)textDidChange:(NSNotification *)notification\n{\n\t[super textDidChange:notification];\n\n\t[self invalidateIntrinsicContentSize];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCAutoExpandingTokenField.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAutoExpandingTokenField.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TVCAutoExpandingTokenField\n\n- (NSSize)intrinsicContentSize\n{\n\tif (self.cell.wraps == NO) {\n\t\treturn super.intrinsicContentSize;\n\t}\n\n\tNSRect originalFrame = self.frame;\n\n\toriginalFrame.size.height = CGFLOAT_MAX;\n\n\tNSSize newFrameSize = [self.cell cellSizeForBounds:originalFrame];\n\n\treturn newFrameSize;\n}\n\n- (void)textDidChange:(NSNotification *)notification\n{\n\t[super textDidChange:notification];\n\n\t[self invalidateIntrinsicContentSize];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCTextFormatterMenu.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSColorHelper.h\"\n#import \"IRCColorFormat.h\"\n#import \"TLOLocalization.h\"\n#import \"TVCTextViewWithIRCFormatterPrivate.h\"\n#import \"TVCTextFormatterMenuPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _formattingMenuRainbowColorMenuItemTag\t\t\t299\n#define _formattingMenuHexColorMenuItemTag\t\t\t\t300\n\n@interface TVCTextViewIRCFormattingMenu () <NSMenuItemValidation>\n@property (readonly, nullable) TVCTextViewWithIRCFormatter *textField;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *formatterMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenu *foregroundColorMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenu *backgroundColorMenu;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *foregroundColorSetMenuItem;\n@property (nonatomic, weak, readwrite) IBOutlet NSMenuItem *backgroundColorSetMenuItem;\n\n- (IBAction)emptyAction:(id)sender;\n@end\n\n@implementation TVCTextViewIRCFormattingMenu\n\n#pragma mark -\n#pragma mark Menu Management\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\t[self generateColorList];\n}\n\n- (nullable TVCTextViewWithIRCFormatter *)textField\n{\n\tid firstResponder = [[NSApp keyWindow] firstResponder];\n\n\tif ([firstResponder isKindOfClass:[TVCTextViewWithIRCFormatter class]]) {\n\t\treturn firstResponder;\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)validateMenuItem:(NSMenuItem *)item\n{\n\tif (self.textField == nil) {\n\t\treturn NO;\n\t}\n\n\tswitch (item.tag) {\n\t\tcase 100: // Bold\n\t\t{\n\t\t\tBOOL boldText = self.textIsBold;\n\n\t\t\titem.state = boldText;\n\n\t\t\tif (boldText) {\n\t\t\t\titem.action = @selector(removeBoldCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertBoldCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 101: // Italics\n\t\t{\n\t\t\tBOOL italicText = self.textIsItalicized;\n\n\t\t\titem.state = italicText;\n\n\t\t\tif (italicText) {\n\t\t\t\titem.action = @selector(removeItalicCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertItalicCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 102: // Monospace\n\t\t{\n\t\t\tBOOL monospaceText = self.textIsMonospace;\n\n\t\t\titem.state = monospaceText;\n\n\t\t\tif (monospaceText) {\n\t\t\t\titem.action = @selector(removeMonospaceCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertMonospaceCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 103: // Spoiler\n\t\t{\n\t\t\tBOOL spoilerText = self.textHasSpoiler;\n\n\t\t\titem.state = spoilerText;\n\n\t\t\tif (spoilerText) {\n\t\t\t\titem.action = @selector(removeSpoilerCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertSpoilerCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 104: // Strikethrough\n\t\t{\n\t\t\tBOOL struckthroughText = self.textIsStruckthrough;\n\n\t\t\titem.state = struckthroughText;\n\n\t\t\tif (struckthroughText) {\n\t\t\t\titem.action = @selector(removeStrikethroughCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertStrikethroughCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 105: // Underline\n\t\t{\n\t\t\tBOOL underlineText = self.textIsUnderlined;\n\n\t\t\titem.state = underlineText;\n\n\t\t\tif (underlineText) {\n\t\t\t\titem.action = @selector(removeUnderlineCharFromTextBox:);\n\t\t\t} else {\n\t\t\t\titem.action = @selector(insertUnderlineCharIntoTextBox:);\n\t\t\t}\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 108: // Foreground Color Missing\n\t\t{\n\t\t\titem.hidden = self.textHasForegroundColor;\n\n\t\t\treturn YES;\n\t\t}\n\t\tcase 107: // Foreground Color Set\n\t\t{\n\t\t\titem.hidden = (self.textHasForegroundColor == NO);\n\n\t\t\t/* Do not enable menu item when there is spoiler */\n\t\t\treturn (self.textHasSpoiler == NO);\n\t\t}\n\t\tcase 110: // Background Color Missing\n\t\t{\n\t\t\titem.hidden = self.textHasBackgroundColor;\n\n\t\t\t/* Require foreground color before background color can be set */\n\t\t\treturn self.textHasForegroundColor;\n\t\t}\n\t\tcase 109: // Background Color Set\n\t\t{\n\t\t\titem.hidden = (self.textHasBackgroundColor == NO);\n\n\t\t\treturn (self.textHasSpoiler == NO);\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (void)emptyAction:(id)sender\n{\n\t/* Empty action used to validate submenus */\n}\n\n#pragma mark -\n#pragma mark Menu Generation\n\n- (void)generateColorList\n{\n\t/* While we could technically load this from a file; we don't need to.\n\t That just adds extra space to the app when we already need to have an\n\t array of colors in the binary. */\n\tNSColorList *colorList = [[NSColorList alloc] initWithName:TXTLS(@\"iwp-cg\")];\n\n\t[[NSColor formatterColors] enumerateObjectsUsingBlock:^(NSColor *color, NSUInteger index, BOOL *stop) {\n\t\t[colorList setColor:color forKey:TXTLS(@\"ham-vk\", index)];\n\t}];\n\n\t[[NSColorPanel sharedColorPanel] attachColorList:colorList];\n}\n\n#pragma mark -\n#pragma mark Formatting Properties\n\n- (BOOL)propertyIsSet:(IRCTextFormatterEffectType)formatterEffect\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\treturn [self.textField.attributedString IRCFormatterAttributeSetInRange:formatterEffect range:selectedTextRange];\n}\n\n- (BOOL)textIsBold\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectBold];\n}\n\n- (BOOL)textIsItalicized\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectItalic];\n}\n\n- (BOOL)textIsMonospace\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectMonospace];\n}\n\n- (BOOL)textIsStruckthrough\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectStrikethrough];\n}\n\n- (BOOL)textIsUnderlined\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectUnderline];\n}\n\n- (BOOL)textHasForegroundColor\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectForegroundColor];\n}\n\n- (BOOL)textHasBackgroundColor\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectBackgroundColor];\n}\n\n- (BOOL)textHasSpoiler\n{\n\treturn [self propertyIsSet:IRCTextFormatterEffectSpoiler];\n}\n\n#pragma mark -\n#pragma mark Formatting Storage Helpers\n\n- (void)applyEffectToTextBox:(IRCTextFormatterEffectType)formatterEffect withValue:(id)value inRange:(NSRange)limitRange\n{\n\tNSMutableAttributedString *stringMutableCopy = [self mutableStringAtRange:limitRange];\n\n\tif (stringMutableCopy == nil) {\n\t\treturn;\n\t}\n\n\t[self applyEffect:formatterEffect withValue:value toMutableString:stringMutableCopy];\n\n\t[self applyAttributedStringToTextBox:stringMutableCopy inRange:limitRange];\n\n\tif (value == nil &&\n\t\t(formatterEffect == IRCTextFormatterEffectForegroundColor ||\n\t\t formatterEffect == IRCTextFormatterEffectSpoiler))\n\t{\n\t\t[self.textField resetFontColorInRange:limitRange];\n\t}\n\n\tif (formatterEffect == IRCTextFormatterEffectMonospace && value == nil) {\n\t\t[self.textField resetFontInRange:limitRange];\n\t}\n}\n\n- (nullable NSMutableAttributedString *)mutableStringAtRange:(NSRange)limitRange\n{\n\tif (limitRange.location == NSNotFound || limitRange.length == 0) {\n\t\treturn nil;\n\t}\n\n\tNSAttributedString *stringSubstring = [self.textField.attributedString attributedSubstringFromRange:limitRange];\n\n\treturn [stringSubstring mutableCopy];\n}\n\n- (void)applyEffect:(IRCTextFormatterEffectType)formatterEffect withValue:(id)value toMutableString:(NSMutableAttributedString *)mutableString\n{\n\t[self applyEffect:formatterEffect withValue:value inRange:mutableString.range toMutableString:mutableString];\n}\n\n- (void)applyEffect:(IRCTextFormatterEffectType)formatterEffect withValue:(id)value inRange:(NSRange)limitRange toMutableString:(NSMutableAttributedString *)mutableString\n{\n\tif (value) {\n\t\t[mutableString setIRCFormatterAttribute:formatterEffect value:value range:limitRange];\n\t} else {\n\t\t[mutableString removeIRCFormatterAttribute:formatterEffect range:limitRange];\n\t}\n}\n\n- (void)applyAttributedStringToTextBox:(NSMutableAttributedString *)mutableString inRange:(NSRange)limitRange\n{\n\tif ([self.textField shouldChangeTextInRange:limitRange replacementString:mutableString.string] == NO) {\n\t\treturn;\n\t}\n\n\t[self.textField.textStorage replaceCharactersInRange:limitRange withAttributedString:mutableString];\n\n\t[self.textField didChangeText];\n\n\t[self.textField setSelectedRange:limitRange];\n}\n\n#pragma mark -\n#pragma mark Add Formatting\n\n- (void)insertBoldCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBold withValue:@(YES) inRange:selectedTextRange];\n}\n\n- (void)insertItalicCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectItalic withValue:@(YES) inRange:selectedTextRange];\n}\n\n- (void)insertMonospaceCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectMonospace withValue:@(YES) inRange:selectedTextRange];\n}\n\n- (void)insertStrikethroughCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectStrikethrough withValue:@(YES) inRange:selectedTextRange];\n}\n\n- (void)insertUnderlineCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectUnderline withValue:@(YES) inRange:selectedTextRange];\n}\n\n- (void)insertForegroundColorCharIntoTextBox:(id)sender\n{\n\tif ([sender tag] == _formattingMenuRainbowColorMenuItemTag) {\n\t\t[self insertRainbowColorCharInfoTextBox:sender asForegroundColor:YES];\n\n\t\treturn;\n\t}\n\telse if ([sender tag] == _formattingMenuHexColorMenuItemTag)\n\t{\n\t\tNSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];\n\n\t\t[colorPanel setTarget:self];\n\t\t[colorPanel setAction:@selector(foregroundColorPanelColorChanged:)];\n\t\t[colorPanel setAlphaValue:1.0];\n\t\t[colorPanel setMode:NSColorPanelModeColorList];\n\t\t[colorPanel setColor:[NSColor formatterWhiteColor]];\n\n\t\t[colorPanel orderFront:nil];\n\t}\n\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:@([sender tag]) inRange:selectedTextRange];\n}\n\n- (void)insertBackgroundColorCharIntoTextBox:(id)sender\n{\n\tif ([sender tag] == _formattingMenuRainbowColorMenuItemTag)\n\t{\n\t\t[self insertRainbowColorCharInfoTextBox:sender asForegroundColor:NO];\n\n\t\treturn;\n\t}\n\telse if ([sender tag] == _formattingMenuHexColorMenuItemTag)\n\t{\n\t\tNSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];\n\n\t\t[colorPanel setTarget:self];\n\t\t[colorPanel setAction:@selector(backgroundColorPanelColorChanged:)];\n\t\t[colorPanel setAlphaValue:1.0];\n\t\t[colorPanel setMode:NSColorPanelModeColorList];\n\t\t[colorPanel setColor:[NSColor formatterBlackColor]];\n\n\t\t[colorPanel orderFront:nil];\n\t}\n\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:@([sender tag]) inRange:selectedTextRange];\n}\n\n- (void)insertRainbowColorCharInfoTextBox:(id)sender asForegroundColor:(BOOL)asForegroundColor\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\tNSMutableAttributedString *mutableStringCopy = [self mutableStringAtRange:selectedTextRange];\n\n\tif (mutableStringCopy == nil) {\n\t\treturn;\n\t}\n\n\t[mutableStringCopy beginEditing];\n\n\tNSUInteger rainbowArrayIndex = 0;\n\n\tNSArray *colorCodes = @[@(4), @(7), @(8), @(3), @(12), @(2), @(6)];\n\n\tfor (NSUInteger charCountIndex = 0; charCountIndex < mutableStringCopy.length; charCountIndex++) {\n\t\tif (rainbowArrayIndex > 6) {\n\t\t\trainbowArrayIndex = 0;\n\t\t}\n\n\t\tNSUInteger currentColorCode = [colorCodes unsignedIntegerAtIndex:rainbowArrayIndex];\n\n\t\tNSRange currentCharacterRange = NSMakeRange(charCountIndex, 1);\n\n\t\tif (asForegroundColor) {\n\t\t\t[self applyEffect:IRCTextFormatterEffectForegroundColor withValue:@(currentColorCode) inRange:currentCharacterRange toMutableString:mutableStringCopy];\n\t\t} else {\n\t\t\t[self applyEffect:IRCTextFormatterEffectBackgroundColor withValue:@(currentColorCode) inRange:currentCharacterRange toMutableString:mutableStringCopy];\n\t\t}\n\n\t\trainbowArrayIndex += 1;\n\t}\n\n\t[mutableStringCopy endEditing];\n\n\t[self applyAttributedStringToTextBox:mutableStringCopy inRange:selectedTextRange];\n}\n\n- (void)foregroundColorPanelColorChanged:(NSColorPanel *)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\tNSColor *color = sender.color;\n\n\tNSUInteger colorDigit = [[NSColor formatterColors] indexOfObject:color];\n\n\tif (colorDigit == NSNotFound) {\n\t\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:color inRange:selectedTextRange];\n\t} else {\n\t\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:@(colorDigit) inRange:selectedTextRange];\n\t}\n}\n\n- (void)backgroundColorPanelColorChanged:(NSColorPanel *)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\tNSColor *color = sender.color;\n\n\tNSUInteger colorDigit = [[NSColor formatterColors] indexOfObject:color];\n\n\tif (colorDigit == NSNotFound) {\n\t\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:color inRange:selectedTextRange];\n\t} else {\n\t\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:@(colorDigit) inRange:selectedTextRange];\n\t}\n}\n\n- (void)insertSpoilerCharIntoTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectSpoiler withValue:@(YES) inRange:selectedTextRange];\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:@(14) inRange:selectedTextRange];\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:@(14) inRange:selectedTextRange];\n}\n\n#pragma mark -\n#pragma mark Remove Formatting\n\n- (void)removeBoldCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBold withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeItalicCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectItalic withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeMonospaceCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectMonospace withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeStrikethroughCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectStrikethrough withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeUnderlineCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectUnderline withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeForegroundColorCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeBackgroundColorCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:nil inRange:selectedTextRange];\n}\n\n- (void)removeSpoilerCharFromTextBox:(id)sender\n{\n\tNSRange selectedTextRange = self.textField.selectedRange;\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectForegroundColor withValue:nil inRange:selectedTextRange];\n\t[self applyEffectToTextBox:IRCTextFormatterEffectBackgroundColor withValue:nil inRange:selectedTextRange];\n\n\t[self applyEffectToTextBox:IRCTextFormatterEffectSpoiler withValue:nil inRange:selectedTextRange];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCTextViewWithIRCFormatter.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"IRCColorFormat.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCTextViewWithIRCFormatterPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define TVCTextViewWithIRCFormatterWidthPadding\t\t1.0\n#define TVCTextViewWithIRCFormatterHeightPadding\t2.0\n\n@interface TVCTextViewWithIRCFormatter ()\n@property (nonatomic, strong) TLOKeyEventHandler *keyEventHandler;\n@end\n\n@implementation TVCTextViewWithIRCFormatter\n\n- (nullable instancetype)initWithCoder:(NSCoder *)coder\n{\n\tif ((self = [super initWithCoder:coder])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.delegate = (id)self;\n\n\tif ([TPCPreferences rightToLeftFormatting]) {\n\t\tself.baseWritingDirection = NSWritingDirectionRightToLeft;\n\t} else {\n\t\tself.baseWritingDirection = NSWritingDirectionLeftToRight;\n\t}\n\n\tself.textContainerInset =\n\t NSMakeSize(TVCTextViewWithIRCFormatterWidthPadding,\n\t\t\t\tTVCTextViewWithIRCFormatterHeightPadding);\n\n\tself.keyEventHandler = [[TLOKeyEventHandler alloc] initWithTarget:self];\n\n\t// The following serve as defaults and are supposed to be replaced\n\tself.preferredFont = [NSFont systemFontOfSize:[NSFont systemFontSize]];\n\tself.preferredFontColor = [NSColor textColor];\n}\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\t[self.window makeFirstResponder:self];\n\n\t[super mouseDown:theEvent];\n}\n\n#pragma mark -\n#pragma mark Keyboard Shortcuts\n\n- (void)setKeyHandlerTarget:(id)target\n{\n\t[self.keyEventHandler setKeyHandlerTarget:target];\n}\n\n- (void)registerSelector:(SEL)selector key:(NSUInteger)keyCode modifiers:(NSUInteger)modifiers\n{\n\t[self.keyEventHandler registerSelector:selector key:keyCode modifiers:modifiers];\n}\n\n- (void)registerSelector:(SEL)selector character:(UniChar)character modifiers:(NSUInteger)modifiers\n{\n\t[self.keyEventHandler registerSelector:selector character:character modifiers:modifiers];\n}\n\n- (void)registerSelector:(SEL)selector characters:(NSRange)characterRange modifiers:(NSUInteger)modifiers\n{\n\t[self.keyEventHandler registerSelector:selector characters:characterRange modifiers:modifiers];\n}\n\n- (BOOL)performedCustomKeyboardEvent:(NSEvent *)e\n{\n\tif ([self.keyEventHandler processKeyEvent:e]) {\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)keyDownToSuper:(NSEvent *)e\n{\n\t[super keyDown:e];\n}\n\n#pragma mark -\n#pragma mark Value Management\n\n- (NSArray<NSString *> *)readablePasteboardTypes\n{\n\treturn @[NSPasteboardTypeString, NSFilenamesPboardType];\n}\n\n- (NSArray<NSString *> *)acceptableDragTypes\n{\n\treturn @[NSPasteboardTypeString, NSFilenamesPboardType];\n}\n\n- (NSString *)stringValue\n{\n\treturn [self.string copy];\n}\n\n- (NSString *)stringValueWithIRCFormatting\n{\n\treturn self.attributedString.stringFormattedForIRC;\n}\n\n- (void)setStringValue:(NSString *)stringValue\n{\n\tNSParameterAssert(stringValue != nil);\n\n\t[self.textStorage replaceCharactersInRange:self.range withString:stringValue];\n\n\t[self didChangeText];\n}\n\n- (NSAttributedString *)attributedStringValue\n{\n\treturn [[self attributedString] copy];\n}\n\n- (void)setAttributedStringValue:(NSAttributedString *)attributedStringValue\n{\n\tNSParameterAssert(attributedStringValue != nil);\n\n\t[self.undoManager removeAllActions];\n\n\t[self.textStorage replaceCharactersInRange:self.range withAttributedString:attributedStringValue];\n\n\t[self didChangeText];\n}\n\n- (void)setStringValueWithIRCFormatting:(NSString *)stringValueWithIRCFormatting\n{\n\tNSParameterAssert(stringValueWithIRCFormatting != nil);\n\n\tNSAttributedString *formattedValue =\n\t[stringValueWithIRCFormatting attributedStringWithIRCFormatting:self.preferredFont\n\t\t\t\t\t\t\t\t\t\t\t\t preferredFontColor:self.preferredFontColor\n\t\t\t\t\t\t\t\t\t\t  honorFormattingPreference:NO];\n\n\tif (formattedValue) {\n\t\tself.attributedStringValue = formattedValue;\n\t}\n}\n\n#pragma mark -\n\n- (void)textDidChange:(NSNotification *)aNotification\n{\n\tif (self.stringLength < 1) {\n\t\t[self resetTypeSetterAttributes];\n\t}\n}\n\n#pragma mark -\n\n- (void)updateAllFontSizesToMatchTheDefaultFont\n{\n\tCGFloat newPointSize = self.preferredFont.pointSize;\n\n\t[self.textStorage beginEditing];\n\n\t[self.textStorage enumerateAttribute:NSFontAttributeName\n\t\t\t\t\t\t\t\t inRange:self.range\n\t\t\t\t\t\t\t\t options:0\n\t\t\t\t\t\t\t  usingBlock:^(id value, NSRange range, BOOL *stop)\n\t{\n\t\tif (fabs([value pointSize]) == fabs(newPointSize)) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSFont *font = [RZFontManager() convertFont:value toSize:newPointSize];\n\n\t\tif (font) {\n\t\t\t[self.textStorage removeAttribute:NSFontAttributeName range:range];\n\n\t\t\t[self.textStorage addAttribute:NSFontAttributeName value:font range:range];\n\t\t}\n\t}];\n\n\t[self.textStorage endEditing];\n}\n\n- (void)setPreferredFont:(NSFont *)preferredFont\n{\n\tNSParameterAssert(preferredFont != nil);\n\n\tif (self->_preferredFont != preferredFont) {\n\t\tself->_preferredFont = [preferredFont copy];\n\n\t\t[self modifyTypingAttributes:@{\n\t\t\tNSFontAttributeName : self->_preferredFont\n\t\t}];\n\t}\n}\n\n- (void)setPreferredFontColor:(NSColor *)preferredFontColor\n{\n\tNSParameterAssert(preferredFontColor != nil);\n\n\tif (self->_preferredFontColor != preferredFontColor) {\n\t\tself->_preferredFontColor = [preferredFontColor copy];\n\n\t\t[self modifyTypingAttributes:@{\n\t\t\tNSForegroundColorAttributeName : self->_preferredFontColor\n\t\t}];\n\n\t\tself.insertionPointColor = self->_preferredFontColor;\n\t}\n}\n\n- (void)resetTypeSetterAttributes\n{\n\tself.typingAttributes = @{\n\t\tNSFontAttributeName : self.preferredFont,\n\t\tNSForegroundColorAttributeName : self.preferredFontColor\n\t};\n}\n\n- (void)modifyTypingAttributes:(NSDictionary<NSString *, id> *)typingAttributes\n{\n\tNSMutableDictionary *typingAttributesMutable = [self.typingAttributes mutableCopy];\n\n\t[typingAttributesMutable addEntriesFromDictionary:typingAttributes];\n\n\tself.typingAttributes = typingAttributesMutable;\n}\n\n- (void)resetFontInRange:(NSRange)range\n{\n\tNSDictionary *newAttributes = @{\n\t\tNSFontAttributeName : self.preferredFont\n\t};\n\n\t[self.textStorage addAttributes:newAttributes range:range];\n}\n\n- (void)resetFontColorInRange:(NSRange)range\n{\n\tNSDictionary *newAttributes = @{\n\t\tNSForegroundColorAttributeName : self.preferredFontColor\n\t};\n\n\t[self.textStorage addAttributes:newAttributes range:range];\n}\n\n#pragma mark -\n#pragma mark Line Counting\n\n- (NSRect)selectedRect\n{\n\tNSLayoutManager *layoutManager = self.layoutManager;\n\n\tNSRange glyphRange = [layoutManager glyphRangeForCharacterRange:self.selectedRange actualCharacterRange:NULL];\n\tNSRect boundingRect = [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:self.textContainer];\n\n\tNSPoint containerOrigin = [self textContainerOrigin];\n\n\treturn NSInsetRect(boundingRect, containerOrigin.x, containerOrigin.y);\n}\n\n- (TVCTextViewCaretLocation)caretLocation\n{\n\tNSUInteger stringLength = self.stringLength;\n\n\tif (stringLength == 0) {\n\t\treturn TVCTextViewCaretLocationOnlyLine;\n\t}\n\n\tNSRange selectedRange = self.selectedRange;\n\n\tNSLayoutManager *layoutManager = self.layoutManager;\n\n\t/* Check first line */\n\tBOOL inFirstLine = (selectedRange.location == 0);\n\n\tif (inFirstLine == NO) {\n\t\tNSRange firstLineRange;\n\n\t\t[layoutManager lineFragmentRectForGlyphAtIndex:0 effectiveRange:&firstLineRange];\n\n\t\tinFirstLine = (selectedRange.location <= NSMaxRange(firstLineRange));\n\t}\n\n\t/* Check last line */\n\tBOOL inLastLine = (NSMaxRange(selectedRange) == stringLength);\n\n\tif (inLastLine == NO) {\n\t\tNSRange lastLineRange;\n\n\t\t[layoutManager lineFragmentRectForGlyphAtIndex:(stringLength - 1) effectiveRange:&lastLineRange];\n\n\t\tinLastLine = (selectedRange.location >= lastLineRange.location);\n\t}\n\n\t/* Process results */\n\tif (inFirstLine && inLastLine) {\n\t\treturn TVCTextViewCaretLocationOnlyLine;\n\t} else if (inFirstLine) {\n\t\treturn TVCTextViewCaretLocationFirstLine;\n\t} else if (inLastLine) {\n\t\treturn TVCTextViewCaretLocationLastLine;\n\t}\n\n\treturn TVCTextViewCaretLocationMiddle;\n}\n\n- (CGFloat)highestHeightBelowHeight:(CGFloat)maximumHeight withPadding:(CGFloat)valuePadding\n{\n\tNSLayoutManager *layoutManager = self.layoutManager;\n\n\tBOOL skipLastFragmentCheck = NO;\n\n\tNSUInteger numberOfGlyphs = layoutManager.numberOfGlyphs;\n\n\tNSUInteger totalLineHeight = valuePadding;\n\n\tfor (NSUInteger i = 0; i < numberOfGlyphs; i++) {\n\t\tNSRange lineRange;\n\n\t\tNSRect rect = [layoutManager lineFragmentRectForGlyphAtIndex:i effectiveRange:&lineRange];\n\n\t\tif ((totalLineHeight +  rect.size.height) <= maximumHeight) {\n\t\t\ttotalLineHeight  += rect.size.height;\n\t\t} else {\n\t\t\tskipLastFragmentCheck = YES;\n\n\t\t\tbreak;\n\t\t}\n\n\t\ti = NSMaxRange(lineRange);\n\t}\n\n\tif (skipLastFragmentCheck) {\n\t\treturn totalLineHeight;\n\t}\n\n\tNSRect lastFragmentRect = layoutManager.extraLineFragmentRect;\n\n\tif ((totalLineHeight +  lastFragmentRect.size.height) <= maximumHeight) {\n\t\ttotalLineHeight  += lastFragmentRect.size.height;\n\t}\n\n\treturn totalLineHeight;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCValidatedComboBox.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TVCErrorMessagePopoverControllerPrivate.h\"\n#import \"TVCValidatedComboBox.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCValidatedComboBox ()\n/* Maintain cached value so that the drawing does not call\n the validation block every time that it is called. */\n@property (nonatomic, assign) BOOL cachedValidValue;\n@property (nonatomic, assign, readwrite) BOOL valueIsPredefined;\n@property (nonatomic, assign) BOOL validationPerformed;\n@property (nonatomic, assign) BOOL listVisible;\n@property (nonatomic, assign) BOOL selectionChangedWhileListVisible;\n@property (nonatomic, assign) BOOL selectionChangedWhileSetting;\n@property (nonatomic, copy, nullable, readwrite) NSString *lastValidationErrorDescription;\n@end\n\n@interface TVCValidatedComboBoxCell ()\n@property (readonly) NSColor *erroneousValueBackgroundColor;\n@property (readonly) BOOL parentValueIsValid;\n@property (readonly) TVCValidatedComboBox *parentField;\n@end\n\n@implementation TVCValidatedComboBox\n\n#pragma mark -\n#pragma mark Public API (Combo Box Text Field)\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.cachedValidValue = NO;\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(comboBoxSelectionDidChange:)\n\t\t\t\t\t\t\t\t   name:NSComboBoxSelectionDidChangeNotification\n\t\t\t\t\t\t\t\t object:self];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(comboBoxWillPopUp:)\n\t\t\t\t\t\t\t\t   name:NSComboBoxWillPopUpNotification\n\t\t\t\t\t\t\t\t object:self];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(comboBoxWillDismiss:)\n\t\t\t\t\t\t\t\t   name:NSComboBoxWillDismissNotification\n\t\t\t\t\t\t\t\t object:self];\n\n}\n\n- (void)dealloc\n{\n\t[self closeValidationErrorPopover];\n\n\t[RZNotificationCenter() removeObserver:self];\n}\n\n- (BOOL)drawsBackground\n{\n\treturn NO;\n}\n\n- (NSString *)value\n{\n\tNSString *stringValue = self.objectValueOfSelectedItem;\n\n\tif (stringValue) {\n\t\treturn stringValue;\n\t}\n\n\tstringValue = self.stringValue;\n\n\tif (self.stringValueUsesOnlyFirstToken) {\n\t\tstringValue = stringValue.trimAndGetFirstToken;\n\t} else if (self.stringValueIsTrimmed) {\n\t\tstringValue = stringValue.trim;\n\t}\n\n\tif (stringValue.length == 0) {\n\t\tif (\t   self.defaultValue && self.stringValueIsInvalidOnEmpty == NO) {\n\t\t\treturn self.defaultValue;\n\t\t}\n\t}\n\n\treturn stringValue;\n}\n\n- (NSString *)lowercaseValue\n{\n\treturn self.value.lowercaseString;\n}\n\n- (NSString *)uppercaseValue\n{\n\treturn self.value.uppercaseString;\n}\n\n- (NSInteger)integerValue\n{\n\treturn self.value.integerValue;\n}\n\n- (void)setIntegerValue:(NSInteger)integerValue\n{\n\tself.stringValue = [NSString stringWithInteger:integerValue];\n}\n\n- (BOOL)valueIsEmpty\n{\n\treturn (self.stringValue.length == 0);\n}\n\n- (BOOL)valueIsValid\n{\n\treturn self.cachedValidValue;\n}\n\n#pragma mark -\n#pragma mark Interval Validation\n\n- (void)comboBoxSelectionDidChange:(NSNotification *)notification\n{\n\tself.selectionChangedWhileListVisible = self.listVisible;\n\n\tif (self.selectionChangedWhileSetting) {\n\t\tself.selectionChangedWhileSetting = NO;\n\n\t\t[self recalculateSelection];\n\t}\n}\n\n- (void)comboBoxWillPopUp:(NSNotification *)notification\n{\n\tself.listVisible = YES;\n}\n\n- (void)comboBoxWillDismiss:(NSNotification *)notification\n{\n\tself.listVisible = NO;\n\n\tif (self.selectionChangedWhileListVisible) {\n\t\tself.selectionChangedWhileListVisible = NO;\n\n\t\t[self recalculateSelection];\n\t}\n}\n\n- (void)textDidChange:(NSNotification *)notification\n{\n\t/* NSComboBoxCell observes NSTextDidChangeNotification to know\n\t when to update the selection index. */\n\t/* Our observance of this notification is competing with theirs\n\t which causes a race condition. To work around this, we wait until\n\t the next pass of the main loop to perform our validation because\n\t the internals of the cell should have selection index up to date\n\t by then to reflect the string value. */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self recalculateSelection];\n\t});\n}\n\n- (void)setStringValue:(NSString *)stringValue\n{\n\tsuper.stringValue = stringValue;\n\n\tNSUInteger objectIndex = [self indexOfItemWithObjectValue:stringValue];\n\n\tif (objectIndex != NSNotFound) {\n\t\tself.selectionChangedWhileSetting = YES;\n\n\t\t[self selectItemAtIndex:objectIndex];\n\n\t\treturn;\n\t}\n\n\t[self resetSelection];\n}\n\n- (void)resetSelection\n{\n\tself.valueIsPredefined = NO;\n\n\t[self _valueChangedAction];\n}\n\n- (void)recalculateSelection\n{\n\tself.valueIsPredefined = (self.indexOfSelectedItem >= 0);\n\n\t[self _valueChangedAction];\n}\n\n- (void)_valueChangedAction\n{\n\tif (self.valueIsPredefined) {\n\t\t/* If predefined selection, then the value is valid\n\t\t no matter what because it is a value WE defined. */\n\t\tself.cachedValidValue = YES;\n\n\t\tself.lastValidationErrorDescription = nil;\n\t} else {\n\t\t[self performValidation];\n\t}\n\n\t[self _valueChangedActionPostflight];\n}\n\n- (void)_valueChangedActionPostflight\n{\n\t[self closeValidationErrorPopover];\n\n\t[self informCallbackTextDidChange];\n\n\t[self setNeedsDisplay:YES];\n}\n\n- (void)informCallbackTextDidChange\n{\n\tif (self.textDidChangeCallback == nil) {\n\t\treturn;\n\t}\n\n\tif ([self.textDidChangeCallback respondsToSelector:@selector(validatedTextFieldTextDidChange:)]) {\n\t\t[self.textDidChangeCallback performSelector:@selector(validatedTextFieldTextDidChange:) withObject:self];\n\t}\n}\n\n- (void)performValidation\n{\n\tNSString *stringToValidate = self.stringValue;\n\n\tNSString *errorDescription = nil;\n\n\tif (stringToValidate.length > 0) {\n\t\tif (self.validationBlock) {\n\t\t\terrorDescription = self.validationBlock(stringToValidate);\n\t\t}\n\t} else {\n\t\tif (self.performValidationWhenEmpty) {\n\t\t\terrorDescription = self.validationBlock(stringToValidate);\n\t\t} else if (self.stringValueIsInvalidOnEmpty) {\n\t\t\terrorDescription = TXTLS(@\"BasicLanguage[fo8-1h]\");\n\t\t}\n\t}\n\n\tself.cachedValidValue = (errorDescription == nil);\n\n\tself.lastValidationErrorDescription = errorDescription;\n\n\tself.validationPerformed = YES;\n}\n\n- (BOOL)showValidationErrorPopover\n{\n\tif (self.validationPerformed == NO) {\n\t\t[self performValidation];\n\t}\n\n\tNSString *errorDescription = self.lastValidationErrorDescription;\n\n\tif (errorDescription == nil) {\n\t\treturn NO;\n\t}\n\n\tif (self.window == nil) {\n\t\treturn NO;\n\t}\n\n\t[[TVCErrorMessagePopoverController sharedController] showMessage:errorDescription forView:self];\n\n\treturn YES;\n}\n\n- (void)closeValidationErrorPopover\n{\n\t[[TVCErrorMessagePopoverController sharedController] closeMessageForView:self];\n}\n\n- (void)viewWillMoveToWindow:(nullable NSWindow *)newWindow\n{\n\t/* While outside logic is responsible for displaying the\n\t validation error message, it would not hurt to help it a\n\t little bit by dismissing the message when the view is no\n\t longer on a window. */\n\tif (newWindow == nil) {\n\t\t[self closeValidationErrorPopover];\n\t}\n}\n\n@end\n\n#pragma mark -\n#pragma mark Text Field Cell\n\n@implementation TVCValidatedComboBoxCell\n\n- (NSColor *)erroneousValueBackgroundColor\n{\n\treturn [NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.05];\n}\n\n- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView\n{\n\tif (self.parentValueIsValid == NO) {\n\t\tNSRect backgroundFrame = cellFrame;\n\n\t\tbackgroundFrame.origin.x += 1.0;\n\t\tbackgroundFrame.origin.y += 1.0;\n\n\t\tbackgroundFrame.size.width -= 2.0;\n\t\tbackgroundFrame.size.height -= 2.0;\n\n\t\tNSColor *backgroundColor = self.erroneousValueBackgroundColor;\n\n\t\tNSBezierPath *backgroundFill = [NSBezierPath bezierPathWithRect:backgroundFrame];\n\n\t\t[backgroundColor set];\n\n\t\t[backgroundFill fill];\n\t}\n\n\t[super drawInteriorWithFrame:cellFrame inView:controlView];\n}\n\n- (TVCValidatedComboBox *)parentField\n{\n\treturn (TVCValidatedComboBox *)self.controlView;\n}\n\n- (BOOL)parentValueIsValid\n{\n\treturn self.parentField.valueIsValid;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Input Text Field/TVCValidatedTextField.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TVCErrorMessagePopoverControllerPrivate.h\"\n#import \"TVCValidatedTextField.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCValidatedTextField ()\n/* Maintain cached value so that the drawing does not call\n the validation block every time that it is called. */\n@property (nonatomic, assign) BOOL cachedValidValue;\n@property (nonatomic, assign) BOOL validationPerformed;\n@property (nonatomic, copy, nullable, readwrite) NSString *lastValidationErrorDescription;\n@end\n\n@interface TVCValidatedTextFieldCell ()\n@property (readonly) NSColor *erroneousValueBackgroundColor;\n@property (readonly) BOOL parentValueIsValid;\n@property (readonly) TVCValidatedTextField *parentField;\n@end\n\n@implementation TVCValidatedTextField\n\n#pragma mark -\n#pragma mark Public API (Normal Text Field)\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.cachedValidValue = NO;\n}\n\n- (void)dealloc\n{\n\t[self closeValidationErrorPopover];\n}\n\n- (BOOL)drawsBackground\n{\n\treturn NO;\n}\n\n- (NSString *)value\n{\n\tNSString *stringValue = self.stringValue;\n\n\tif (self.stringValueUsesOnlyFirstToken) {\n\t\tstringValue = stringValue.trimAndGetFirstToken;\n\t} else if (self.stringValueIsTrimmed) {\n\t\tstringValue = stringValue.trim;\n\t}\n\n\tif (stringValue.length == 0) {\n\t\tif (\t   self.defaultValue && self.stringValueIsInvalidOnEmpty == NO) {\n\t\t\treturn self.defaultValue;\n\t\t}\n\t}\n\n\treturn stringValue;\n}\n\n- (NSString *)lowercaseValue\n{\n\treturn self.value.lowercaseString;\n}\n\n- (NSString *)uppercaseValue\n{\n\treturn self.value.uppercaseString;\n}\n\n- (NSInteger)integerValue\n{\n\treturn self.value.integerValue;\n}\n\n- (void)setIntegerValue:(NSInteger)integerValue\n{\n\tself.stringValue = [NSString stringWithInteger:integerValue];\n}\n\n- (BOOL)valueIsEmpty\n{\n\treturn (self.stringValue.length == 0);\n}\n\n- (BOOL)valueIsValid\n{\n\treturn self.cachedValidValue;\n}\n\n#pragma mark -\n#pragma mark Interval Validation\n\n- (void)textDidChange:(NSNotification *)notification\n{\n\t[self _valueChangedAction];\n}\n\n- (void)setStringValue:(NSString *)stringValue\n{\n\tsuper.stringValue = stringValue;\n\n\t[self _valueChangedAction];\n}\n\n- (void)_valueChangedAction\n{\n\t[self performValidation];\n\n\t[self _valueChangedActionPostflight];\n}\n\n- (void)_valueChangedActionPostflight\n{\n\t[self closeValidationErrorPopover];\n\n\t[self informCallbackTextDidChange];\n}\n\n- (void)informCallbackTextDidChange\n{\n\tif (self.textDidChangeCallback == nil) {\n\t\treturn;\n\t}\n\n\tif ([self.textDidChangeCallback respondsToSelector:@selector(validatedTextFieldTextDidChange:)]) {\n\t\t[self.textDidChangeCallback performSelector:@selector(validatedTextFieldTextDidChange:) withObject:self];\n\t}\n}\n\n- (void)performValidation\n{\n\tNSString *stringToValidate = self.stringValue;\n\n\tNSString *errorDescription = nil;\n\n\tif (stringToValidate.length > 0) {\n\t\tif (self.validationBlock) {\n\t\t\terrorDescription = self.validationBlock(stringToValidate);\n\t\t}\n\t} else {\n\t\tif (self.performValidationWhenEmpty) {\n\t\t\terrorDescription = self.validationBlock(stringToValidate);\n\t\t} else if (self.stringValueIsInvalidOnEmpty) {\n\t\t\terrorDescription = TXTLS(@\"BasicLanguage[fo8-1h]\");\n\t\t}\n\t}\n\n\tself.cachedValidValue = (errorDescription == nil);\n\n\tself.lastValidationErrorDescription = errorDescription;\n\n\tself.validationPerformed = YES;\n}\n\n- (BOOL)showValidationErrorPopover\n{\n\tif (self.validationPerformed == NO) {\n\t\t[self performValidation];\n\t}\n\n\tNSString *errorDescription = self.lastValidationErrorDescription;\n\n\tif (errorDescription == nil) {\n\t\treturn NO;\n\t}\n\n\tif (self.window == nil) {\n\t\treturn NO;\n\t}\n\n\t[[TVCErrorMessagePopoverController sharedController] showMessage:errorDescription forView:self];\n\n\treturn YES;\n}\n\n- (void)closeValidationErrorPopover\n{\n\t[[TVCErrorMessagePopoverController sharedController] closeMessageForView:self];\n}\n\n- (void)viewWillMoveToWindow:(nullable NSWindow *)newWindow\n{\n\t/* While outside logic is responsible for displaying the\n\t validation error message, it would not hurt to help it a\n\t little bit by dismissing the message when the view is no\n\t longer on a window. */\n\tif (newWindow == nil) {\n\t\t[self closeValidationErrorPopover];\n\t}\n}\n\n@end\n\n#pragma mark -\n#pragma mark Text Field Cell\n\n@implementation TVCValidatedTextFieldCell\n\n- (NSColor *)erroneousValueBackgroundColor\n{\n\treturn [NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.05];\n}\n\n- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView\n{\n\tif (self.parentValueIsValid == NO) {\n\t\tNSRect backgroundFrame = cellFrame;\n\n\t\tbackgroundFrame.origin.x += 1.0;\n\t\tbackgroundFrame.origin.y += 1.0;\n\n\t\tbackgroundFrame.size.width -= 2.0;\n\t\tbackgroundFrame.size.height -= 2.0;\n\n\t\tNSColor *backgroundColor = self.erroneousValueBackgroundColor;\n\n\t\tNSBezierPath *backgroundFill = [NSBezierPath bezierPathWithRect:backgroundFrame];\n\n\t\t[backgroundColor set];\n\n\t\t[backgroundFill fill];\n\t}\n\n\t[super drawInteriorWithFrame:cellFrame inView:controlView];\n}\n\n- (TVCValidatedTextField *)parentField\n{\n\treturn (TVCValidatedTextField *)self.controlView;\n}\n\n- (BOOL)parentValueIsValid\n{\n\treturn self.parentField.valueIsValid;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindow.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSStringHelper.h\"\n#import \"IRCChannelPrivate.h\"\n#import \"IRCChannelMode.h\"\n#import \"IRCClientConfig.h\"\n#import \"IRCClientPrivate.h\"\n#import \"IRCTreeItemPrivate.h\"\n#import \"IRCUserRelationsPrivate.h\"\n#import \"IRCWorldPrivate.h\"\n#import \"TVCDockIconPrivate.h\"\n#import \"TVCLogControllerPrivate.h\"\n#import \"TVCLogViewPrivate.h\"\n#import \"TVCMainWindowAppearancePrivate.h\"\n#import \"TVCMainWindowChannelViewPrivate.h\"\n#import \"TVCMainWindowLoadingScreenPrivate.h\"\n#import \"TVCMainWindowSplitViewPrivate.h\"\n#import \"TVCMainWindowTextViewPrivate.h\"\n#import \"TVCMainWindowTitlebarAccessoryViewPrivate.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TVCServerListAppearancePrivate.h\"\n#import \"TVCServerListCellPrivate.h\"\n#import \"TVCMemberListPrivate.h\"\n#import \"TVCTextFormatterMenuPrivate.h\"\n#import \"TVCTextViewWithIRCFormatterPrivate.h\"\n#import \"TPCApplicationInfo.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCThemeControllerPrivate.h\"\n#import \"TPCTheme.h\"\n#import \"TXGlobalModels.h\"\n#import \"TXMasterControllerPrivate.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"THOPluginDispatcherPrivate.h\"\n#import \"TLOEncryptionManagerPrivate.h\"\n#import \"TLOKeyEventHandler.h\"\n#import \"TLOInputHistoryPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOLicenseManagerPrivate.h\"\n#import \"TLONicknameCompletionStatusPrivate.h\"\n#import \"TLONotificationControllerPrivate.h\"\n#import \"TLOSpeechSynthesizerPrivate.h\"\n#import \"TDCLicenseManagerDialogPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TVCMainWindowAppearanceChangedNotification = @\"TVCMainWindowAppearanceChangedNotification\";\nNSString * const TVCMainWindowRedrawSubviewsNotification = @\"TVCMainWindowRedrawSubviewsNotification\";\n\nNSString * const TVCMainWindowWillReloadThemeNotification = @\"TVCMainWindowWillReloadThemeNotification\";\nNSString * const TVCMainWindowDidReloadThemeNotification = @\"TVCMainWindowDidReloadThemeNotification\";\n\nNSString * const TVCMainWindowSelectionChangedNotification = @\"TVCMainWindowSelectionChangedNotification\";\n\n@interface TVCMainWindow ()\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowChannelView *channelView;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowTitlebarAccessoryView *titlebarAccessoryView;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowTitlebarAccessoryViewController *titlebarAccessoryViewController;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowTitlebarAccessoryViewLockButton *titlebarAccessoryViewLockButton;\n@property (nonatomic, strong, readwrite) IBOutlet TXMenuControllerMainWindowProxy *mainMenuProxy;\n@property (nonatomic, strong, readwrite) IBOutlet TVCTextViewIRCFormattingMenu *formattingMenu;\n@property (nonatomic, unsafe_unretained, readwrite) IBOutlet TVCMainWindowTextView *inputTextField;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowSplitView *contentSplitView;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMainWindowLoadingScreenView *loadingScreen;\n@property (nonatomic, weak, readwrite) IBOutlet TVCMemberList *memberList;\n@property (nonatomic, weak, readwrite) IBOutlet TVCServerList *serverList;\n@property (nonatomic, strong) TLOInputHistory *inputHistoryManager;\n@property (nonatomic, strong) TLONicknameCompletionStatus *nicknameCompletionStatus;\n@property (nonatomic, strong, readwrite) TVCMainWindowAppearance *userInterfaceObjects;\n@property (nonatomic, readwrite, copy) NSArray *selectedItems;\n@property (nonatomic, readwrite, strong, nullable) IRCTreeItem *selectedItem;\n@property (nonatomic, copy, nullable) NSArray *previousSelectedItemsId;\n@property (nonatomic, copy, nullable) NSString *previousSelectedItemId;\n@property (nonatomic, assign) NSTimeInterval lastKeyWindowStateChange;\n@property (nonatomic, assign) BOOL lastKeyWindowRedrawFailedBecauseOfOcclusion;\n@property (nonatomic, strong) TLOKeyEventHandler *keyEventHandler;\n@property (nonatomic, copy, nullable) NSValue *cachedSwipeOriginPoint;\n@property (nonatomic, assign, readwrite) double textSizeMultiplier;\n@property (nonatomic, assign, readwrite) BOOL reloadingTheme;\n@end\n\n#define _treeDragItemType\t\tTVCServerListDragType\n\n#define _treeDragItemTypes\t\t[NSArray arrayWithObject:_treeDragItemType]\n\n@implementation TVCMainWindow\n\n#pragma mark -\n#pragma mark Awakening\n\n- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag\n{\n\tif ((self = [super initWithContentRect:contentRect styleMask:style backing:bufferingType defer:flag])) {\n\t\t[self prepareInitialState];\n\t}\n\n\treturn self;\n}\n\n- (void)prepareInitialState\n{\n\tself.inputHistoryManager = [[TLOInputHistory alloc] initWithWindow:self];\n\n\tself.keyEventHandler = [[TLOKeyEventHandler alloc] initWithTarget:self];\n\n\tself.nicknameCompletionStatus = [[TLONicknameCompletionStatus alloc] initWithWindow:self];\n\n\tself.previousSelectedItemsId = @[];\n\n\tself.selectedItems = @[];\n\n\tself.textSizeMultiplier = 1.0;\n}\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\t/* -awakeFromNib is called multiple times because of reloads */\n\tstatic BOOL _awakeFromNibCalled = NO;\n\n\tif (_awakeFromNibCalled == NO) {\n\t\t_awakeFromNibCalled = YES;\n\n\t\t[self _awakeFromNib];\n\t}\n}\n\n- (void)_awakeFromNib\n{\n\tself.delegate = (id)self;\n\n\tself.allowsConcurrentViewDrawing = NO;\n\n\tself.alphaValue = [TPCPreferences mainWindowTransparency];\n\n\t[self addAccessoryViewsToTitlebar];\n\n\t[self updateAppearance];\n\n\t[self reloadLoadingScreen];\n\n\t[self makeMainWindow];\n\n\t[self makeKeyAndOrderFront:nil];\n\n\t[self loadWindowState];\n\n\t[self updateChannelViewArrangement];\n\n\t[masterController() applicationWakeStepOne];\n\n\t[themeController() load];\n\n\t[menuController() prepareInitialState];\n\n\t[self registerKeyHandlers];\n\n\t[worldController() setupConfiguration];\n\n\t[self setupTrees];\n\n\t[TVCDockIcon drawWithoutCount];\n\n\t[self observeNotifications];\n\n\t[masterController() applicationWakeStepTwo];\n}\n\n- (void)observeNotifications\n{\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(licenseManagerActivatedLicense:)\n\t\t\t\t\t\t\t\t   name:TDCLicenseManagerActivatedLicenseNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(licenseManagerDeactivatedLicense:)\n\t\t\t\t\t\t\t\t   name:TDCLicenseManagerDeactivatedLicenseNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(licenseManagerTrialExpired:)\n\t\t\t\t\t\t\t\t   name:TDCLicenseManagerTrialExpiredNotification\n\t\t\t\t\t\t\t\t object:nil];\n#endif\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(applicationAppearanceChanged:)\n\t\t\t\t\t\t\t\t   name:TXApplicationAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(systemAppearanceChanged:)\n\t\t\t\t\t\t\t\t   name:TXSystemAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeVarietyChanged:)\n\t\t\t\t\t\t\t\t   name:TPCThemeAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeVarietyChanged:)\n\t\t\t\t\t\t\t\t   name:TPCThemeVarietyChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n}\n\n- (void)maybeToggleFullscreenAfterLaunch\n{\n\tBOOL isFullscreen = [RZUserDefaults() boolForKey:@\"Window -> Main Window Is Fullscreen'd\"];\n\n\tif (isFullscreen == NO) {\n\t\treturn;\n\t}\n\n\t[self performSelectorInCommonModes:@selector(toggleFullscreenAfterLaunch) withObject:nil afterDelay:1.0];\n}\n\n- (void)toggleFullscreenAfterLaunch\n{\n\tif (self.inFullscreenMode) {\n\t\treturn;\n\t}\n\n\t[self toggleFullScreen:nil];\n}\n\n- (void)themeVarietyChanged:(NSNotification *)notification\n{\n\t[self reloadTheme];\n}\n\n- (void)applicationAppearanceChanged:(NSNotification *)notification\n{\n\t[self updateAppearance];\n}\n\n- (void)systemAppearanceChanged:(NSNotification *)notification\n{\n\t[self notifySystemAppearanceChanged];\n}\n\n- (BOOL)isUsingDarkAppearance\n{\n\treturn self.userInterfaceObjects.isDarkAppearance;\n}\n\n- (void)updateAppearance\n{\n\tTVCMainWindowAppearance *appearance = [[TVCMainWindowAppearance alloc] initWithWindow:self];\n\n\tself.userInterfaceObjects = appearance;\n\n\t[self updateVibrancyWithAppearance:appearance];\n\n\t[self notifyApplicationAppearanceChanged];\n}\n\n- (void)updateVibrancyWithAppearance:(TVCMainWindowAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tNSAppearance *appKitAppearance = nil;\n\n\tif (appearance.appKitAppearanceTarget == TXAppKitAppearanceTargetWindow) {\n\t\tappKitAppearance = appearance.appKitAppearance;\n\t}\n\n\tself.appearance = appKitAppearance;\n}\n\n- (void)notifyApplicationAppearanceChanged\n{\n\t[super notifyApplicationAppearanceChanged];\n\n\t[RZNotificationCenter() postNotificationName:TVCMainWindowAppearanceChangedNotification object:self];\n}\n\n- (void)updateAlphaValueToReflectPreferences\n{\n\t[self updateAlphaValueToReflectPreferencesAnimated:NO];\n}\n\n- (void)updateAlphaValueToReflectPreferencesAnimated:(BOOL)animate\n{\n\tif (self.inFullscreenMode) {\n\t\treturn;\n\t}\n\n\tdouble alphaValue = [TPCPreferences mainWindowTransparency];\n\n\tif (animate) {\n\t\t[self animator].alphaValue = alphaValue;\n\t} else {\n\t\tself.alphaValue = alphaValue;\n\t}\n}\n\n- (void)loadWindowState\n{\n\t[self restoreWindowStateUsingKeyword:@\"Main Window\"];\n\n\t[self restoreSavedContentSplitViewState];\n}\n\n- (void)saveWindowState\n{\n\t[RZUserDefaults() setBool:self.isInFullscreenMode forKey:@\"Window -> Main Window Is Fullscreen'd\"];\n\n\t[self saveWindowStateUsingKeyword:@\"Main Window\"];\n\n\t[self saveContentSplitViewState];\n\n\t[self saveSelection];\n}\n\n- (void)prepareForApplicationTermination\n{\n\tLogToConsoleTerminationProgress(\"Removing main window observers\");\n\n\t[RZNotificationCenter() removeObserver:self];\n\n\tLogToConsoleTerminationProgress(\"Saving window state\");\n\n\t[self saveWindowState];\n\n\tLogToConsoleTerminationProgress(\"Giving up server list & member list delegation\");\n\n\tself.serverList.dataSource = nil;\n\tself.serverList.delegate = nil;\n\tself.serverList.keyDelegate = nil;\n\n\tself.memberList.keyDelegate = nil;\n\n\t[self.memberList assignToChannel:nil];\n\n\tself.delegate = (id)self;\n\n\tself.selectedItems = nil;\n\tself.selectedItem = nil;\n\n\tLogToConsoleTerminationProgress(\"Closing main window\");\n\n\t[self close];\n}\n\n#pragma mark -\n#pragma mark Item Update\n\n- (void)reloadMainWindowFrameOnScreenChange\n{\n\tif (masterController().applicationIsTerminating) {\n\t\treturn;\n\t}\n\n\t[TVCDockIcon resetCachedCount];\n\n\t[TVCDockIcon updateDockIcon];\n\n\t[self updateAppearance];\n}\n\n- (void)resetSelectedItemState\n{\n\tif (masterController().applicationIsTerminating) {\n\t\treturn;\n\t}\n\n\tid selectedItem = self.selectedItem;\n\n\tif (selectedItem) {\n\t\t[selectedItem resetState];\n\t}\n\n\t[TVCDockIcon updateDockIcon];\n}\n\n- (void)reloadSubviewDrawings\n{\n\t[RZNotificationCenter() postNotificationName:TVCMainWindowRedrawSubviewsNotification object:self];\n}\n\n- (void)reloadViewControllerDrawings\n{\n\tif (masterController().applicationIsTerminating) {\n\t\treturn;\n\t}\n\n\tfor (IRCTreeItem *item in self.selectedItems) {\n\t\t[item.viewController.backingView redrawViewIfNeeded];\n\t}\n}\n\n#pragma mark -\n#pragma mark NSWindow Delegate\n\n- (void)windowDidDeminiaturize:(NSNotification *)notification\n{\n//\t[self reloadViewControllerDrawings];\n}\n\n- (void)windowDidChangeScreen:(NSNotification *)notification\n{\n\t[self reloadMainWindowFrameOnScreenChange];\n}\n\n- (void)windowDidChangeOcclusionState:(NSNotification *)notification\n{\n\tif (self.occluded) {\n\t\treturn;\n\t}\n\n\tif (self.lastKeyWindowRedrawFailedBecauseOfOcclusion) {\n\t\tself.lastKeyWindowRedrawFailedBecauseOfOcclusion = NO;\n\n\t\t[self reloadSubviewDrawings];\n\t} else {\n\t\t/* We keep track of the last subview redraw so that we do\n\t\t not draw too often. Current maximum is 1.0 second. */\n\t\tNSTimeInterval timeDifference = ([NSDate timeIntervalSince1970] - self.lastKeyWindowStateChange);\n\n\t\tif (timeDifference > 1.0) {\n\t\t\t[self reloadSubviewDrawings];\n\t\t}\n\t}\n}\n\n- (void)windowDidBecomeKey:(NSNotification *)notification\n{\n\tself.lastKeyWindowStateChange = [NSDate timeIntervalSince1970];\n\n\t[self resetSelectedItemState];\n\n\tif (self.occluded) {\n\t\tself.lastKeyWindowRedrawFailedBecauseOfOcclusion = YES;\n\n\t\treturn;\n\t}\n\n\t[self reloadSubviewDrawings];\n\n//\t[self reloadViewControllerDrawings];\n}\n\n- (void)windowDidResignKey:(NSNotification *)notification\n{\n\tself.lastKeyWindowStateChange = [NSDate timeIntervalSince1970];\n\n\t[self reloadSubviewDrawings];\n}\n\n- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu\n{\n\treturn NO;\n}\n\n- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard\n{\n\treturn NO;\n}\n\n- (void)windowDidResize:(NSNotification *)notification\n{\n\t[self.inputTextField recalculateTextViewSize];\n}\n\n- (BOOL)windowShouldZoom:(NSWindow *)awindow toFrame:(NSRect)newFrame\n{\n\treturn (self.inFullscreenMode == NO);\n}\n\n- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize\n{\n\treturn proposedSize;\n}\n\n- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions\n{\n\treturn proposedOptions;\n}\n\n- (void)windowDidExitFullScreen:(NSNotification *)notification\n{\n\t[self updateAlphaValueToReflectPreferencesAnimated:YES];\n}\n\n- (void)windowWillEnterFullScreen:(NSNotification *)notification\n{\n\t[self animator].alphaValue = 1.0;\n}\n\n- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tNSMenu *editorMenu = self.inputTextField.menu;\n\n\t\tNSMenuItem *formatterMenu = self.formattingMenu.formatterMenu;\n\n\t\tNSInteger formatterMenuIndex = [editorMenu indexOfItemWithTitle:formatterMenu.title];\n\n\t\tif (formatterMenuIndex < 0) {\n\t\t\t[editorMenu addItem:[NSMenuItem separatorItem]];\n\n\t\t\t[editorMenu addItem:formatterMenu];\n\t\t}\n\n\t\tself.inputTextField.menu = editorMenu;\n\t});\n\n\treturn self.inputTextField;\n}\n\n#pragma mark -\n#pragma mark Keyboard Shortcuts\n\n- (void)setKeyHandlerTarget:(id)target\n{\n\t[self.keyEventHandler setKeyHandlerTarget:target];\n}\n\n- (void)registerSelector:(SEL)selector key:(NSUInteger)keyCode modifiers:(NSUInteger)modifiers\n{\n\t[self.keyEventHandler registerSelector:selector key:keyCode modifiers:modifiers];\n}\n\n- (void)registerSelector:(SEL)selector character:(UniChar)character modifiers:(NSUInteger)modifiers\n{\n\t[self.keyEventHandler registerSelector:selector character:character modifiers:modifiers];\n}\n\n- (void)registerInputSelector:(SEL)selector key:(NSUInteger)keyCode modifiers:(NSUInteger)modifiers\n{\n\t[self.inputTextField registerSelector:selector key:keyCode modifiers:modifiers];\n}\n\n- (void)registerInputSelector:(SEL)selector character:(UniChar)character modifiers:(NSUInteger)modifiers\n{\n\t[self.inputTextField registerSelector:selector character:character modifiers:modifiers];\n}\n\n- (BOOL)performedCustomKeyboardEvent:(NSEvent *)e\n{\n\tif ([self.keyEventHandler processKeyEvent:e]) {\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)redirectKeyDown:(NSEvent *)e\n{\n\t[self.inputTextField focus];\n\n\tif (e.keyCode == TXKeyEnterCode ||\n\t\te.keyCode == TXKeyReturnCode)\n\t{\n\t\treturn;\n\t}\n\n\t[self.inputTextField keyDown:e];\n}\n\n- (void)memberListKeyDown:(NSEvent *)e\n{\n\t[self redirectKeyDown:e];\n}\n\n- (void)serverListKeyDown:(NSEvent *)e\n{\n\t[self redirectKeyDown:e];\n}\n\n- (void)registerKeyHandlers\n{\n\t[self.inputTextField setKeyHandlerTarget:self];\n\n\t/* Window keyboard shortcuts */\n\t[self registerSelector:@selector(exitFullscreenMode:) key:TXKeyEscapeCode modifiers:0];\n\n\t[self registerSelector:@selector(tab:) key:TXKeyTabCode modifiers:0];\n\t[self registerSelector:@selector(shiftTab:)\tkey:TXKeyTabCode modifiers:NSEventModifierFlagShift];\n\n\t[self registerSelector:@selector(selectPreviousSelection:) key:TXKeyTabCode modifiers:NSEventModifierFlagOption];\n\n\t[self registerSelector:@selector(textFormattingBold:) character:'b' modifiers:NSEventModifierFlagCommand];\n\t[self registerSelector:@selector(textFormattingUnderline:) character:'u' modifiers:(NSEventModifierFlagControl | NSEventModifierFlagShift)];\n\t[self registerSelector:@selector(textFormattingItalic:)\tcharacter:'i' modifiers:(NSEventModifierFlagControl | NSEventModifierFlagShift)];\n\t[self registerSelector:@selector(textFormattingForegroundColor:) character:'c' modifiers:(NSEventModifierFlagControl | NSEventModifierFlagShift)];\n\t[self registerSelector:@selector(textFormattingBackgroundColor:) character:'h' modifiers:(NSEventModifierFlagControl | NSEventModifierFlagShift)];\n\n\t[self registerSelector:@selector(speakPendingNotifications:) character:'.' modifiers:NSEventModifierFlagCommand];\n\n\t[self registerSelector:@selector(inputHistoryUp:) character:'p' modifiers:NSEventModifierFlagControl];\n\t[self registerSelector:@selector(inputHistoryDown:)\tcharacter:'n' modifiers:NSEventModifierFlagControl];\n\n\t/* Text field keyboard shortcuts */\n\t[self registerInputSelector:@selector(sendControlEnterMessageMaybe:) key:TXKeyEnterCode modifiers:NSEventModifierFlagControl];\n\n\t[self registerInputSelector:@selector(sendMessageAsAction:) key:TXKeyReturnCode modifiers:NSEventModifierFlagCommand];\n\t[self registerInputSelector:@selector(sendMessageAsAction:) key:TXKeyEnterCode modifiers:NSEventModifierFlagCommand];\n\n\t[self registerInputSelector:@selector(focusWebview:) character:'l' modifiers:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];\n\n\t[self registerInputSelector:@selector(inputHistoryUpWithScrollCheck:) key:TXKeyUpArrowCode modifiers:0];\n\t[self registerInputSelector:@selector(inputHistoryUpWithScrollCheck:) key:TXKeyUpArrowCode modifiers:NSEventModifierFlagOption];\n\n\t[self registerInputSelector:@selector(inputHistoryDownWithScrollCheck:) key:TXKeyDownArrowCode modifiers:0];\n\t[self registerInputSelector:@selector(inputHistoryDownWithScrollCheck:) key:TXKeyDownArrowCode modifiers:NSEventModifierFlagOption];\n}\n\n#pragma mark -\n#pragma mark Navigation\n\n- (void)navigateServerListEntries:(nullable NSArray<IRCTreeItem *> *)scannedRows\n\t\t\t\t\t   entryCount:(NSInteger)entryCount\n\t\t\t\t\tstartingPoint:(NSInteger)startingPoint\n\t\t\t\t\t isMovingDown:(BOOL)isMovingDown\n\t\t\t\t   navigationType:(TVCServerListNavigationMovementType)navigationType\n\t\t\t\t\tselectionType:(TVCServerListNavigationSelectionType)selectionType\n{\n\tNSParameterAssert(entryCount > 0);\n\tNSParameterAssert(startingPoint >= 0);\n\n\tNSInteger currentPosition = startingPoint;\n\n\twhile (1) {\n\t\t/* Move to next selection */\n\t\tif (isMovingDown) {\n\t\t\tcurrentPosition += 1;\n\t\t} else {\n\t\t\tcurrentPosition -= 1;\n\t\t}\n\n\t\t/* Make sure selection is within our bounds */\n\t\tif (currentPosition >= entryCount || currentPosition < 0) {\n\t\t\tif (isMovingDown == NO && currentPosition < 0) {\n\t\t\t\tcurrentPosition = (entryCount - 1);\n\t\t\t} else {\n\t\t\t\tcurrentPosition = 0;\n\t\t\t}\n\t\t}\n\n\t\tif (currentPosition == startingPoint) {\n\t\t\tbreak;\n\t\t}\n\n\t\t/* Get next selection depending on data source */\n\t\tid item;\n\n\t\tif (scannedRows) {\n\t\t\titem = scannedRows[currentPosition];\n\t\t} else {\n\t\t\titem = [self.serverList itemAtRow:currentPosition];\n\t\t}\n\n\t\t/* Skip entries depending on navigation type */\n\t\tif (selectionType == TVCServerListNavigationSelectionTypeChannel)\n\t\t{\n\t\t\tif ([item isChannel] == NO && [item isPrivateMessage] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\telse if (selectionType == TVCServerListNavigationSelectionTypeServer)\n\t\t{\n\t\t\tif ([item isClient] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t/* Select current item if it is matched by our condition */\n\t\tif (navigationType == TVCServerListNavigationMovementTypeAll)\n\t\t{\n\t\t\t[self select:item];\n\n\t\t\tbreak;\n\t\t}\n\t\telse if (navigationType == TVCServerListNavigationMovementTypeActive)\n\t\t{\n\t\t\tif ([item isActive]) {\n\t\t\t\t[self select:item];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse if (navigationType == TVCServerListNavigationMovementTypeUnread)\n\t\t{\n\t\t\tif ([item isUnread]) {\n\t\t\t\t[self select:item];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)navigateChannelEntries:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType\n{\n\tif ([TPCPreferences channelNavigationIsServerSpecific]) {\n\t\t[self navigateChannelEntriesWithinServerScope:isMovingDown withNavigationType:navigationType];\n\t} else {\n\t\t[self navigateChannelEntriesOutsideServerScope:isMovingDown withNavigationType:navigationType];\n\t}\n}\n\n- (void)navigateChannelEntriesOutsideServerScope:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType\n{\n\tNSInteger entryCount = self.serverList.numberOfRows;\n\n\tNSInteger startingPoint = [self.serverList rowForItem:self.selectedItem];\n\n\t[self navigateServerListEntries:nil\n\t\t\t\t\t\t entryCount:entryCount\n\t\t\t\t\t  startingPoint:startingPoint\n\t\t\t\t\t   isMovingDown:isMovingDown\n\t\t\t\t\t navigationType:navigationType\n\t\t\t\t\t  selectionType:TVCServerListNavigationSelectionTypeChannel];\n}\n\n- (void)navigateChannelEntriesWithinServerScope:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType\n{\n\tNSArray *scannedRows = [self.serverList itemsFromParentGroup:self.selectedItem];\n\n\t/* We add selected server so navigation falls within its scope if its the selected item */\n\tscannedRows = [scannedRows arrayByAddingObject:self.selectedClient];\n\n\t[self navigateServerListEntries:scannedRows\n\t\t\t\t\t\t entryCount:scannedRows.count\n\t\t\t\t\t  startingPoint:[scannedRows indexOfObject:self.selectedItem]\n\t\t\t\t\t   isMovingDown:isMovingDown\n\t\t\t\t\t navigationType:navigationType\n\t\t\t\t\t  selectionType:TVCServerListNavigationSelectionTypeChannel];\n}\n\n- (void)navigateServerEntries:(BOOL)isMovingDown withNavigationType:(TVCServerListNavigationMovementType)navigationType\n{\n\tNSArray *scannedRows = self.serverList.groupItems;\n\n\t[self navigateServerListEntries:scannedRows\n\t\t\t\t\t\t entryCount:scannedRows.count\n\t\t\t\t\t  startingPoint:[scannedRows indexOfObject:self.selectedClient]\n\t\t\t\t\t   isMovingDown:isMovingDown\n\t\t\t\t\t navigationType:navigationType\n\t\t\t\t\t  selectionType:TVCServerListNavigationSelectionTypeServer];\n}\n\n- (void)navigateToNextEntry:(BOOL)isMovingDown\n{\n\tNSInteger entryCount = self.serverList.numberOfRows;\n\n\tNSInteger startingPoint = [self.serverList rowForItem:self.selectedItem];\n\n\t[self navigateServerListEntries:nil\n\t\t\t\t\t\t entryCount:entryCount\n\t\t\t\t\t  startingPoint:startingPoint\n\t\t\t\t\t   isMovingDown:isMovingDown\n\t\t\t\t\t navigationType:TVCServerListNavigationMovementTypeAll\n\t\t\t\t\t  selectionType:TVCServerListNavigationSelectionTypeAny];\n}\n\n- (void)selectPreviousChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:NO withNavigationType:TVCServerListNavigationMovementTypeAll];\n}\n\n- (void)selectNextChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:YES withNavigationType:TVCServerListNavigationMovementTypeAll];\n}\n\n- (void)selectPreviousUnreadChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:NO withNavigationType:TVCServerListNavigationMovementTypeUnread];\n}\n\n- (void)selectNextUnreadChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:YES withNavigationType:TVCServerListNavigationMovementTypeUnread];\n}\n\n- (void)selectPreviousActiveChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:NO withNavigationType:TVCServerListNavigationMovementTypeActive];\n}\n\n- (void)selectNextActiveChannel:(NSEvent *)e\n{\n\t[self navigateChannelEntries:YES withNavigationType:TVCServerListNavigationMovementTypeActive];\n}\n\n- (void)selectPreviousServer:(NSEvent *)e\n{\n\t[self navigateServerEntries:NO withNavigationType:TVCServerListNavigationMovementTypeAll];\n}\n\n- (void)selectNextServer:(NSEvent *)e\n{\n\t[self navigateServerEntries:YES withNavigationType:TVCServerListNavigationMovementTypeAll];\n}\n\n- (void)selectPreviousActiveServer:(NSEvent *)e\n{\n\t[self navigateServerEntries:NO withNavigationType:TVCServerListNavigationMovementTypeActive];\n}\n\n- (void)selectNextActiveServer:(NSEvent *)e\n{\n\t[self navigateServerEntries:YES withNavigationType:TVCServerListNavigationMovementTypeActive];\n}\n\n- (void)selectPreviousSelection:(NSEvent *)e\n{\n\t[self selectPreviousItem];\n}\n\n- (void)selectNextWindow:(NSEvent *)e\n{\n\t[self navigateToNextEntry:YES];\n}\n\n- (void)selectPreviousWindow:(NSEvent *)e\n{\n\t[self navigateToNextEntry:NO];\n}\n\n#pragma mark -\n#pragma mark View Controls\n\n- (void)changeTextSize:(BOOL)bigger\n{\n#define MinimumZoomMultiplier\t   0.5\n#define MaximumZoomMultiplier\t   3.0\n\n#define ZoomMultiplierRatio\t\t\t1.2\n\n\tdouble textSizeMultiplier = self.textSizeMultiplier;\n\n\tif (bigger) {\n\t\ttextSizeMultiplier *= ZoomMultiplierRatio;\n\n\t\tif (textSizeMultiplier > MaximumZoomMultiplier) {\n\t\t\treturn;\n\t\t}\n\n\t\tself.textSizeMultiplier = textSizeMultiplier;\n\t} else {\n\t\ttextSizeMultiplier /= ZoomMultiplierRatio;\n\n\t\tif (textSizeMultiplier < MinimumZoomMultiplier) {\n\t\t\treturn;\n\t\t}\n\n\t\tself.textSizeMultiplier = textSizeMultiplier;\n\t}\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\t[u.viewController changeTextSize:bigger];\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t[c.viewController changeTextSize:bigger];\n\t\t}\n\t}\n\n#undef MinimumZoomMultiplier\n#undef MaximumZoomMultiplier\n\n#undef ZoomMultiplierRatio\n}\n\n- (void)markAllAsRead\n{\n\t[self markAllAsReadInGroup:nil];\n}\n\n- (void)markAllAsReadInGroup:(nullable IRCTreeItem *)item\n{\n\tBOOL markScrollback = [TPCPreferences autoAddScrollbackMark];\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tif (markScrollback) {\n\t\t\t[u.viewController mark];\n\t\t}\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tif (markScrollback) {\n\t\t\t\t[c.viewController mark];\n\t\t\t}\n\n\t\t\t[c resetState];\n\t\t}\n\t}\n\n\t[TVCDockIcon updateDockIcon];\n\n\tif (item) {\n\t\t[self reloadTreeGroup:item];\n\t} else {\n\t\t[self reloadTree];\n\t}\n}\n\n- (void)reloadTheme\n{\n\tif (self.reloadingTheme == NO) {\n\t\tself.reloadingTheme = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() postNotificationName:TVCMainWindowWillReloadThemeNotification object:self];\n\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\tif (masterController().applicationIsTerminating) {\n\t\t\treturn;\n\t\t}\n\n\t\t[TVCLogView emptyCaches];\n\n\t\t[self _reloadTheme_performReload];\n\t});\n}\n\n- (void)_reloadTheme_performReload\n{\n\tfor (IRCClient *u in worldController().clientList) {\n\t\t[u.viewController reloadTheme];\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t[c.viewController reloadTheme];\n\t\t}\n\t}\n\n\tself.reloadingTheme = NO;\n\n\t[RZNotificationCenter() postNotificationName:TVCMainWindowDidReloadThemeNotification object:self];\n}\n\n- (void)clearContentsOfClient:(IRCClient *)client\n{\n\tNSParameterAssert(client != nil);\n\n\t[client resetState];\n\n\t[client.viewController clear];\n\n\t[self reloadTreeItem:client];\n}\n\n- (void)clearContentsOfChannel:(IRCChannel *)channel\n{\n\tNSParameterAssert(channel != nil);\n\n\t[channel resetState];\n\n\t[channel.viewController clear];\n\n\t[self reloadTreeItem:channel];\n}\n\n- (void)clearAllViews\n{\n\tfor (IRCClient *u in worldController().clientList) {\n\t\t[self clearContentsOfClient:u];\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t[self clearContentsOfChannel:c];\n\t\t}\n\t}\n\n\t[self markAllAsRead];\n}\n\n#pragma mark -\n#pragma mark Actions\n\n- (void)completeNickname:(BOOL)movingForward\n{\n\t[self.nicknameCompletionStatus completeNickname:movingForward];\n}\n\n- (void)tab:(NSEvent *)e\n{\n\tTXTabKeyAction tabKeyAction = [TPCPreferences tabKeyAction];\n\n\tif (tabKeyAction == TXTabKeyActionNicknameComplete) {\n\t\t[self completeNickname:YES];\n\t} else if (tabKeyAction == TXTabKeyActionUnreadChannel) {\n\t\t[self navigateChannelEntries:YES withNavigationType:TVCServerListNavigationMovementTypeUnread];\n\t}\n}\n\n- (void)shiftTab:(NSEvent *)e\n{\n\tTXTabKeyAction tabKeyAction = [TPCPreferences tabKeyAction];\n\n\tif (tabKeyAction == TXTabKeyActionNicknameComplete) {\n\t\t[self completeNickname:NO];\n\t} else if (tabKeyAction == TXTabKeyActionUnreadChannel) {\n\t\t[self navigateChannelEntries:NO withNavigationType:TVCServerListNavigationMovementTypeUnread];\n\t}\n}\n\n- (void)sendControlEnterMessageMaybe:(NSEvent *)e\n{\n\tif ([TPCPreferences controlEnterSendsMessage]) {\n\t\t[self textEntered];\n\n\t\treturn;\n\t}\n\n\t[self.inputTextField keyDownToSuper:e];\n}\n\n- (void)sendMessageAsAction:(NSEvent *)e\n{\n\tif ([TPCPreferences commandReturnSendsMessageAsAction]) {\n\t\t[self inputTextAsCommand:IRCRemoteCommandPrivmsgAction];\n\n\t\treturn;\n\t}\n\n\t[self textEntered];\n}\n\n- (void)moveInputHistory:(BOOL)movingUp checkScroller:(BOOL)checkScroller event:(NSEvent *)event\n{\n\tif (checkScroller) {\n\t\tTVCTextViewCaretLocation caretLocation = self.inputTextField.caretLocation;\n\n\t\tif (caretLocation != TVCTextViewCaretLocationOnlyLine) {\n\t\t\tBOOL atTop = (caretLocation == TVCTextViewCaretLocationFirstLine);\n\t\t\tBOOL atBottom = (caretLocation == TVCTextViewCaretLocationLastLine);\n\n\t\t\tif ((atTop\t\t\t&& event.keyCode == TXKeyDownArrowCode) ||\n\t\t\t\t(atBottom\t\t&& event.keyCode == TXKeyUpArrowCode) ||\n\t\t\t\t(atTop == NO\t&& atBottom == NO))\n\t\t\t{\n\t\t\t\t[self.inputTextField keyDownToSuper:event];\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tNSAttributedString *stringValue = self.inputTextField.attributedStringValue;\n\n\tif (movingUp) {\n\t\tstringValue = [self.inputHistoryManager up:stringValue];\n\t} else {\n\t\tstringValue = [self.inputHistoryManager down:stringValue];\n\t}\n\n\tif (stringValue == nil) {\n\t\treturn;\n\t}\n\n\tself.inputTextField.attributedStringValue = stringValue;\n\n\t[self.inputTextField focus];\n\n\tif (movingUp == NO) {\n\t\tself.inputTextField.selectedRange = NSMakeRange(0, 0);\n\t}\n}\n\n- (void)inputHistoryUp:(NSEvent *)e\n{\n\t[self moveInputHistory:YES checkScroller:NO event:e];\n}\n\n- (void)inputHistoryDown:(NSEvent *)e\n{\n\t[self moveInputHistory:NO checkScroller:NO event:e];\n}\n\n- (void)inputHistoryUpWithScrollCheck:(NSEvent *)e\n{\n\t[self moveInputHistory:YES checkScroller:YES event:e];\n}\n\n- (void)inputHistoryDownWithScrollCheck:(NSEvent *)e\n{\n\t[self moveInputHistory:NO checkScroller:YES event:e];\n}\n\n- (void)textFormattingBold:(NSEvent *)e\n{\n\tif (self.formattingMenu.textIsBold) {\n\t\t[self.formattingMenu removeBoldCharFromTextBox:nil];\n\t} else {\n\t\t[self.formattingMenu insertBoldCharIntoTextBox:nil];\n\t}\n}\n\n- (void)textFormattingItalic:(NSEvent *)e\n{\n\tif (self.formattingMenu.textIsItalicized) {\n\t\t[self.formattingMenu removeItalicCharFromTextBox:nil];\n\t} else {\n\t\t[self.formattingMenu insertItalicCharIntoTextBox:nil];\n\t}\n}\n\n- (void)textFormattingStrikethrough:(NSEvent *)e\n{\n\tif (self.formattingMenu.textIsStruckthrough) {\n\t\t[self.formattingMenu removeStrikethroughCharFromTextBox:nil];\n\t} else {\n\t\t[self.formattingMenu insertStrikethroughCharIntoTextBox:nil];\n\t}\n}\n\n- (void)textFormattingUnderline:(NSEvent *)e\n{\n\tif (self.formattingMenu.textIsUnderlined) {\n\t\t[self.formattingMenu removeUnderlineCharFromTextBox:nil];\n\t} else {\n\t\t[self.formattingMenu insertUnderlineCharIntoTextBox:nil];\n\t}\n}\n\n- (void)textFormattingForegroundColor:(NSEvent *)e\n{\n\tif (self.formattingMenu.textHasSpoiler) {\n\t\treturn;\n\t}\n\n\tif (self.formattingMenu.textHasForegroundColor) {\n\t\t[self.formattingMenu removeForegroundColorCharFromTextBox:nil];\n\n\t\treturn;\n\t}\n\n\tNSRect textFieldFrame = self.inputTextField.frame;\n\n\ttextFieldFrame.origin.y -= 200;\n\ttextFieldFrame.origin.x += 100;\n\n\t[self.formattingMenu.foregroundColorMenu popUpMenuPositioningItem:nil atLocation:textFieldFrame.origin inView:self.inputTextField];\n}\n\n- (void)textFormattingBackgroundColor:(NSEvent *)e\n{\n\tif (self.formattingMenu.textHasSpoiler) {\n\t\treturn;\n\t}\n\n\tif (self.formattingMenu.textHasForegroundColor == NO) {\n\t\treturn;\n\t}\n\n\tif (self.formattingMenu.textHasBackgroundColor) {\n\t\t[self.formattingMenu removeForegroundColorCharFromTextBox:nil];\n\n\t\treturn;\n\t}\n\n\tNSRect textFieldFrame = self.inputTextField.frame;\n\n\ttextFieldFrame.origin.y -= 200;\n\ttextFieldFrame.origin.x += 100;\n\n\t[self.formattingMenu.backgroundColorMenu popUpMenuPositioningItem:nil atLocation:textFieldFrame.origin inView:self.inputTextField];\n}\n\n- (void)exitFullscreenMode:(NSEvent *)e // escape key\n{\n\tif (self.inFullscreenMode) {\n\t\t[self toggleFullScreen:nil];\n\n\t\treturn;\n\t}\n\n\t[self.inputTextField keyDown:e];\n}\n\n- (void)speakPendingNotifications:(NSEvent *)e\n{\n\t[[TXSharedApplication sharedSpeechSynthesizer] stopSpeakingAndMoveForward];\n}\n\n- (void)focusWebview:(NSEvent *)e\n{\n\tif (self.attachedSheet != nil) {\n\t\treturn;\n\t}\n\n\tTVCLogController *viewController = self.selectedViewController;\n\n\tif (viewController == nil) {\n\t\treturn;\n\t}\n\n\tNSView *webView = viewController.backingView.webView;\n\n\t[self makeFirstResponder:webView];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)textEntered\n{\n\t[self inputTextAsCommand:IRCRemoteCommandPrivmsg];\n}\n\n- (void)inputTextAsCommand:(IRCRemoteCommand)command\n{\n\t[self.nicknameCompletionStatus clear];\n\n\tNSAttributedString *stringValue = self.inputTextField.attributedStringValue;\n\n\tif (stringValue.length == 0) {\n\t\treturn;\n\t}\n\n\tself.inputTextField.attributedStringValue = [NSAttributedString attributedString];\n\n\t[self.inputHistoryManager add:stringValue];\n\n\t[self inputText:stringValue asCommand:command];\n}\n\n- (void)inputText:(id)string asCommand:(IRCRemoteCommand)command\n{\n\tNSParameterAssert(string != nil);\n\n\tif (self.selectedItem == nil) {\n\t\treturn;\n\t}\n\n\tNSString *stringValue = [THOPluginDispatcher interceptUserInput:string command:command];\n\t\n\tif (stringValue == nil) {\n\t\treturn;\n\t}\n\n\t[self.selectedClient inputText:stringValue asCommand:command];\n}\n\n#pragma mark -\n#pragma mark Swipe Events\n\n/* Three Finger Swipe Event\n\tThis event will only work if \n\t\tSystem Settings -> Trackpad -> More Gestures -> Swipe between full-screen apps\n\tis not set to \"Swipe left or right with three fingers\"\n */\n- (void)swipeWithEvent:(NSEvent *)event\n{\n\tCGFloat x = event.deltaX;\n\n\tBOOL invertedScrollingDirection = [RZUserDefaults() boolForKey:@\"com.apple.swipescrolldirection\"];\n\n\tif (invertedScrollingDirection) {\n\t\tx = (x * (-1));\n\t}\n\n\tif (x > 0) {\n\t\t[self selectNextWindow:nil];\n\t} else if (x < 0) {\n\t\t[self selectPreviousWindow:nil];\n\t}\n}\n\n- (void)beginGestureWithEvent:(NSEvent *)event\n{\n\tCGFloat swipeMinimumLength = [TPCPreferences swipeMinimumLength];\n\n\tif (swipeMinimumLength < 1.0) {\n\t\treturn;\n\t}\n\n\tNSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:nil];\n\n\tif (touches.count != 2) {\n\t\treturn;\n\t}\n\n\tNSArray *touchArray = touches.allObjects;\n\n\tself.cachedSwipeOriginPoint = [self touchesToPoint:touchArray[0] fingerB:touchArray[1]];\n}\n\n- (NSValue *)touchesToPoint:(NSTouch *)fingerA fingerB:(NSTouch *)fingerB\n{\n\tNSParameterAssert(fingerA != nil);\n\tNSParameterAssert(fingerB != nil);\n\n\tNSSize deviceSize = fingerA.deviceSize;\n\n\tCGFloat x = ((fingerA.normalizedPosition.x + fingerB.normalizedPosition.x) / 2.0 * deviceSize.width);\n\tCGFloat y = ((fingerA.normalizedPosition.y + fingerB.normalizedPosition.y) / 2.0 * deviceSize.height);\n\n\treturn [NSValue valueWithPoint:NSMakePoint(x, y)];\n}\n\n- (void)endGestureWithEvent:(NSEvent *)event\n{\n\tCGFloat swipeMinimumLength = [TPCPreferences swipeMinimumLength];\n\n\tif (swipeMinimumLength < 1.0) {\n\t\treturn;\n\t}\n\n\tNSSet *touches = [event touchesMatchingPhase:NSTouchPhaseAny inView:nil];\n\n\tif (self.cachedSwipeOriginPoint == nil || touches.count != 2) {\n\t\tself.cachedSwipeOriginPoint = nil;\n\n\t\treturn;\n\t}\n\n\tNSArray *touchArray = touches.allObjects;\n\n\tNSPoint origin = self.cachedSwipeOriginPoint.pointValue;\n\n\tNSPoint destination = [self touchesToPoint:touchArray[0] fingerB:touchArray[1]].pointValue;\n\n\tself.cachedSwipeOriginPoint = nil;\n\n\tNSPoint delta = NSMakePoint((origin.x - destination.x),\n\t\t\t\t\t\t\t\t(origin.y - destination.y));\n\n\tif (fabs(delta.y) > fabs(delta.x)) {\n\t\treturn;\n\t}\n\n\tif (fabs(delta.x) < swipeMinimumLength) {\n\t\treturn;\n\t}\n\n\tCGFloat x = delta.x;\n\n\tBOOL invertedScrollingDirection = [RZUserDefaults() boolForKey:@\"com.apple.swipescrolldirection\"];\n\n\tif (invertedScrollingDirection) {\n\t\tx = (x * (-1));\n\t}\n\n\tif (x > 0) {\n\t\t[self selectPreviousWindow:nil];\n\t} else {\n\t\t[self selectNextWindow:nil];\n\t}\n}\n\n#pragma mark -\n#pragma mark Misc\n\n- (TVCMainWindowMouseLocation)locationOfMouseInWindow\n{\n\tNSPoint mouseLocation = [NSEvent mouseLocation];\n\n\treturn [self locationOfMouse:mouseLocation];\n}\n\n- (TVCMainWindowMouseLocation)locationOfMouse:(NSPoint)mouseLocation\n{\n\tTVCMainWindowMouseLocation mouseLocationEnum = 0;\n\n\tNSRect windowFrame = self.frame;\n\n\tif (NSPointInRect(mouseLocation, windowFrame) == NO) {\n\t\treturn mouseLocationEnum;\n\t}\n\n\tmouseLocationEnum |= TVCMainWindowMouseLocationInsideWindow;\n\n\tNSRect titlebarFrame = self.titlebarFrame;\n\n\tif (NSPointInRect(mouseLocation, titlebarFrame) == NO) {\n\t\treturn mouseLocationEnum;\n\t}\n\n\tmouseLocationEnum |= TVCMainWindowMouseLocationInsideWindowTitle;\n\n#define ConvertRectToScreen(rect)\t\\\n\tNSMakeRect( (titlebarFrame.origin.x + rect.origin.x),\t\\\n\t\t\t\t(titlebarFrame.origin.y + rect.origin.y),\t\\\n\t\t\t\trect.size.width,\t\\\n\t\t\t\trect.size.height)\t\\\n\n#define PointInRect(view)\t\\\n\tNSPointInRect(mouseLocation, ConvertRectToScreen(view.frame))\n\n\tif (PointInRect([self standardWindowButton:NSWindowCloseButton]) ||\n\t\tPointInRect([self standardWindowButton:NSWindowMiniaturizeButton]) ||\n\t\tPointInRect([self standardWindowButton:NSWindowZoomButton]))\n\t{\n\t\tmouseLocationEnum |= TVCMainWindowMouseLocationOnTopOfWindowTitleControl;\n\n\t\treturn mouseLocationEnum;\n\t}\n\n\tfor (NSTitlebarAccessoryViewController *viewController in self.titlebarAccessoryViewControllers) {\n\t\t/* NSTitlebarAccessoryViewController will have an origin of 0,0 which means we have\n\t\t to check the frame of it's superview, NSTitlebarAccessoryViewClipView */\n\t\tif (PointInRect(viewController.view.superview) == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tmouseLocationEnum |= TVCMainWindowMouseLocationOnTopOfWindowTitleControl;\n\n\t\treturn mouseLocationEnum;\n\t}\n\n\treturn mouseLocationEnum;\n\n#undef ConvertRectToScreen\n\n#undef PointInRect\n}\n\n- (void)preferencesChanged\n{\n\tif ([TPCPreferences displayDockBadge] == NO) {\n\t\t[TVCDockIcon drawWithoutCount];\n\t} else {\n\t\t[TVCDockIcon resetCachedCount];\n\n\t\t[TVCDockIcon updateDockIcon];\n\t}\n}\n\n- (void)endEditingFor:(nullable id)object\n{\n\t/* WebHTMLView results in this method being called.\n\t *\n\t * The documentation states \"The endEditingFor: method should be used only as a\n\t * last resort if the field editor refuses to resign first responder status.\"\n\t *\n\t * The documentation then goes to say how you should try setting makeFirstResponder first.\n\t */\n\n\tif ([self makeFirstResponder:self] == NO) {\n\t\t[super endEditingFor:object];\n\t}\n}\n\n- (BOOL)canBecomeKeyWindow\n{\n\treturn YES;\n}\n\n- (BOOL)canBecomeMainWindow\n{\n\treturn YES;\n}\n\n- (BOOL)isDisabled\n{\n\treturn NO;\n}\n\n- (void)makeKeyAndOrderFront:(nullable id)sender\n{\n\tif (self.disabled) {\n\t\treturn;\n\t}\n\n\t[super makeKeyAndOrderFront:nil];\n}\n\n- (void)orderFront:(nullable id)sender\n{\n\tif (self.disabled) {\n\t\treturn;\n\t}\n\n\t[super orderFront:nil];\n}\n\n- (NSRect)defaultWindowFrame\n{\n\tNSRect windowFrame = self.frame;\n\n\twindowFrame.size = self.userInterfaceObjects.defaultWindowSize;\n\n\treturn windowFrame;\n}\n\n#pragma mark -\n#pragma mark Channel View Box\n\n- (BOOL)multipleItemsSelected\n{\n\treturn (self.selectedItems.count > 1);\n}\n\n- (void)channelViewSelectionChangeTo:(IRCTreeItem *)selectedItem\n{\n\t[self selectItemInSelectedItems:selectedItem refreshChannelView:NO];\n}\n\n- (void)updateChannelViewArrangement\n{\n\t[self.channelView updateArrangement];\n}\n\n- (void)updateChannelViewBoxContentViewSelection\n{\n\t[self.channelView populateSubviews];\n}\n\n- (BOOL)isItemVisible:(IRCTreeItem *)item\n{\n\tif (item == nil) {\n\t\treturn NO;\n\t}\n\n\treturn ([self isItemSelected:item] || [self isItemInSelectedGroup:item]);\n}\n\n- (BOOL)isItemSelected:(IRCTreeItem *)item\n{\n\tif (item == nil) {\n\t\treturn NO;\n\t}\n\n\treturn (self.selectedItem == item);\n}\n\n- (BOOL)isItemInSelectedGroup:(IRCTreeItem *)item\n{\n\tif (item == nil) {\n\t\treturn NO;\n\t}\n\n\treturn ([self.selectedItems containsObject:item]);\n}\n\n- (void)selectionDidChangeToRows:(NSIndexSet *)selectedRows\n{\n\t[self selectionDidChangeToRows:selectedRows selectedItem:nil];\n}\n\n- (void)selectionDidChangeToRows:(NSIndexSet *)selectedRows selectedItem:(nullable IRCTreeItem *)selectedItem\n{\n\tNSParameterAssert(selectedRows != nil);\n\n\t/* Create list of selected items and notify those newly selected items\n\t that they are now visible + part of a stacked view */\n\tNSArray *selectedItems = self.serverList.selectedObjects;\n\n\t/* Update selected item even if group hasn't changed */\n\tif ([selectedItems isEqualToArray:self.selectedItems]) { /* Update selected item even if group hasn't changed */\n\t\tif (selectedItem) {\n\t\t\t[self selectItemInSelectedItems:selectedItem];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tNSUInteger selectedItemsCount = selectedItems.count;\n\n\t/* Store previous selection */\n\t[self storePreviousSelection];\n\n\t/* Update properties */\n\tNSArray *selectedItemsPrevious = nil;\n\n\tif (self.selectedItems) {\n\t\tselectedItemsPrevious = [self.selectedItems copy];\n\t}\n\n\tif (selectedItemsCount > 0) {\n\t\tself.selectedItems = selectedItems;\n\n\t\tif (selectedItem == nil) {\n\t\t\tselectedItem = self.selectedItem;\n\t\t}\n\n\t\tif (selectedItem && [self isItemInSelectedGroup:selectedItem]) {\n\t\t\tself.selectedItem = selectedItem;\n\t\t} else {\n\t\t\tself.selectedItem = selectedItems[(selectedItemsCount - 1)];\n\t\t}\n\t} else {\n\t\tself.selectedItem = nil;\n\t\tself.selectedItems = @[];\n\t}\n\n\t/* Update split view */\n\t[self updateChannelViewBoxContentViewSelection];\n\n\t/* Inform views that are currently selected that no longer will be that they\n\t are now hidden. We wait until after -updateChannelViewBoxContentViewSelection\n\t is called to do this so that the views that are hidden are actually hidden\n\t before informing the views of this fact. */\n\tfor (IRCTreeItem *item in selectedItemsPrevious) {\n\t\tif (selectedItems == nil || [selectedItems containsObject:item] == NO) {\n\t\t\t[item.viewController notifyDidBecomeHidden];\n\t\t}\n\t}\n\n\t/* Inform new views that they are visible now that they are visible. */\n\tfor (IRCTreeItem *item in selectedItems) {\n\t\tif (selectedItemsPrevious == nil || [selectedItemsPrevious containsObject:item] == NO) {\n\t\t\t[item.viewController notifyDidBecomeVisible];\n\n\t\t\tif (item != self.selectedItem) {\n\t\t\t\t[item.viewController notifySelectionChanged];\n\t\t\t}\n\t\t}\n\t}\n\n\tselectedItems = nil;\n\tselectedItemsPrevious = nil;\n\n\t/* Perform postflight routines */\n\t[self selectionDidChangePostflight];\n}\n\n- (void)selectionDidChangePostflight\n{\n\t/* If the selection hasn't changed, then do nothing. */\n\tIRCTreeItem *itemChangedTo = self.selectedItem;\n\n\tIRCTreeItem *itemChangedFrom = self.previouslySelectedItem;\n\n\tif (itemChangedTo == itemChangedFrom) {\n\t\treturn;\n\t}\n\n\t/* Reset state of selections */\n\tif (itemChangedFrom) {\n\t\t[itemChangedFrom resetState];\n\t}\n\n\tif (itemChangedTo) {\n\t\tif (self.multipleItemsSelected) {\n\t\t\t[self.serverList refreshMessageCountForItem:itemChangedTo];\n\t\t}\n\n\t\t[itemChangedTo resetState];\n\t}\n\n\t/* Notify WebKit its selection status has changed */\n\tif (itemChangedFrom) {\n\t\t[itemChangedFrom.viewController notifySelectionChanged];\n\t}\n\n\t/* Destroy member list if we have no selection */\n\tif (itemChangedTo == nil) {\n\t\t[self.memberList assignToChannel:nil];\n\n\t\tself.serverList.menu = nil;\n\n\t\t[self updateTitle];\n\n\t\treturn; // Nothing more to do for empty selections\n\t}\n\n\t/* Prepare the member list for the selection */\n\tBOOL isClient = itemChangedTo.isClient;\n\n\tBOOL isChannel = itemChangedTo.isChannel;\n\n\t/* The right click menu follows selection so let's update\n\t the menu we will show depending on the selection. */\n\tif (isClient) {\n\t\tself.serverList.menu = menuController().mainMenuServerMenuItem.submenu;\n\t} else if (isChannel) {\n\t\tself.serverList.menu = menuController().mainMenuChannelMenu;\n\t} else {\n\t\tself.serverList.menu = menuController().mainMenuQueryMenu;\n\t}\n\n\t/* Update table view data sources */\n\tif (isChannel) {\n\t\t[self.memberList assignToChannel:(id)itemChangedTo];\n\t} else {\n\t\t[self.memberList assignToChannel:nil];\n\t}\n\n\t/* Begin work on text field */\n\tBOOL autoFocusInputTextField = [TPCPreferences focusMainTextViewOnSelectionChange];\n\n\tif (autoFocusInputTextField && [XRAccessibility isVoiceOverEnabled] == NO) {\n\t\t[self.inputTextField focus];\n\t}\n\n\t[self.inputTextField updateSegmentedController];\n\n\t/* Setup text field value with history item when we have\n\t history setup to be channel specific. */\n\t[self.inputHistoryManager moveFocusTo:itemChangedTo];\n\n\t/* Reset spelling for text field */\n\t[self.inputTextField resetSpellingIgnores];\n\n\t/* Update splitter view depending on selection */\n\tif (isChannel) {\n\t\tif (self.memberList.isHiddenByUser == NO) {\n\t\t\t[self.contentSplitView expandMemberList];\n\t\t}\n\t} else {\n\t\t[self.contentSplitView collapseMemberList];\n\t}\n\n\t/* Notify WebKit its selection status has changed */\n\t[itemChangedTo.viewController notifySelectionChanged];\n\n\t/* Finish up */\n\t[self storeLastSelectedChannel];\n\n\t[RZNotificationCenter() postNotificationName:TVCMainWindowSelectionChangedNotification object:self];\n\n\t[TVCDockIcon updateDockIcon];\n\n\t[self updateTitle];\n}\n\n#pragma mark -\n#pragma mark Split View\n\n- (void)saveContentSplitViewState\n{\n\t[RZUserDefaults() setBool:self.serverListVisible\n\t\t\t\t\t   forKey:@\"Window -> Main Window -> Server List is Visible\"];\n\n\t[RZUserDefaults() setBool:(self.memberList.isHiddenByUser == NO)\n\t\t\t\t\t   forKey:@\"Window -> Main Window -> Member List is Visible\"];\n}\n\n- (void)restoreSavedContentSplitViewState\n{\n\t/* Make server list and member list visible + restore saved position. */\n\t[self.contentSplitView restorePositions];\n\n\t/* Collapse one or more items if they were collapsed when closing Textual. */\n\tid makeMemberListVisible = [RZUserDefaults() objectForKey:@\"Window -> Main Window -> Member List is Visible\"];\n\n\tif (makeMemberListVisible && [makeMemberListVisible boolValue] == NO) {\n\t\tself.memberList.isHiddenByUser = YES;\n\n\t\t[self.contentSplitView collapseMemberList];\n\t}\n\n\tid makeServerListVisible = [RZUserDefaults() objectForKey:@\"Window -> Main Window -> Server List is Visible\"];\n\n\tif (makeServerListVisible && [makeServerListVisible boolValue] == NO) {\n\t\t[self.contentSplitView collapseServerList];\n\t}\n}\n\n- (BOOL)isMemberListVisible\n{\n\treturn (self.contentSplitView.memberListCollapsed == NO);\n}\n\n- (BOOL)isServerListVisible\n{\n\treturn (self.contentSplitView.serverListCollapsed == NO);\n}\n\n#pragma mark -\n#pragma mark License Manager\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n- (void)licenseManagerActivatedLicense:(NSNotification *)notification\n{\n\t[self reloadLoadingScreen];\n}\n\n- (void)licenseManagerDeactivatedLicense:(NSNotification *)notification\n{\n\t[self reloadLoadingScreen];\n}\n\n- (void)licenseManagerTrialExpired:(NSNotification *)notification\n{\n\t[self reloadLoadingScreen];\n}\n#endif\n\n#pragma mark -\n#pragma mark Loading Screen\n\n- (void)setLoadingScreenProgressViewReason:(NSString *)progressReason\n{\n\tNSParameterAssert(progressReason != nil);\n\n\t[self.loadingScreen setProgressViewReason:progressReason];\n}\n\n- (BOOL)reloadLoadingScreen\n{\n\t/* This method returns YES (success) if the loading screen is dismissed\n\t when called. NO indicates an error that resulted in it staying on screen. */\n\tif (worldController().isImportingConfiguration) {\n\t\treturn NO;\n\t}\n\n\tif (masterController().applicationIsLaunched == NO) {\n\t\t[self.loadingScreen showProgressViewWithReason:TXTLS(@\"TVCMainWindow[iph-a9]\")];\n\n\t\treturn NO;\n\t}\n\n#if TEXTUAL_BUILT_WITH_LICENSE_MANAGER == 1\n\tif (TLOLicenseManagerTextualIsRegistered() == NO && TLOLicenseManagerIsTrialExpired()) {\n\t\t[self.loadingScreen showTrialExpiredView];\n\n\t\treturn NO;\n\t}\n#endif\n\n\tif (worldController().clientCount <= 0) {\n\t\t[self.loadingScreen showWelcomeAddServerView];\n\n\t\treturn NO;\n\t}\n\n\t[self.loadingScreen hideAnimated];\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Window Extras\n\n- (void)presentCertificateTrustInformation:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\n\tif (u) {\n\t\t[u presentCertificateTrustInformation];\n\t}\n}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n- (void)titlebarAccessoryViewLockButtonClicked:(id)sender\n{\n\tNSMenu *statusMenu = menuController().encryptionManagerStatusMenu;\n\n\t[statusMenu popUpMenuPositioningItem:nil\n\t\t\t\t\t\t\t  atLocation:self.titlebarAccessoryViewLockButton.frame.origin\n\t\t\t\t\t\t\t\t  inView:self.titlebarAccessoryViewLockButton];\n}\n#endif\n\n- (void)updateAccessoryViewLockButton\n{\n\tIRCClient *u = self.selectedClient;\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\tIRCChannel *c = self.selectedChannel;\n\n\tBOOL updateEncryption = (c.isPrivateMessage && [u encryptionAllowedForTarget:c.name]);\n\n\tif (updateEncryption) {\n\t\tself.titlebarAccessoryViewLockButton.action = @selector(titlebarAccessoryViewLockButtonClicked:);\n\n\t\t[self.titlebarAccessoryViewLockButton enableDrawingCustomBackgroundColor];\n\n\t\t[self.titlebarAccessoryViewLockButton positionImageOnLeftSide];\n\n\t\t[sharedEncryptionManager() updateLockIconButton:self.titlebarAccessoryViewLockButton\n\t\t\t\t\t\t\t\t\t\t\twithStateOf:[u encryptionAccountNameForUser:c.name]\n\t\t\t\t\t\t\t\t\t\t\t\t   from:[u encryptionAccountNameForLocalUser]];\n\n\t\tself.titlebarAccessoryView.hidden = NO;\n\t}\n\telse\n\t{\n#endif\n\n\t\tself.titlebarAccessoryViewLockButton.action = @selector(presentCertificateTrustInformation:);\n\n\t\t[self.titlebarAccessoryViewLockButton disableDrawingCustomBackgroundColor];\n\n\t\t[self.titlebarAccessoryViewLockButton positionImageOverContent];\n\n\t\tself.titlebarAccessoryViewLockButton.title = @\"\";\n\n\t\tif (u.isSecured) {\n\t\t\t[self.titlebarAccessoryViewLockButton setIconAsLocked];\n\n\t\t\tself.titlebarAccessoryView.hidden = NO;\n\t\t} else {\n\t\t\tself.titlebarAccessoryView.hidden = YES;\n\t\t}\n\n#if TEXTUAL_BUILT_WITH_ADVANCED_ENCRYPTION == 1\n\t}\n#endif\n\n\tif (self.titlebarAccessoryView.hidden == NO) {\n\t\t[self.titlebarAccessoryViewLockButton sizeToFit];\n\t}\n}\n\n- (void)addAccessoryViewsToTitlebar\n{\n\tNSThemeFrame *themeFrame = (NSThemeFrame *)self.contentView.superview;\n\n\tthemeFrame.usesCustomTitlebarTitlePositioning = YES;\n\n\tNSTitlebarAccessoryViewController *accessoryView = self.titlebarAccessoryViewController;\n\n\taccessoryView.layoutAttribute = NSLayoutAttributeRight;\n\n\t[self addTitlebarAccessoryViewController:accessoryView];\n}\n\n- (void)updateTitleFor:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\tif ([self isItemSelected:item] == NO) {\n\t\treturn;\n\t}\n\n\t[self updateTitle];\n}\n\n- (void)updateTitle\n{\n\t[self updateAccessoryViewLockButton];\n\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil && c == nil) {\n\t\tself.title = [TPCApplicationInfo applicationName];\n\n\t\treturn;\n\t}\n\n\tNSMutableString *title = [NSMutableString string];\n\n\tif (u.isConnected == NO && u.isConnecting == NO) {\n\t\tif (u.isReconnecting) {\n\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[3yn-wd]\")];\n\t\t} else {\n\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[q42-an]\")];\n\t\t}\n\t} else if (u.isConnecting && u.isLoggedIn == NO) {\n\t\tif (u.connectType == IRCClientConnectModeRetry || u.connectType == IRCClientConnectModeReconnect) {\n\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[s23-zd]\")];\n\t\t} else {\n\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[8eu-c7]\")];\n\t\t}\n\t} else if (u.isConnected && u.isLoggedIn == NO) {\n\t\t[title appendString:TXTLS(@\"TVCMainWindow[wcb-y8]\")];\n\t} else if (u.isQuitting) {\n\t\t[title appendString:TXTLS(@\"TVCMainWindow[xqd-h9]\")];\n\t}\n\t\n\tNSString *awayStatus = ((u.userIsAway) ? TXTLS(@\"TVCMainWindow[nxz-l9]\") : @\"\");\n\n\t[title appendString:TXTLS(@\"TVCMainWindow[19v-bc]\", u.userNickname, awayStatus, u.networkNameAlt)];\n\n\tif (c == nil) // = Client\n\t{\n\t\t/* If we have the actual server that the client is connected\n\t\t to, then we we append that. Otherwise, we just leave it blank. */\n\t\tNSString *serverAddress = u.serverAddress;\n\n\t\tif (serverAddress) {\n\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[jqk-ha]\")]; // divider\n\n\t\t\t[title appendString:serverAddress];\n\t\t}\n\t}\n\telse\n\t{\n\t\t[title appendString:TXTLS(@\"TVCMainWindow[jqk-ha]\")]; // divider\n\n\t\tNSString *channelName = c.name;\n\n\t\tswitch (c.type) {\n\t\t\tcase IRCChannelTypeChannel:\n\t\t\t{\n\t\t\t\t[title appendString:channelName];\n\n\t\t\t\tNSString *userCount = TXFormattedNumber(c.numberOfMembers);\n\n\t\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[v6i-zb]\", userCount)];\n\n\t\t\t\tNSString *modeSymbols = c.modeInfo.stringWithMaskedPassword;\n\n\t\t\t\tif (modeSymbols.length > 1) {\n\t\t\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[cyg-g9]\", modeSymbols)];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCChannelTypePrivateMessage:\n\t\t\t{\n\t\t\t\t/* Textual defines the topic of a private message as the user host. */\n\t\t\t\t/* If it is not defined yet, then we just use the channel name\n\t\t\t\t which is equal to the nickname of the private message owner. */\n\t\t\t\tIRCUser *user = [u findUser:channelName];\n\n\t\t\t\tNSString *hostmask = user.hostmaskFragment;\n\n\t\t\t\tif (hostmask) {\n\t\t\t\t\t[title appendString:TXTLS(@\"TVCMainWindow[6wz-pd]\", channelName, hostmask)];\n\t\t\t\t} else {\n\t\t\t\t\t[title appendString:channelName];\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase IRCChannelTypeUtility:\n\t\t\t{\n\t\t\t\t[title appendString:channelName];\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tself.title = title;\n\n\t[self setAccessibilityTitle:TXTLS(@\"Accessibility[k79-1a]\")];\n}\n\n#pragma mark -\n#pragma mark User List\n\n- (void)updateDrawingForUserInUserList:(IRCUser *)user\n{\n\tIRCChannel *selectedChannel = self.selectedChannel;\n\n\tif (selectedChannel == nil) {\n\t\treturn;\n\t}\n\n\tIRCChannelUser *channelUser = [user userAssociatedWithChannel:selectedChannel];\n\n\tif (channelUser == nil) {\n\t\treturn;\n\t}\n\n\t[self.memberList refreshDrawingForMember:channelUser];\n}\n\n#pragma mark -\n#pragma mark Server List\n\n- (void)saveSelection\n{\n\tNSMutableArray<NSString *> *selectedIdentifiers = [NSMutableArray array];\n\n\tfor (IRCTreeItem *item in self.selectedItems) {\n\t\t[selectedIdentifiers addObject:item.uniqueIdentifier];\n\t}\n\n\t[RZUserDefaults() setObject:[selectedIdentifiers copy]\n\t\t\t\t\t\t forKey:@\"Window -> Main Window -> Server List Selection\"];\n}\n\n- (void)restoreExpandedClients\n{\n\tfor (IRCClient *e in worldController().clientList) {\n\t\tif (e.config.sidebarItemExpanded) {\n\t\t\t[self expandClient:e];\n\t\t}\n\t}\n}\n\n- (void)restoreSelectionDuringSetup\n{\n\tNSArray *selectedIdentifiers = [RZUserDefaults() objectForKey:@\"Window -> Main Window -> Server List Selection\"];\n\n\tif (selectedIdentifiers == nil || selectedIdentifiers.count == 0) {\n\t\t[self selectBestChoiceDuringSetup];\n\n\t\treturn;\n\t}\n\n\tNSArray *selection = [worldController() findItemsWithIds:selectedIdentifiers];\n\n\tif (selection.count == 0) {\n\t\t[self selectBestChoiceDuringSetup];\n\n\t\treturn;\n\t}\n\n\t[self adjustSelectionWithItems:selection selectedItem:nil];\n}\n\n- (void)selectBestChoiceDuringSetup\n{\n\tIRCClient *firstSelection = nil;\n\n\tfor (IRCClient *e in worldController().clientList) {\n\t\tif (e.config.autoConnect && e.config.sidebarItemExpanded) {\n\t\t\tif (firstSelection == nil) {\n\t\t\t\tfirstSelection = e;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (firstSelection) {\n\t\tNSInteger n = [self.serverList rowForItem:firstSelection];\n\n\t\tif (firstSelection.channelCount > 0) {\n\t\t\tn++;\n\t\t}\n\n\t\t[self.serverList selectItemAtIndex:n];\n\t} else {\n\t\t[self.serverList selectItemAtIndex:0];\n\t}\n}\n\n- (void)setupTrees\n{\n\tself.memberList.keyDelegate = self;\n\n\tself.memberList.target = menuController();\n\tself.memberList.doubleAction = @selector(memberInMemberListDoubleClicked:);\n\n\tself.serverList.keyDelegate = self;\n\n\tself.serverList.delegate = (id)self;\n\tself.serverList.dataSource = (id)self;\n\n\tself.serverList.target = self;\n\tself.serverList.doubleAction = @selector(outlineViewDoubleClicked:);\n\n\t/* Inform the table we want drag events */\n\t[self.serverList registerForDraggedTypes:_treeDragItemTypes];\n\n\t/* Prepare our first selection */\n\t[self restoreExpandedClients];\n\n\t[self restoreSelectionDuringSetup];\n\n\t/* Fake the delegate call */\n\t[self outlineViewSelectionDidChange:nil];\n\n\t/* Populate navigation list */\n\t[menuController() populateNavigationChannelList];\n}\n\n- (nullable IRCClient *)selectedClient\n{\n\tif (\t   self.selectedItem) {\n\t\treturn self.selectedItem.associatedClient;\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n- (nullable IRCChannel *)selectedChannel\n{\n\tif (\tself.selectedItem) {\n\t\tif (self.selectedItem.isClient) {\n\t\t\treturn nil;\n\t\t} else {\n\t\t\treturn (id)self.selectedItem;\n\t\t}\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n- (nullable IRCChannel *)selectedChannelOn:(IRCClient *)c\n{\n\tif (self.selectedClient == c) {\n\t\treturn self.selectedChannel;\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n- (nullable TVCLogController *)selectedViewController\n{\n\tif (\t   self.selectedChannel) {\n\t\treturn self.selectedChannel.viewController;\n\t} else if (self.selectedClient) {\n\t\treturn self.selectedClient.viewController;\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n- (void)reloadTreeItem:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\t[self.serverList refreshDrawingForItem:item];\n}\n\n- (void)reloadTreeGroup:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\tif (item.isClient == NO) {\n\t\treturn;\n\t}\n\n\t[self reloadTreeItem:item];\n\n\tfor (IRCChannel *channel in ((IRCClient *)item).channelList) {\n\t\t[self reloadTreeItem:channel];\n\t}\n}\n\n- (void)reloadTree\n{\n\t[self.serverList refreshAllDrawings];\n}\n\n- (void)expandClient:(IRCClient *)client\n{\n\t[[self.serverList animator] expandItem:client];\n}\n\n- (void)adjustSelection\n{\n\t[self adjustSelectionWithItems:self.selectedItems selectedItem:self.selectedItem];\n}\n\n- (void)adjustSelectionWithItems:(NSArray<IRCTreeItem *> *)selectedItems selectedItem:(nullable IRCTreeItem *)selectedItem\n{\n\tNSParameterAssert(selectedItems != nil);\n\n\tNSMutableIndexSet *itemRows = [NSMutableIndexSet indexSet];\n\n\tfor (IRCTreeItem *item in selectedItems) {\n\t\t/* Expand the parent of the item if its not already expanded. */\n\t\tif (item.isClient == NO) {\n\t\t\tIRCClient *itemClient = item.associatedClient;\n\n\t\t\t[self.serverList expandItem:itemClient];\n\t\t}\n\n\t\t/* Find the row of the item */\n\t\tNSInteger itemRow = [self.serverList rowForItem:item];\n\n\t\tif ( itemRow >= 0) {\n\t\t\t[itemRows addIndex:itemRow];\n\t\t}\n\t}\n\n\t/* If the selected rows have not changed, then only select the one item */\n\tNSIndexSet *selectedRows = self.serverList.selectedRowIndexes;\n\n\tif ([selectedRows isEqualToIndexSet:itemRows] == NO) {\n\t\t/* Selection updates are disabled and selection changes are faked so that\n\t\t the correct next item is selected when moving to previous group. */\n\t\tself.ignoreNextOutlineViewSelectionChange = YES;\n\n\t\t[self.serverList selectRowIndexes:itemRows\n\t\t\t\t\t byExtendingSelection:NO\n\t\t\t\t\t\tscrollToSelection:YES];\n\t}\n\n\t/* Perform selection logic */\n\t[self selectionDidChangeToRows:itemRows selectedItem:selectedItem];\n}\n\n- (void)storePreviousSelection\n{\n\tself.previousSelectedItemId = self.selectedItem.uniqueIdentifier;\n\n\t[self storePreviousSelections];\n}\n\n- (void)storePreviousSelections\n{\n\tNSMutableArray<NSString *> *previousSelectedItems = [NSMutableArray array];\n\n\tfor (IRCTreeItem *item in self.selectedItems) {\n\t\t[previousSelectedItems addObject:item.uniqueIdentifier];\n\t}\n\n\tself.previousSelectedItemsId = previousSelectedItems;\n}\n\n- (void)storeLastSelectedChannel\n{\n\tif (self.selectedClient) {\n\t\tself.selectedClient.lastSelectedChannel = self.selectedChannel;\n\t}\n}\n\n- (nullable IRCTreeItem *)previouslySelectedItem\n{\n\tNSString *itemIdentifier = self.previousSelectedItemId;\n\n\tif (itemIdentifier) {\n\t\treturn [worldController() findItemWithId:itemIdentifier];\n\t}\n\n\treturn nil;\n}\n\n- (void)selectPreviousItem\n{\n\t/* Do not try to browse backwards without these items */\n\tif (self.previousSelectedItemId == nil ||\n\t\tself.previousSelectedItemsId == nil)\n\t{\n\t\treturn;\n\t}\n\n\t/* Get previously selected item and cancel if its missing */\n\tIRCTreeItem *itemPrevious = self.previouslySelectedItem;\n\n\tif (itemPrevious == nil) {\n\t\treturn;\n\t}\n\n\t/* Build list of rows in the table view that contain previous group */\n\tNSMutableArray<IRCTreeItem *> *itemsPrevious = [NSMutableArray array];\n\n\tfor (NSString *itemIdentifier in self.previousSelectedItemsId) {\n\t\tIRCTreeItem *item = [worldController() findItemWithId:itemIdentifier];\n\n\t\tif ( item) {\n\t\t\t[itemsPrevious addObject:item];\n\t\t}\n\t}\n\n\t[self adjustSelectionWithItems:itemsPrevious selectedItem:itemPrevious];\n}\n\n- (void)selectItemInSelectedItems:(IRCTreeItem *)selectedItem\n{\n\t[self selectItemInSelectedItems:selectedItem refreshChannelView:YES];\n}\n\n- (void)selectItemInSelectedItems:(IRCTreeItem *)selectedItem refreshChannelView:(BOOL)refreshChannelView\n{\n\tNSParameterAssert(selectedItem != nil);\n\n\t/* Do nothing if items are the same */\n\tif ([self isItemSelected:selectedItem]) {\n\t\treturn;\n\t}\n\n\t/* Select item if its in the current group */\n\tif ([self isItemInSelectedGroup:selectedItem] == NO) {\n\t\treturn;\n\t}\n\n\t[self storePreviousSelection];\n\n\tself.selectedItem = selectedItem;\n\n\tif (refreshChannelView) {\n\t\t[self updateChannelViewBoxContentViewSelection];\n\t}\n\n\t[self selectionDidChangePostflight];\n}\n\n- (void)select:(nullable IRCTreeItem *)item\n{\n\t[self shiftSelection:self.selectedItem\n\t\t\t\t  toItem:item\n\t\t\t\t options:(TVCMainWindowShiftSelectionFlagMaintainGrouping |\n\t\t\t\t\t\t  TVCMainWindowShiftSelectionFlagPerformDeselect)];\n}\n\n- (void)deselect:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\t[self shiftSelection:item\n\t\t\t\t  toItem:nil\n\t\t\t\t options:TVCMainWindowShiftSelectionFlagPerformDeselect];\n}\n\n- (void)deselectGroup:(IRCTreeItem *)item\n{\n\tNSParameterAssert(item != nil);\n\n\tif (item.isClient == NO) {\n\t\treturn;\n\t}\n\n\t[self shiftSelection:item\n\t\t\t\t  toItem:nil\n\t\t\t\t options:(TVCMainWindowShiftSelectionFlagPerformDeselect |\n\t\t\t\t\t\t  TVCMainWindowShiftSelectionFlagPerformDeselectChildren)];\n}\n\n- (void)shiftSelection:(nullable IRCTreeItem *)oldItem toItem:(nullable IRCTreeItem *)newItem options:(TVCMainWindowShiftSelectionFlags)selectionOptions\n{\n\tif (oldItem == newItem) {\n\t\treturn;\n\t}\n\n\t/* If the next item is a channel, then make sure the client\n\t it is associated with is expanded, or we can't switch to it. */\n\tif (newItem && newItem.isClient == NO) {\n\t\tIRCClient *itemClient = newItem.associatedClient;\n\n\t\t[self expandClient:itemClient];\n\t}\n\n\t/* Context */\n\tBOOL optionMaintainGrouping = ((selectionOptions & TVCMainWindowShiftSelectionFlagMaintainGrouping) == TVCMainWindowShiftSelectionFlagMaintainGrouping);\n\n\tBOOL optionPerformDeselectAll = NO;\n\tBOOL optionPerformDeselectOld = ((selectionOptions & TVCMainWindowShiftSelectionFlagPerformDeselect) == TVCMainWindowShiftSelectionFlagPerformDeselect);\n\tBOOL optionPerformDeselectChildren = ((selectionOptions & TVCMainWindowShiftSelectionFlagPerformDeselectChildren) == TVCMainWindowShiftSelectionFlagPerformDeselectChildren);\n\n\tBOOL optionPerformDeselect = (optionPerformDeselectChildren || optionPerformDeselectOld);\n\n\t/* Do nothing if item is not group */\n\tNSInteger itemIndexOld = [self.serverList rowForItem:oldItem];\n\tNSInteger itemIndexNew = [self.serverList rowForItem:newItem];\n\n\tNSIndexSet *selectedRows = self.serverList.selectedRowIndexes;\n\n\tNSIndexSet *selectedRowsForbidden = nil;\n\n\t/* Maybe do nothing at all */\n\tif (optionPerformDeselect && itemIndexOld >= 0 && [selectedRows containsIndex:itemIndexOld] == NO) {\n\t\treturn;\n\t}\n\n\t/* If we are not performing a deselect for the old item and both items\n\t are selected, then simply update selection inside grouping. */\n\tif (optionMaintainGrouping &&\n\t\t(itemIndexOld >= 0 && [selectedRows containsIndex:itemIndexOld]) &&\n\t\t(itemIndexNew >= 0 && [selectedRows containsIndex:itemIndexNew]) &&\n\t\tnewItem != nil) // This condition is impossible but static analyzer doesn't know that.\n\t\t\t\t\t\t// Condition is impossible because itemIndexNew will never return\n\t\t\t\t\t\t// greater to or equal zero unless item is non-nil.\n\t{\n\t\t[self selectItemInSelectedItems:newItem];\n\n\t\treturn;\n\t} else {\n\t\tif (optionPerformDeselectOld) {\n\t\t\toptionPerformDeselectAll = YES;\n\t\t}\n\t}\n\n\t/* Create a mutable copy of the current selection */\n\tNSMutableIndexSet *selectedRowsNew = [selectedRows mutableCopy];\n\n\tif (optionPerformDeselectAll) {\n\t\t[selectedRowsNew removeAllIndexes];\n\t} else if (optionPerformDeselectOld) {\n\t\t[selectedRowsNew removeIndex:itemIndexOld];\n\t}\n\n\t/* optionPerformDeselectChildren is still performed even if optionPerformDeselectAll\n\t is set so that the list of forbidden rows can be defined by it. */\n\tif (optionPerformDeselectChildren) {\n\t\tNSIndexSet *childrenRowRange = [self.serverList indexesOfItemsInGroup:oldItem];\n\n\t\tif (childrenRowRange) {\n\t\t\t[selectedRowsNew removeIndexes:childrenRowRange];\n\n\t\t\tselectedRowsForbidden = childrenRowRange;\n\t\t}\n\t}\n\n\t/* If the next item is not nil and is a row, then select that */\n\tif (newItem) {\n\t\tif (itemIndexNew >= 0) {\n\t\t\t[selectedRowsNew addIndex:itemIndexNew];\n\t\t} else {\n\t\t\tLogToConsoleDebug(\"Tried to shift selection to an item not in the server list\");\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* If no item to switch to is specified, then the current action is \n\t treated as a deselect for the old item. In that case, we pick the \n\t next best item to remain selected. */\n\tif (newItem == nil) {\n\t\t/* If there is an item in the current selection that is before \n\t\t or after the row removed, then we can use that. */\n\t\tBOOL selectedRowsComplete =\n\t\t([selectedRowsNew indexLessThanIndex:itemIndexOld] != NSNotFound ||\n\t\t [selectedRowsNew indexGreaterThanIndex:itemIndexOld] != NSNotFound);\n\n\t\t/* If there is not an item in the current selection that can take over,\n\t\t then the first step is to try to find an item newer than the current. */\n\t\tif (selectedRowsComplete == NO) {\n\t\t\tNSInteger numberOfRows = self.serverList.numberOfRows;\n\n\t\t\tNSInteger nextSelectionRow = (itemIndexOld + 1);\n\n\t\t\t/* Next row is in forbidden range */\n\t\t\tif (selectedRowsForbidden && [selectedRowsForbidden containsIndex:nextSelectionRow]) {\n\t\t\t\tnextSelectionRow = (selectedRowsForbidden.lastIndex + 1);\n\t\t\t}\n\n\t\t\t/* Next row is above number of rows. Try to go one below instead. */\n\t\t\tif (nextSelectionRow >= numberOfRows) {\n\t\t\t\tnextSelectionRow = (itemIndexOld - 1);\n\t\t\t}\n\n\t\t\t/* Previous row is in forbidden range */\n\t\t\tif (selectedRowsForbidden && [selectedRowsForbidden containsIndex:nextSelectionRow]) {\n\t\t\t\tnextSelectionRow = (selectedRowsForbidden.firstIndex - 1);\n\t\t\t}\n\n\t\t\t/* Previous row is less than zero. There is no where else to go. */\n\t\t\tif (nextSelectionRow < 0) {\n\t\t\t\tnextSelectionRow = (-1);\n\t\t\t}\n\n\t\t\t/* Add new selection index if there is one. */\n\t\t\tif (nextSelectionRow >= 0) {\n\t\t\t\t[selectedRowsNew addIndex:nextSelectionRow];\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Save selection */\n\tif (selectedRowsNew.count == 0) {\n\t\t[self storePreviousSelection];\n\n\t\tself.selectedItem = nil;\n\t\tself.selectedItems = @[];\n\n\t\t[self selectionDidChangePostflight];\n\n\t\treturn;\n\t}\n\n\t[self.serverList selectRowIndexes:selectedRowsNew\n\t\t\t\t byExtendingSelection:NO\n\t\t\t\t\tscrollToSelection:YES];\n}\n\n#pragma mark -\n#pragma mark Server List Delegate\n\n- (void)outlineViewDoubleClicked:(id)sender\n{\n\tIRCClient *u = self.selectedClient;\n\tIRCChannel *c = self.selectedChannel;\n\n\tif (u == nil && c == nil) {\n\t\treturn;\n\t}\n\n\tif (u && c == nil)\n\t{\n\t\tif (u.isConnecting || u.isConnected)\n\t\t{\n\t\t\tif ([TPCPreferences disconnectOnDoubleclick]) {\n\t\t\t\t[u quit];\n\t\t\t}\n\t\t}\n\t\telse if (u.isQuitting)\n\t\t{\n\t\t\tLogToConsole(\"Double click event ignored because client is quitting\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ([TPCPreferences connectOnDoubleclick]) {\n\t\t\t\t[u connect];\n\t\t\t}\n\t\t}\n\n\t\t[self expandClient:u];\n\t}\n\telse\n\t{\n\t\tif (u.isLoggedIn == NO) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (c.isActive)\n\t\t{\n\t\t\tif ([TPCPreferences leaveOnDoubleclick]) {\n\t\t\t\t[u partChannel:c];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ([TPCPreferences joinOnDoubleclick]) {\n\t\t\t\t[u joinChannel:c];\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(nullable id)item\n{\n\tif (item) {\n\t\treturn [item numberOfChildren];\n\t}\n\n\treturn worldController().clientCount;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item\n{\n\treturn ([item numberOfChildren] > 0);\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(nullable id)item\n{\n\tif (item) {\n\t\treturn [item childAtIndex:index];\n\t}\n\n\treturn worldController().clientList[index];\n}\n\n- (nullable id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable id)item\n{\n\treturn item;\n}\n\n- (nullable NSTableRowView *)outlineView:(NSOutlineView *)outlineView rowViewForItem:(id)item\n{\n\tif (item == nil || [item isClient]) {\n\t\treturn [[TVCServerListGroupRowCell alloc] initWithServerList:(id)outlineView];\n\t} else {\n\t\treturn [[TVCServerListChildRowCell alloc] initWithServerList:(id)outlineView];\n\t}\n}\n\n- (nullable NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(nullable NSTableColumn *)tableColumn item:(id)item\n{\n\tNSString *viewIdentifier = nil;\n\n\tif (item == nil || [item isClient]) {\n\t\tviewIdentifier = @\"GroupView\";\n\t} else {\n\t\tviewIdentifier = @\"ChildView\";\n\t}\n\n\tNSView *newView = [outlineView makeViewWithIdentifier:viewIdentifier owner:self];\n\n\treturn newView;\n}\n\n- (void)outlineView:(NSOutlineView *)outlineView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row\n{\n\t[self.serverList refreshDrawingForRow:row];\n}\n\n- (void)outlineViewItemDidCollapse:(NSNotification *)notification\n{\n\tid itemBeingCollapsed = notification.userInfo[@\"NSObject\"];\n\n\tIRCClient *u = [itemBeingCollapsed associatedClient];\n\n\tu.sidebarItemIsExpanded = NO;\n}\n\n- (void)outlineViewItemDidExpand:(NSNotification *)notification\n{\n\tid itemBeingCollapsed = notification.userInfo[@\"NSObject\"];\n\n\tIRCClient *u = [itemBeingCollapsed associatedClient];\n\n\tu.sidebarItemIsExpanded = YES;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item\n{\n\treturn YES;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(id)item\n{\n\treturn YES;\n}\n\n- (void)outlineViewItemWillCollapse:(NSNotification *)notification\n{\n\n}\n\n- (BOOL)selectionShouldChangeInOutlineView:(NSOutlineView *)outlineView\n{\n\tTVCServerList *serverList = (id)outlineView;\n\n\t/* Allow rows to be deselected during redrawing */\n\t/* See logic in -updateAppearance in TVCServerList */\n\tif (serverList.invalidatingBackgroundForSelection) {\n\t\treturn YES;\n\t}\n\n\t/* If the window is not focused, don't allow change. */\n\tif (self.keyWindow == NO) {\n\t\treturn NO;\n\t}\n\n\t/* If the server list does not have a mouse down event, allow change. */\n\tif (serverList.leftMouseIsDownInView == NO) {\n\t\treturn YES;\n\t}\n\n\t/* If command or shift are held down, allow change. */\n\tNSUInteger keyboardKeys = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\tif ((keyboardKeys & NSEventModifierFlagCommand) == NSEventModifierFlagCommand ||\n\t\t(keyboardKeys & NSEventModifierFlagShift) == NSEventModifierFlagShift)\n\t{\n\t\treturn YES;\n\t}\n\n\t/* Find which row is beneath the mouse */\n\tNSInteger rowBeneathMouse = outlineView.rowBeneathMouse;\n\n\t/* If a row is not beneath the mouse or the row that is, is not\n\t selected, then the selection is allowed to be changed. */\n\tif (rowBeneathMouse < 0) {\n\t\treturn YES;\n\t}\n\n\tif ([outlineView isRowSelected:rowBeneathMouse] == NO) {\n\t\treturn YES;\n\t}\n\n\t/* If the item beneath the mouse is already selected and we did not \n\t try to unselect it by holding command or shift, then tell the table\n\t view not to change the selection. That will be handled by us. */\n\tIRCTreeItem *itemUnderMouse = [outlineView itemAtRow:rowBeneathMouse];\n\n\t[self selectItemInSelectedItems:itemUnderMouse];\n\n\treturn NO;\n}\n\n- (NSIndexSet *)outlineView:(NSOutlineView *)outlineView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes\n{\n#define _maximumSelectedRows\t6\n\n\treturn [outlineView selectionIndexesForProposedSelection:proposedSelectionIndexes maximumNumberOfSelections:_maximumSelectedRows];\n\n#undef _maximumSelectedRows\n}\n\n- (void)outlineViewSelectionDidChange:(NSNotification *)notification\n{\n\tTVCServerList *serverList = (id)((notification.object) ?: self.serverList);\n\n\tif (serverList.invalidatingBackgroundForSelection) {\n\t\treturn;\n\t}\n\n\tif (self.ignoreNextOutlineViewSelectionChange) {\n\t\tself.ignoreNextOutlineViewSelectionChange = NO;\n\n\t\treturn;\n\t}\n\n\tif (self.ignoreOutlineViewSelectionChanges) {\n\t\treturn;\n\t}\n\n\tNSIndexSet *selectedRows = serverList.selectedRowIndexes;\n\n\tIRCTreeItem *selectedItem = nil;\n\n\tNSUInteger keyboardKeys = ([NSEvent modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask);\n\n\tif (keyboardKeys == NSEventModifierFlagCommand) {\n\t\tNSInteger rowBeneathMouse = serverList.rowBeneathMouse;\n\n\t\tif (rowBeneathMouse >= 0 && [selectedRows containsIndex:rowBeneathMouse]) {\n\t\t\tselectedItem = [serverList itemAtRow:rowBeneathMouse];\n\t\t}\n\t}\n\n\tif (selectedItem) {\n\t\t[self selectionDidChangeToRows:selectedRows selectedItem:selectedItem];\n\t} else {\n\t\t[self selectionDidChangeToRows:selectedRows];\n\t}\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard\n{\n\t/* TODO (March 27, 2016): Support dragging multiple items */\n\tif (items.count == 1) {\n\t\tNSString *itemToken = [worldController() pasteboardStringForItem:items[0]];\n\n\t\t[pasteboard declareTypes:_treeDragItemTypes owner:self];\n\n\t\t[pasteboard setString:itemToken forType:_treeDragItemType];\n\t}\n\n\treturn YES;\n}\n\n- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(nullable id)item proposedChildIndex:(NSInteger)index\n{\n\tif (index < 0) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tNSPasteboard *pasteboard = [info draggingPasteboard];\n\n\tif ([pasteboard availableTypeFromArray:_treeDragItemTypes] == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tNSString *draggedItemToken = [pasteboard stringForType:_treeDragItemType];\n\n\tif (draggedItemToken == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tIRCTreeItem *draggedItem = [worldController() findItemWithPasteboardString:draggedItemToken];\n\n\tif (draggedItem == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tif (draggedItem.isClient)\n\t{\n\t\tif (item) {\n\t\t\treturn NSDragOperationNone;\n\t\t}\n\t}\n\telse\n\t{\n\t\tIRCChannel *channel = (IRCChannel *)draggedItem;\n\n\t\tif (channel.associatedClient != item) {\n\t\t\treturn NSDragOperationNone;\n\t\t}\n\n\t\tIRCClient *client = (IRCClient *)item;\n\n\t\tNSArray *channelList = client.channelList;\n\n\t\tIRCChannel *previousItem = nil;\n\n\t\tif ((index - 1) >= 0) {\n\t\t\tpreviousItem = channelList[(index - 1)];\n\t\t}\n\n\t\tIRCChannel *nextItem = nil;\n\n\t\tif (index < channelList.count) {\n\t\t\tnextItem = channelList[index];\n\t\t}\n\n\t\tif (channel.isChannel) {\n\t\t\tif (previousItem && previousItem.isChannel == NO) {\n\t\t\t\treturn NSDragOperationNone;\n\t\t\t}\n\t\t} else {\n\t\t\tif (nextItem.isChannel) {\n\t\t\t\treturn NSDragOperationNone;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn NSDragOperationGeneric;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(nullable id)item childIndex:(NSInteger)index\n{\n\tif (index < 0) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tNSPasteboard *pasteboard = [info draggingPasteboard];\n\n\tif ([pasteboard availableTypeFromArray:_treeDragItemTypes] == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tNSString *draggedItemToken = [pasteboard stringForType:_treeDragItemType];\n\n\tif (draggedItemToken == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tIRCTreeItem *draggedItem = [worldController() findItemWithPasteboardString:draggedItemToken];\n\n\tif (draggedItem == nil) {\n\t\treturn NSDragOperationNone;\n\t}\n\n\tTVCServerList *serverList = (id)outlineView;\n\n\tif (draggedItem.isClient)\n\t{\n\t\tNSArray *clientList = worldController().clientList;\n\n\t\tNSMutableArray *clientListMutable = [clientList mutableCopy];\n\n\t\tNSUInteger originalIndex = [clientList indexOfObjectIdenticalTo:draggedItem];\n\n\t\t[clientListMutable moveObjectAtIndex:originalIndex toIndex:index];\n\n\t\tworldController().clientList = clientListMutable;\n\n\t\t[serverList moveItemAtIndex:originalIndex inParent:nil toIndex:index inParent:nil];\n\t}\n\telse\n\t{\n\t\tif (item == nil || item != draggedItem.associatedClient) {\n\t\t\treturn NO;\n\t\t}\n\n\t\tIRCClient *client = (IRCClient *)item;\n\n\t\tNSArray *channelList = client.channelList;\n\n\t\tNSMutableArray *channelListMutable = [channelList mutableCopy];\n\n\t\tNSUInteger originalIndex = [channelList indexOfObjectIdenticalTo:draggedItem];\n\n\t\t[channelListMutable moveObjectAtIndex:originalIndex toIndex:index];\n\n\t\tclient.channelList = channelListMutable;\n\n\t\t[serverList moveItemAtIndex:originalIndex inParent:client toIndex:index inParent:client];\n\t}\n\n\t[menuController() populateNavigationChannelList];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCAppearancePrivate.h\"\n#import \"TVCServerListAppearancePrivate.h\"\n#import \"TVCMemberListAppearancePrivate.h\"\n#import \"TVCMainWindowTextViewAppearancePrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowAppearance ()\n@property (nonatomic, strong, readwrite) TVCServerListAppearance *serverList;\n@property (nonatomic, strong, readwrite) TVCMemberListAppearance *memberList;\n@property (nonatomic, strong, readwrite) TVCMainWindowTextViewAppearance *textView;\n@property (nonatomic, assign, readwrite) NSSize defaultWindowSize;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelViewOverlayDefaultBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelViewOverlayDefaultBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *loadingScreenBackgroundColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *splitViewDividerColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *titlebarAccessoryViewBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *titlebarAccessoryViewBackgroundColorInactiveWindow;\n@property (nonatomic, assign, readwrite) CGFloat titlebarAccessoryViewLeftMargin;\n@property (nonatomic, assign, readwrite) CGFloat titlebarAccessoryViewRightMargin;\n@end\n\n@implementation TVCMainWindowAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (nullable instancetype)initWithWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(mainWindow != nil);\n\n\tNSURL *appearanceLocation = [self.class appearanceLocation];\n\n\tBOOL forRetinaDisplay = mainWindow.runningInHighResolutionMode;\n\n\tif ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\t[self prepareInitialStateWithWindow:mainWindow];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (NSURL *)appearanceLocation\n{\n\treturn [RZMainBundle() URLForResource:@\"TVCMainWindowAppearance\" withExtension:@\"plist\"];\n}\n\n- (void)prepareInitialStateWithWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(mainWindow != nil);\n\n\tself.defaultWindowSize = [self sizeForKey:@\"defaultWindowSize\"];\n\n\tself.channelViewOverlayDefaultBackgroundColorActiveWindow = [self colorForKey:@\"channelViewOverlayDefaultBackgroundColor\" forActiveWindow:YES];\n\tself.channelViewOverlayDefaultBackgroundColorInactiveWindow = [self colorForKey:@\"channelViewOverlayDefaultBackgroundColor\" forActiveWindow:NO];\n\n\tself.loadingScreenBackgroundColor = [self colorForKey:@\"loadingScreenBackgroundColor\"];\n\n\tself.splitViewDividerColor = [self colorForKey:@\"splitViewDividerColor\"];\n\n\tself.titlebarAccessoryViewBackgroundColorActiveWindow = [self colorForKey:@\"titlebarAccessoryViewBackgroundColor\" forActiveWindow:YES];\n\tself.titlebarAccessoryViewBackgroundColorInactiveWindow = [self colorForKey:@\"titlebarAccessoryViewBackgroundColor\" forActiveWindow:NO];\n\n\tself.titlebarAccessoryViewLeftMargin = [self measurementForKey:@\"titlebarAccessoryViewLeftMargin\"];\n\tself.titlebarAccessoryViewRightMargin = [self measurementForKey:@\"titlebarAccessoryViewRightMargin\"];\n\n\tself.serverList = [[TVCServerListAppearance alloc] initWithServerList:mainWindow.serverList inWindow:mainWindow];\n\tself.memberList = [[TVCMemberListAppearance alloc] initWithMemberList:mainWindow.memberList inWindow:mainWindow];\n\tself.textView = [[TVCMainWindowTextViewAppearance alloc] initWithWindow:mainWindow];\n\n\t[self flushAppearanceProperties];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowChannelView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXAppearance.h\"\n#import \"NSViewHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCThemeController.h\"\n#import \"TPCTheme.h\"\n#import \"IRCTreeItem.h\"\n#import \"TVCLogController.h\"\n#import \"TVCLogView.h\"\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowSplitViewPrivate.h\"\n#import \"TVCMainWindowChannelViewPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMainWindowChannelViewSubviewOverlayView;\n\n@interface TVCMainWindowChannelViewSubview : NSView\n@property (nonatomic, assign) NSUInteger itemIndex;\n@property (nonatomic, assign) BOOL isSelected;\n@property (nonatomic, assign) BOOL overlayVisible;\n@property (nonatomic, assign) BOOL isObservingBackingView;\n@property (readonly) BOOL backingViewIsLoading;\n@property (nonatomic, copy) NSString *uniqueIdentifier;\n@property (nonatomic, strong, nullable) TVCLogView *backingView;\n@property (nonatomic, weak) TVCMainWindowChannelView *parentView;\n@property (nonatomic, strong, nullable) TVCMainWindowChannelViewSubviewOverlayView *overlayView;\n\n- (void)toggleOverlayView;\n@end\n\n@interface TVCMainWindowChannelViewSubviewOverlayView : NSView\n@end\n\n@interface TVCMainWindowChannelView ()\n@property (nonatomic, assign) BOOL isMovingDividers;\n@property (nonatomic, assign) NSUInteger itemIndexSelected;\n\n- (void)selectionChangeTo:(NSUInteger)itemIndex;\n@end\n\n@implementation TVCMainWindowChannelView\n\nNSComparisonResult sortSubviews(TVCMainWindowChannelViewSubview *firstView,\n\t\t\t\t\t\t\t\tTVCMainWindowChannelViewSubview *secondView,\n\t\t\t\t\t\t\t\tvoid *context)\n{\n\tNSUInteger itemIndex1 = firstView.itemIndex;\n\tNSUInteger itemIndex2 = secondView.itemIndex;\n\n\tif (itemIndex1 < itemIndex2) {\n\t\treturn NSOrderedAscending;\n\t} else if (itemIndex1 > itemIndex2) {\n\t\treturn NSOrderedDescending;\n\t}\n\n\treturn NSOrderedSame;\n}\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.delegate = (id)self;\n}\n\n- (void)viewDidMoveToWindow\n{\n\tif (self.window == nil) {\n\t\t[RZNotificationCenter() removeObserver:self];\n\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(themeAppearanceChanged:)\n\t\t\t\t\t\t\t\t   name:TPCThemeAppearanceChangedNotification\n\t\t\t\t\t\t\t\t object:nil];\n}\n\n- (void)resetSubviews\n{\n\tNSArray *subviews = [self.subviews copy];\n\n\tfor (NSView *subview in subviews) {\n\t\t[subview removeFromSuperview];\n\t}\n}\n\n- (void)populateSubviews\n{\n\t/* Get list of views selected by the user */\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tNSArray *selectedItems = mainWindow.selectedItems;\n\n\tNSUInteger selectedItemsCount = selectedItems.count;\n\n\tif (selectedItemsCount == 0) {\n\t\t[self resetSubviews];\n\n\t\tself.itemIndexSelected = NSNotFound;\n\n\t\treturn;\n\t}\n\n\t/* Make a list of subviews that already exist to compare when adding\n\t or removing views so that we do not have to destroy entire backing. */\n\tNSMutableDictionary *subviews = nil;\n\n\tfor (TVCMainWindowChannelViewSubview *subview in self.subviews) {\n\t\tNSString *uniqueIdentifier = subview.uniqueIdentifier;\n\n\t\tif (subviews == nil) {\n\t\t\tsubviews = [NSMutableDictionary dictionary];\n\t\t}\n\n\t\tsubviews[uniqueIdentifier] = subview;\n\t}\n\n\t/* Once selectedItems is processed, the value of subviewsUnclaimed will\n\t be subviews that are no longer selected */\n\tNSMutableDictionary *subviewsUnclaimed = nil;\n\n\tif (subviews) {\n\t\tsubviewsUnclaimed = [subviews mutableCopy];\n\t}\n\n\t/* Enumerate views that the user has selected */\n\tIRCTreeItem *itemSelected = mainWindow.selectedItem;\n\n\t__block NSUInteger itemSelectedIndex = NSNotFound;\n\n\t[selectedItems enumerateObjectsUsingBlock:^(IRCTreeItem *item, NSUInteger index, BOOL *stop) {\n\t\tNSString *uniqueIdentifier = item.uniqueIdentifier;\n\n\t\tTVCMainWindowChannelViewSubview *subview = nil;\n\n\t\tBOOL subviewIsNew = YES;\n\n\t\tif (subviews) {\n\t\t\tsubview = subviews[uniqueIdentifier];\n\n\t\t\tif (subview) {\n\t\t\t\tsubviewIsNew = NO;\n\n\t\t\t\t[subviewsUnclaimed removeObjectForKey:uniqueIdentifier];\n\t\t\t}\n\t\t}\n\n\t\tif (subview == nil) {\n\t\t\tsubview = [self subviewForItem:item];\n\t\t}\n\n\t\tTVCLogView *backingView = [self backingViewForItem:item];\n\n\t\tsubview.backingView = backingView;\n\n\t\tsubview.itemIndex = index;\n\n\t\tif (itemSelected == item) {\n\t\t\titemSelectedIndex = index;\n\n\t\t\tsubview.isSelected = YES;\n\t\t} else {\n\t\t\tsubview.isSelected = NO;\n\n\t\t\t/* -isSelected is defaulted to NO which means for new views,\n\t\t\t -toggleOverlayView must be manually invoked because the\n\t\t\t setter wont change the value if they are same (NO == NO) */\n\t\t\tif (subviewIsNew) {\n\t\t\t\t[subview toggleOverlayView];\n\t\t\t}\n\t\t}\n\n\t\tsubview.uniqueIdentifier = uniqueIdentifier;\n\n\t\tif (subviewIsNew) {\n\t\t\t[self addSubview:subview];\n\t\t}\n\t}];\n\n\tself.itemIndexSelected = itemSelectedIndex;\n\n\t/* Remove subviews that are no longer selected */\n\tif (subviewsUnclaimed) {\n\t\tfor (NSString *itemIdentifier in subviewsUnclaimed) {\n\t\t\tTVCMainWindowChannelViewSubview *subview = subviewsUnclaimed[itemIdentifier];\n\n\t\t\t[subview removeFromSuperview];\n\t\t}\n\n\t\tsubviewsUnclaimed = nil;\n\t}\n\n\t/* Sort views */\n\tif (subviews) {\n\t\t[self sortSubviewsUsingFunction:sortSubviews context:nil];\n\n\t\tsubviews = nil;\n\t}\n\n\t/* Size views */\n\t[self adjustSubviews];\n}\n\n- (void)selectionChangeTo:(NSUInteger)itemIndex\n{\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tNSArray *selectedItems = mainWindow.selectedItems;\n\n\tNSArray *subviews = self.subviews;\n\n\tNSUInteger itemIndexSelected = self.itemIndexSelected;\n\n\tif (itemIndexSelected != NSNotFound) {\n\t\tTVCMainWindowChannelViewSubview *oldItemView = subviews[itemIndexSelected];\n\n\t\toldItemView.isSelected = NO;\n\t\t[oldItemView toggleOverlayView];\n\t}\n\n\tTVCMainWindowChannelViewSubview *newItemView = subviews[itemIndex];\n\n\tnewItemView.isSelected = YES;\n\t[newItemView toggleOverlayView];\n\n\tself.itemIndexSelected = itemIndex;\n\n\tIRCTreeItem *newItem = selectedItems[itemIndex];\n\n\t[mainWindow channelViewSelectionChangeTo:newItem];\n}\n\n- (TVCLogView *)backingViewForItem:(IRCTreeItem *)item\n{\n\treturn item.viewController.backingView;\n}\n\n- (TVCMainWindowChannelViewSubview *)subviewForItem:(IRCTreeItem *)item\n{\n\tNSRect splitViewFrame = self.frame;\n\n\tsplitViewFrame.origin.x = 0.0;\n\tsplitViewFrame.origin.y = 0.0;\n\n\t  TVCMainWindowChannelViewSubview *overlayView =\n\t[[TVCMainWindowChannelViewSubview alloc] initWithFrame:splitViewFrame];\n\n\toverlayView.parentView = self;\n\n\treturn overlayView;\n}\n\n- (NSLayoutPriority)holdingPriorityForSubviewAtIndex:(NSInteger)subviewIndex\n{\n\treturn 350.0;\n}\n\n- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview\n{\n\treturn NO;\n}\n\n- (CGFloat)dividerThickness\n{\n\treturn 2.0;\n}\n\n- (NSColor *)dividerColor\n{\n\treturn self.mainWindow.contentSplitView.dividerColor;\n}\n\n- (void)updateArrangement\n{\n\tTXChannelViewArrangement arrangement = [TPCPreferences channelViewArrangement];\n\n\tself.vertical = (arrangement == TXChannelViewArrangedVertically);\n}\n\n- (void)themeAppearanceChanged:(NSNotification *)notification\n{\n\t[self updateVibrancy];\n}\n\n- (void)updateVibrancy\n{\n\tif (theme().appearance == TPCThemeAppearanceTypeDark || themeSettings().underlyingWindowColorIsDark) {\n\t\tself.appearance = [TXAppearancePropertyCollection appKitDarkAppearance];\n\t} else {\n\t\tself.appearance = [TXAppearancePropertyCollection appKitLightAppearance];\n\t}\n}\n\n- (BOOL)needsDisplayWhenApplicationAppearanceChanges\n{\n\treturn YES;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Overlay View\n\n@implementation TVCMainWindowChannelViewSubview\n\n- (instancetype)initWithFrame:(NSRect)frameRect\n{\n\tif ((self = [super initWithFrame:frameRect])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self teardownBackingView];\n}\n\n- (void)prepareInitialState\n{\n\tself.translatesAutoresizingMaskIntoConstraints = NO;\n}\n\n- (BOOL)backingViewIsLoading\n{\n\treturn self.backingView.isLayingOutView;\n}\n\n- (void)setIsSelected:(BOOL)isSelected\n{\n\tif (self->_isSelected != isSelected) {\n\t\tself->_isSelected = isSelected;\n\n\t\t[self toggleOverlayView];\n\t}\n}\n\n- (void)setBackingView:(nullable TVCLogView *)backingView\n{\n\tif (self->_backingView != backingView) {\n\t\t[self teardownBackingView];\n\n\t\tself->_backingView = backingView;\n\n\t\t[self setupWebView];\n\t}\n}\n\n- (void)teardownBackingView\n{\n\tif (self.isObservingBackingView == NO) {\n\t\treturn;\n\t}\n\n\t[self.backingView removeObserver:self forKeyPath:@\"layingOutView\"];\n\n\tself.isObservingBackingView = NO;\n}\n\n- (void)setupWebView\n{\n\tTVCLogView *backingView = self.backingView;\n\n\tif (backingView == nil) {\n\t\treturn;\n\t}\n\n\tif (self.backingViewIsLoading) {\n\t\tself.isObservingBackingView = YES;\n\n\t\t[backingView addObserver:self forKeyPath:@\"layingOutView\" options:NSKeyValueObservingOptionNew context:NULL];\n\t}\n\n\tNSView *webView = backingView.webView;\n\n\tif (self.overlayVisible) {\n\t\t[self addSubview:webView positioned:NSWindowBelow relativeTo:self.overlayView];\n\t} else {\n\t\t[self addSubview:webView];\n\t}\n\n\t[self addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-0-[webView(>=30)]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(webView)]];\n\n\t[self addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-0-[webView(>=30)]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(webView)]];\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"layingOutView\"]) {\n\t\t[self toggleOverlayView];\n\t}\n}\n\n- (void)constructOverlayView\n{\n\t  TVCMainWindowChannelViewSubviewOverlayView *overlayView =\n\t[[TVCMainWindowChannelViewSubviewOverlayView alloc] initWithFrame:self.frame];\n\n\toverlayView.translatesAutoresizingMaskIntoConstraints = NO;\n\n\tself.overlayView = overlayView;\n}\n\n- (void)addOverlayView\n{\n\tif (self.overlayVisible) {\n\t\t[self.overlayView setNeedsDisplay:YES];\n\n\t\treturn;\n\t}\n\n\tif (self.overlayView == nil) {\n\t\t[self constructOverlayView];\n\t}\n\n\tTVCMainWindowChannelViewSubviewOverlayView *overlayView = self.overlayView;\n\n\t[self addSubview:overlayView];\n\n\t[self addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-0-[overlayView]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(overlayView)]];\n\n\t[self addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-0-[overlayView]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(overlayView)]];\n\n\tself.overlayVisible = YES;\n}\n\n- (void)toggleOverlayView\n{\n\tif (self.backingViewIsLoading || self.isSelected == NO) {\n\t\t[self addOverlayView];\n\t} else {\n\t\tif ( self.overlayView) {\n\t\t\t[self.overlayView removeFromSuperview];\n\n\t\t\tself.overlayVisible = NO;\n\t\t}\n\t}\n}\n\n- (void)mouseDownSelectionChange\n{\n\tif (self.backingViewIsLoading) {\n\t\treturn;\n\t}\n\n\t[self.parentView selectionChangeTo:self.itemIndex];\n}\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\tif (self.overlayVisible) {\n\t\t[self mouseDownSelectionChange];\n\n\t\treturn;\n\t}\n\n\t[super mouseDown:theEvent];\n}\n\n- (void)rightMouseDown:(NSEvent *)theEvent\n{\n\tif (self.overlayVisible) {\n\t\t[self mouseDownSelectionChange];\n\n\t\treturn;\n\t}\n\n\t[super rightMouseDown:theEvent];\n}\n\n- (void)otherMouseDown:(NSEvent *)theEvent\n{\n\tif (self.overlayVisible) {\n\t\t[self mouseDownSelectionChange];\n\n\t\treturn;\n\t}\n\n\t[super otherMouseDown:theEvent];\n}\n\n- (nullable NSView *)hitTest:(NSPoint)aPoint\n{\n\tif (NSPointInRect(aPoint, self.frame) == NO) {\n\t\treturn nil;\n\t}\n\n\tif (self.overlayVisible) {\n\t\treturn self.overlayView;\n\t}\n\n\treturn [super hitTest:aPoint];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCMainWindowChannelViewSubviewOverlayView\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\t[self.superview mouseDown:theEvent];\n}\n\n- (void)rightMouseDown:(NSEvent *)theEvent\n{\n\t[self.superview rightMouseDown:theEvent];\n}\n\n- (void)otherMouseDown:(NSEvent *)theEvent\n{\n\t[self.superview otherMouseDown:theEvent];\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tTVCMainWindowChannelViewSubview *subview = (id)self.superview;\n\n\tNSColor *backgroundColor = nil;\n\n\tif (subview.backingViewIsLoading) {\n\t\tbackgroundColor = themeSettings().underlyingWindowColor;\n\t} else {\n\t\tbackgroundColor = themeSettings().channelViewOverlayColor;\n\t}\n\n\tif (backgroundColor == nil) {\n\t\tbackgroundColor = [self defaultBackgroundColor];\n\t}\n\n\t[backgroundColor set];\n\n\t[NSBezierPath fillRect:dirtyRect];\n}\n\n- (NSColor *)defaultBackgroundColor\n{\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tTVCMainWindowAppearance *appearance = mainWindow.userInterfaceObjects;\n\n\tif (appearance == nil) {\n\t\treturn [NSColor blackColor];\n\t}\n\n\tif (mainWindow.isActiveForDrawing) {\n\t\treturn appearance.channelViewOverlayDefaultBackgroundColorActiveWindow;\n\t} else {\n\t\treturn appearance.channelViewOverlayDefaultBackgroundColorInactiveWindow;\n\t}\n}\n\n- (nullable NSView *)hitTest:(NSPoint)aPoint\n{\n\treturn self;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowLoadingScreen.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TVCMainWindowSplitView.h\"\n#import \"TVCMainWindowTextViewPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TVCMainWindowLoadingScreenPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowLoadingScreenView ()\n@property (nonatomic, weak) NSView *visibleView;\n@property (nonatomic, strong) IBOutlet NSView *welcomeAddServerView;\n@property (nonatomic, weak) IBOutlet NSButton *welcomeAddServerViewContinueButton;\n@property (nonatomic, strong) IBOutlet NSView *progressView;\n@property (nonatomic, weak) IBOutlet NSTextField *progressViewDescriptionTextField;\n@property (nonatomic, weak) IBOutlet NSProgressIndicator *progressViewIndicator;\n@property (nonatomic, strong) IBOutlet NSView *trialExpiredView;\n@end\n\n@implementation TVCMainWindowLoadingScreenView\n\n#pragma mark -\n#pragma mark Display View (Public)\n\n- (void)showWelcomeAddServerView\n{\n\t[self displayView:self.welcomeAddServerView];\n}\n\n- (void)showProgressViewWithReason:(NSString *)progressReason\n{\n\tNSParameterAssert(progressReason != nil);\n\n\t[self displayView:self.progressView];\n\n\t[self setProgressViewReason:progressReason];\n\n\t[self.progressViewIndicator startAnimation:nil];\n}\n\n- (void)setProgressViewReason:(NSString *)progressReason\n{\n\tNSParameterAssert(progressReason != nil);\n\n\tself.progressViewDescriptionTextField.stringValue = progressReason;\n}\n\n- (void)showTrialExpiredView\n{\n\t[self displayView:self.trialExpiredView];\n}\n\n#pragma mark -\n\n- (void)hide\n{\n\t[self hideAnimated:NO];\n}\n\n- (void)hideAnimated\n{\n\t[self hideAnimated:YES];\n}\n\n- (void)hideAnimated:(BOOL)animated\n{\n\t[self hideView:self.visibleView animate:animated];\n}\n\n#pragma mark -\n#pragma mark Display View (Private)\n\n- (void)displayView:(NSView *)view\n{\n\tNSParameterAssert(view != nil);\n\n\tif (self.visibleView != nil) {\n\t\t[self.visibleView removeFromSuperview];\n\t}\n\n\tself.visibleView = view;\n\n\t[self disableBackgroundControlsStepOne];\n\n\t[self addSubview:view];\n\n\tNSArray *constraints = @[\n\t/* Center view on both axis. */\n\t [NSLayoutConstraint constraintWithItem:view\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeCenterX\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeCenterX\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t [NSLayoutConstraint constraintWithItem:view\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeCenterY\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationEqual\n\t\t\t\t\t\t\t\t\t toItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeCenterY\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t /* Constrain edges but use >= so that window does not\n\t  shrink to conform to it. */\n\t [NSLayoutConstraint constraintWithItem:view\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeLeft\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationGreaterThanOrEqual\n\t\t\t\t\t\t\t\t\t toItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeLeft\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\n\t [NSLayoutConstraint constraintWithItem:view\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t  relatedBy:NSLayoutRelationGreaterThanOrEqual\n\t\t\t\t\t\t\t\t\t toItem:self\n\t\t\t\t\t\t\t\t  attribute:NSLayoutAttributeTop\n\t\t\t\t\t\t\t\t multiplier:1.0\n\t\t\t\t\t\t\t\t   constant:0.0],\n\t ];\n\n\t[self addConstraints:constraints];\n\n\tself.alphaValue = 1.0;\n\n\tself.hidden = NO;\n\n\t[self displayIfNeeded];\n\n\t[self disableBackgroundControlsStepTwo];\n}\n\n#pragma mark -\n#pragma mark Hide View (Private)\n\n- (void)hideView:(NSView *)view animate:(BOOL)animate\n{\n\t[self enableBackgroundControlsStepOne];\n\n\t/* ================================== */\n\n\tvoid (^phaseTwoBlock)(NSView *) = ^(NSView *viewToHide) {\n\t\t[view removeFromSuperview];\n\n\t\t/* We only continue with phase two if we have not\n\t\t replaced the visible view with a new one. */\n\t\tif (self.visibleView == viewToHide) {\n\t\t\tself.visibleView = nil;\n\n\t\t\tself.hidden = YES;\n\n\t\t\t[self enableBackgroundControlsStepTwo];\n\t\t}\n\t};\n\n\t/* ================================== */\n\n\tif (animate == NO) {\n\t\tself.alphaValue = 0.0;\n\n\t\tphaseTwoBlock(view);\n\n\t\treturn;\n\t}\n\n\t/* ================================== */\n\n\tRZAnimationCurrentContext().duration = 1.0;\n\n\t[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {\n\t\tself.animator.alphaValue = 0.0;\n\t} completionHandler:^{\n\t\tphaseTwoBlock(view);\n\t}];\n}\n\n#pragma mark -\n#pragma mark Private Utilities\n\n- (BOOL)viewIsVisible\n{\n\treturn (self.isHidden == NO);\n}\n\n- (void)disableBackgroundControlsStepOne\n{\n\tself.mainWindow.contentSplitView.hidden = YES;\n}\n\n- (void)disableBackgroundControlsStepTwo\n{\n\tTVCMainWindowTextView *textField = self.mainWindow.inputTextField;\n\n\ttextField.editable = NO;\n\n\ttextField.selectable = NO;\n\n\t[textField updateSegmentedController];\n}\n\n- (void)enableBackgroundControlsStepOne\n{\n\tself.mainWindow.contentSplitView.hidden = NO;\n}\n\n- (void)enableBackgroundControlsStepTwo\n{\n\tTVCMainWindowTextView *textField = self.mainWindow.inputTextField;\n\n\ttextField.editable = YES;\n\n\ttextField.selectable = YES;\n\n\t[textField updateSegmentedController];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowSegmentedControl.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuController.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowLoadingScreen.h\"\n#import \"IRCClient.h\"\n#import \"IRCWorld.h\"\n#import \"TVCMainWindowSegmentedControlPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowSegmentedController ()\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *segmentedControllerLeadingConstraint;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *segmentedControllerWidthConstraint;\n@end\n\n@implementation TVCMainWindowSegmentedController\n\n- (void)segmentedCellClicked:(id)sender\n{\n\tNSInteger selectedSegment = self.selectedSegment;\n\n\tif (selectedSegment == 2) {\n\t\t[menuController() showAddressBook:sender];\n\t}\n}\n\n- (void)updateSegmentedControllerOrigin\n{\n\tif ([TPCPreferences hideMainWindowSegmentedController]) {\n\t\t[self.segmentedControllerLeadingConstraint archiveConstantAndZeroOut];\n\t\t[self.segmentedControllerWidthConstraint archiveConstantAndZeroOut];\n\t} else {\n\t\t[self.segmentedControllerLeadingConstraint restoreArchivedConstant];\n\t\t[self.segmentedControllerWidthConstraint restoreArchivedConstant];\n\t}\n}\n\n- (void)updateSegmentedController\n{\n\tif ([TPCPreferences hideMainWindowSegmentedController]) {\n\t\treturn;\n\t}\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tIRCClient *selectedClient = mainWindow.selectedClient;\n\tIRCChannel *selectedChannel = mainWindow.selectedChannel;\n\n\t/* Enable controller */\n\tself.enabled = (worldController().clientCount > 0 &&\n\t\t\t\tmainWindow.loadingScreen.viewIsVisible == NO);\n\n\t// Cell 0\n\tNSMenu *cell0Menu = menuController().mainWindowSegmentedControllerCellMenu;\n\n\t[self setMenu:cell0Menu forSegment:0];\n\n\t// Cell 1\n\tNSMenuItem *cell1MenuItem = nil;\n\n\tif (selectedChannel == nil) {\n\t\tcell1MenuItem = menuController().mainMenuServerMenuItem;\n\t} else {\n\t\tcell1MenuItem = menuController().mainMenuChannelMenuItem;\n\t}\n\n\t[self setMenu:cell1MenuItem.submenu forSegment:1];\n\n\t// Cell 2\n\t[self setEnabled:(selectedClient.isConnected) forSegment:2];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TVCMainWindowSegmentedControllerCell\n\n- (nullable SEL)action\n{\n\tNSInteger selectedSegment = self.selectedSegment;\n\n\tif ([self menuForSegment:selectedSegment] == nil) {\n\t\treturn super.action;\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowSplitView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCServerList.h\"\n#import \"TVCServerListAppearance.h\"\n#import \"TVCMemberList.h\"\n#import \"TVCMemberListAppearance.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMainWindowSplitViewPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const _userDefaultsKey\t  = @\"Window -> Main Window -> Split Channel View Saved Frames\";\n\n@interface TVCMainWindowSplitView ()\n@property (nonatomic, assign) BOOL restoredPositions;\n@property (nonatomic, assign) BOOL stopFrameUpdatesForServerList;\n@property (nonatomic, assign) BOOL stopFrameUpdatesForMemberList;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *serverListWidthMinConstraint;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *serverListWidthMaxConstraint;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *memberListWidthMinConstraint;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *memberListWidthMaxConstraint;\n@end\n\n@implementation TVCMainWindowSplitView\n\n- (void)applicationAppearanceChanged\n{\n\tTVCMainWindowAppearance *appearance = self.mainWindow.userInterfaceObjects;\n\n\tTVCServerListAppearance *serverList = appearance.serverList;\n\n\tself.serverListWidthMinConstraint.constant = serverList.minimumWidth;\n\tself.serverListWidthMaxConstraint.constant = serverList.maximumWidth;\n\n\tTVCMemberListAppearance *memberList = appearance.memberList;\n\n\tself.memberListWidthMinConstraint.constant = memberList.minimumWidth;\n\tself.memberListWidthMaxConstraint.constant = memberList.maximumWidth;\n}\n\n- (NSColor *)dividerColor\n{\n\tTVCMainWindowAppearance *appearance = self.mainWindow.userInterfaceObjects;\n\n\tNSColor *dividerColor = appearance.splitViewDividerColor;\n\n\tif (appearance.isDarkAppearance) {\n\t\tdividerColor = dividerColor.invertedColor;\n\t}\n\n\treturn dividerColor;\n}\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.delegate = (id)self;\n}\n\n- (void)restorePositions\n{\n\tif (self.restoredPositions) {\n\t\treturn;\n\t}\n\n\t[self expandMemberList];\n\n\t[self expandServerList];\n\n\t// Set after expanding views so that -resizeWithOldSuperviewSize:\n\t// does not save the views' frames prematurely\n\tself.restoredPositions = YES;\n}\n\n- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect ofDividerAtIndex:(NSInteger)dividerIndex\n{\n\tif (dividerIndex == 0) {\n\t\tif (self.serverListCollapsed) {\n\t\t\treturn NSZeroRect;\n\t\t}\n\t} else if (dividerIndex == 1) {\n\t\tif (self.memberListCollapsed) {\n\t\t\treturn NSZeroRect;\n\t\t}\n\t}\n\n\treturn proposedEffectiveRect;\n}\n\n- (void)splitViewDidResizeSubviews:(NSNotification *)notification\n{\n\tif (self.restoredPositions) {\n\t\t[self updateSavedFrames];\n\t}\n}\n\n- (BOOL)allowsVibrancy\n{\n\treturn YES;\n}\n\n- (void)expandServerList\n{\n\tNSScrollView *scrollView = self.mainWindow.serverList.enclosingScrollView;\n\n\tscrollView.hasVerticalScroller = YES;\n\n\tNSView *subview = self.subviews[0];\n\n\tsubview.hidden = NO;\n\n\t[self setPosition:[self positionToRestoreServerListAt] ofDividerAtIndex:0];\n\n\tself.serverListWidthMinConstraint.active = YES;\n\n\tself.stopFrameUpdatesForServerList = NO;\n}\n\n- (void)expandMemberList\n{\n\tNSScrollView *scrollView = self.mainWindow.memberList.enclosingScrollView;\n\n\tscrollView.hasVerticalScroller = YES;\n\n\tNSView *subview = self.subviews[2];\n\n\tsubview.hidden = NO;\n\n\t[self setPosition:[self positionToRestoreMemberListAt] ofDividerAtIndex:1];\n\n\tself.memberListWidthMinConstraint.active = YES;\n\n\tself.stopFrameUpdatesForMemberList = NO;\n}\n\n- (void)collapseServerList\n{\n\tself.stopFrameUpdatesForServerList = YES;\n\n\tself.serverListWidthMinConstraint.active = NO;\n\n\tNSScrollView *scrollView = self.mainWindow.serverList.enclosingScrollView;\n\n\tscrollView.hasVerticalScroller = NO;\n\n\tNSView *subview = self.subviews[0];\n\n\t[self setPosition:0.0 ofDividerAtIndex:0];\n\n\tsubview.hidden = YES;\n}\n\n- (void)collapseMemberList\n{\n\tself.stopFrameUpdatesForMemberList = YES;\n\n\tself.memberListWidthMinConstraint.active = NO;\n\n\tNSView *subview = self.subviews[2];\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tNSScrollView *scrollView = mainWindow.memberList.enclosingScrollView;\n\n\tscrollView.hasVerticalScroller = NO;\n\n\tNSRect windowFrame = mainWindow.frame;\n\n\t[self setPosition:NSWidth(windowFrame) ofDividerAtIndex:1];\n\n\tsubview.hidden = YES;\n}\n\n- (void)toggleServerListVisibility\n{\n\tif (self.serverListCollapsed) {\n\t\t[self expandServerList];\n\t} else {\n\t\t[self collapseServerList];\n\t}\n}\n\n- (void)toggleMemberListVisibility\n{\n\tif (self.memberListCollapsed) {\n\t\t[self expandMemberList];\n\t} else {\n\t\t[self collapseMemberList];\n\t}\n}\n\n- (CGFloat)positionForDividerAtIndex:(NSInteger)index\n{\n\tNSRect subviewFrame = self.subviews[index].frame;\n\n\treturn (NSMaxX(subviewFrame) + (self.dividerThickness * index));\n}\n\n- (CGFloat)positionToRestoreServerListAt\n{\n\tNSDictionary *frames = [self savedFrames];\n\n\tCGFloat position = [frames doubleForKey:@\"serverList\"];\n\n\tTVCServerListAppearance *appearance = self.mainWindow.userInterfaceObjects.serverList;\n\n\tif (position < appearance.minimumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t} else if (position > appearance.maximumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t}\n\n\treturn position;\n}\n\n- (CGFloat)positionToRestoreMemberListAt\n{\n\treturn [self positionToRestoreMemberListAt:YES];\n}\n\n- (CGFloat)positionToRestoreMemberListAt:(BOOL)correctedFrame\n{\n\tNSDictionary *frames = [self savedFrames];\n\n\tCGFloat position = [frames doubleForKey:@\"memberList\"];\n\n\tTVCMemberListAppearance *appearance = self.mainWindow.userInterfaceObjects.memberList;\n\n\tif (position < appearance.minimumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t} else if (position > appearance.maximumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t}\n\n\tif (correctedFrame) {\n\t\tNSRect windowFrame = self.mainWindow.frame;\n\n\t\treturn ((NSWidth(windowFrame) - position) - self.dividerThickness);\n\t}\n\n\treturn position;\n}\n\n- (CGFloat)positionOfServerListForSaving\n{\n\tCGFloat position = [self positionForDividerAtIndex:0];\n\n\tTVCServerListAppearance *appearance = self.mainWindow.userInterfaceObjects.serverList;\n\n\tif (position < appearance.minimumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t} else if (position > appearance.maximumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t}\n\n\treturn position;\n}\n\n- (CGFloat)positionOfMemberListForSaving\n{\n\tCGFloat position = [self positionForDividerAtIndex:1];\n\n\tNSRect windowFrame = self.mainWindow.frame;\n\n\tposition = ((position - NSWidth(windowFrame)) * (-1));\n\n\tTVCMemberListAppearance *appearance = self.mainWindow.userInterfaceObjects.memberList;\n\n\tif (position < appearance.minimumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t} else if (position > appearance.maximumWidth) {\n\t\tposition = appearance.defaultWidth;\n\t}\n\n\treturn position;\n}\n\n- (void)updateSavedFrames\n{\n\tCGFloat serverListPosition = 0;\n\n\tif (self.stopFrameUpdatesForServerList) {\n\t\tserverListPosition = [self positionToRestoreServerListAt];\n\t} else {\n\t\tserverListPosition = [self positionOfServerListForSaving];\n\t}\n\n\tCGFloat memberListPosition = 0;\n\n\tif (self.stopFrameUpdatesForMemberList) {\n\t\tmemberListPosition = [self positionToRestoreMemberListAt:NO];\n\t} else {\n\t\tmemberListPosition = [self positionOfMemberListForSaving];\n\t}\n\n\tNSDictionary *newFrames = @{\n\t\t@\"serverList\" : @(serverListPosition),\n\t\t@\"memberList\" : @(memberListPosition),\n\t};\n\n\t[RZUserDefaults() setObject:newFrames forKey:_userDefaultsKey];\n}\n\n- (nullable NSDictionary<NSString *, NSNumber *> *)savedFrames\n{\n\treturn [RZUserDefaults() objectForKey:_userDefaultsKey];\n}\n\n- (BOOL)isServerListCollapsed\n{\n\treturn [self isSubviewCollapsed:self.subviews[0]];\n}\n\n- (BOOL)isMemberListCollapsed\n{\n\treturn [self isSubviewCollapsed:self.subviews[2]];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowTextView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"IRCColorFormat.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCResourceManagerPrivate.h\"\n#import \"TPCPreferencesLocalPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowSegmentedControlPrivate.h\"\n#import \"TVCTextViewWithIRCFormatterPrivate.h\"\n#import \"TVCMainWindowTextViewAppearancePrivate.h\"\n#import \"TVCMainWindowTextViewPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _KeyObservingArray \t@[\t@\"TextFieldAutomaticSpellCheck\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldAutomaticGrammarCheck\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldAutomaticSpellCorrection\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldSmartCopyPaste\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldSmartQuotes\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldSmartDashes\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldSmartLinks\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldDataDetectors\", \\\n\t\t\t\t\t\t\t\t@\"TextFieldTextReplacement\"]\n\n@interface TVCMainWindowTextView ()\n@property (nonatomic, copy) NSAttributedString *placeholderAttributedString;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *textViewHeightConstraint;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *windowContentViewMinimumHeight;\n@property (nonatomic, weak) IBOutlet TVCMainWindowTextViewBackground *backgroundView;\n@property (nonatomic, weak) IBOutlet TVCMainWindowTextViewContentView *contentView;\n@property (nonatomic, weak) IBOutlet TVCMainWindowSegmentedController *segmentedController;\n@property (nonatomic, weak) IBOutlet TVCMainWindowSegmentedControllerCell *segmentedControllerCell;\n@property (nonatomic, strong) TVCMainWindowTextViewAppearance *userInterfaceObjects;\n@property (readonly) NSArray<NSString *> *defaultSpellingIgnores;\n@end\n\n@interface TVCMainWindowTextViewBackground ()\n@property (nonatomic, unsafe_unretained) IBOutlet TVCMainWindowTextView *textView;\n@end\n\n@interface TVCMainWindowTextViewContentView ()\n@property (nonatomic, unsafe_unretained) IBOutlet TVCMainWindowTextView *textView;\n@property (nonatomic, weak) IBOutlet TVCMainWindowSegmentedController *segmentedController;\n@end\n\n@implementation TVCMainWindowTextView\n\n#pragma mark -\n#pragma mark Drawing\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.backgroundColor = [NSColor clearColor];\n\n\t[self updateTextDirection];\n}\n\n- (void)viewDidMoveToWindow\n{\n\t[super viewDidMoveToWindow];\n\n\tNSWindow *window = self.window;\n\n\tif (window)\n\t{\n\t\tfor (NSString *key in _KeyObservingArray) {\n\t\t\t[RZUserDefaults() addObserver:self forKeyPath:key options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) context:NULL];\n\t\t}\n\t}\n\telse // window\n\t{\n\t\tfor (NSString *key in _KeyObservingArray) {\n\t\t\t[RZUserDefaults() removeObserver:self forKeyPath:key];\n\t\t}\n\t}\n}\n\n- (void)updateVibrancyWithAppearance:(TVCMainWindowTextViewAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tself.backgroundView.needsDisplay = YES;\n\n\tself.contentView.needsDisplay = YES;\n}\n\n- (void)applicationAppearanceChanged\n{\n\tTVCMainWindowTextViewAppearance *appearance = self.mainWindow.userInterfaceObjects.textView;\n\n\t[self _updateAppearance:appearance];\n}\n\n/*\n- (void)systemAppearanceChanged\n{\n\n}\n*/\n\n- (void)_updateAppearance:(TVCMainWindowTextViewAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tself.userInterfaceObjects = appearance;\n\n\t[self updateVibrancyWithAppearance:appearance];\n\n\tself.textContainerInset = appearance.textViewInset;\n\n\tself.preferredFontColor = appearance.textViewTextColor;\n\n\t[self reloadOriginPoints];\n\n\t[self updateTextBoxCachedPreferredFontSize];\n\n\t[self resetTypeSetterAttributes];\n\n\t[self updateAllFontColorsToMatchTheDefaultFont];\n}\n\n#pragma mark -\n#pragma mark Segmented Controller\n\n- (void)reloadOriginPointsAndRecalculateSize\n{\n\t[self reloadOriginPoints];\n\n\t/* Reload size on next go around to allow constraint layout to occur before so */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self recalculateTextViewSizeForced];\n\t});\n}\n\n- (void)reloadOriginPoints\n{\n\t[self.segmentedController updateSegmentedControllerOrigin];\n}\n\n- (void)updateSegmentedController\n{\n\t[self.segmentedController updateSegmentedController];\n}\n\n#pragma mark -\n#pragma mark Spelling\n\n- (void)resetSpellingIgnores\n{\n\t/* When performing nickname completion, completions are\n\t added to the ignore list. The main window then resets\n\t the entire spelling ignore list, by calling this method\n\t when the selection changes. */\n\t/* Because the main window will eventually call this for us,\n\t we allow it to happen lazily, instead of in awake from nib. */\n\t[RZSpellChecker() setIgnoredWords:self.defaultSpellingIgnores inSpellDocumentWithTag:self.spellCheckerDocumentTag];\n}\n\n- (NSArray<NSString *> *)defaultSpellingIgnores\n{\n\treturn [TPCResourceManager arrayFromResources:@\"StaticStore\" key:@\"Spelling Ignores\"];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)updateAllFontColorsToMatchTheDefaultFont\n{\n\t[self.textStorage beginEditing];\n\n\t[self.textStorage enumerateAttributesInRange:self.range\n\t\t\t\t\t\t\t\t\t\t options:0\n\t\t\t\t\t\t\t\t\t  usingBlock:^(NSDictionary *attributes, NSRange effectiveRange, BOOL *stop)\n\t\t{\n\t\t\tif ([attributes containsKey:IRCTextFormatterForegroundColorAttributeName]) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t[self resetFontColorInRange:effectiveRange];\n\t\t}];\n\n\t[self.textStorage endEditing];\n}\n\n- (void)setAttributedStringValue:(NSAttributedString *)attributedStringValue\n{\n\tsuper.attributedStringValue = attributedStringValue;\n\n\t[self updateAllFontColorsToMatchTheDefaultFont];\n}\n\n- (void)updateTextDirection\n{\n\tif ([TPCPreferences rightToLeftFormatting]) {\n\t\tself.baseWritingDirection = NSWritingDirectionRightToLeft;\n\t} else {\n\t\tself.baseWritingDirection = NSWritingDirectionLeftToRight;\n\t}\n}\n\n- (void)textDidChange:(NSNotification *)aNotification\n{\n\t[super textDidChange:aNotification];\n\n\t[self recalculateTextViewSize];\n}\n\n- (void)paste:(nullable id)sender\n{\n\t[super paste:self];\n\n\t[self recalculateTextViewSize];\n}\n\n- (BOOL)textView:(NSTextView *)aTextView doCommandBySelector:(SEL)aSelector\n{\n\tif (aSelector == @selector(insertNewline:)) {\n\t\t[self.mainWindow textEntered];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Multi-line Text Box Drawing\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\t/* The place holder string is not drawn for right to left users */\n\tif (self.stringLength > 0 || self.baseWritingDirection != NSWritingDirectionLeftToRight) {\n\t\t[super drawRect:dirtyRect];\n\n\t\treturn;\n\t}\n\n\t// TODO: Don't used fix positions\n\tNSRect selectedRect = self.selectedRect;\n\n\tTVCMainWindowTextViewFontSize preferredFontSize = self.userInterfaceObjects.textViewPreferredFontSize;\n\n\tif (preferredFontSize == TVCMainWindowTextViewFontSizeNormal ||\n\t\tpreferredFontSize == TVCMainWindowTextViewFontSizeLarge)\n\t{\n\t\tselectedRect.origin.y -= 1;\n\t}\n\n\t[self.placeholderAttributedString drawAtPoint:selectedRect.origin];\n}\n\n- (void)updateTextBoxCachedPreferredFontSize\n{\n\t/* Update font */\n\tTVCMainWindowTextViewAppearance *appearance = self.userInterfaceObjects;\n\n\tif ([appearance preferredTextViewFontChanged] == NO) {\n\t\treturn;\n\t}\n\n\tNSFont *preferredFont = appearance.textViewPreferredFont;\n\n\tself.preferredFont = preferredFont;\n\n\t/* Update the placeholder string */\n\tNSColor *placeholderTextColor = appearance.textViewPlaceholderTextColor;\n\n\tNSDictionary *placeholderStringAttributes = @{\n\t\tNSFontAttributeName\t: preferredFont,\n\t\tNSForegroundColorAttributeName : placeholderTextColor\n\t};\n\n\tself.placeholderAttributedString =\n\t[NSAttributedString attributedStringWithString:TXTLS(@\"TVCMainWindow[8r3-ih]\") attributes:placeholderStringAttributes];\n\n\tself.needsDisplay = YES;\n}\n\n- (void)updateTextBasedOnPreferredFontSize\n{\n\tTVCMainWindowTextViewAppearance *appearance = self.userInterfaceObjects;\n\n\tTVCMainWindowTextViewFontSize preferredFontSize = appearance.textViewPreferredFontSize;\n\n\t[self updateTextBoxCachedPreferredFontSize];\n\n\tif (appearance.textViewPreferredFontSize != preferredFontSize) {\n\t\t[self updateAllFontSizesToMatchTheDefaultFont];\n\t}\n\n\t[self recalculateTextViewSizeForced];\n}\n\n- (CGFloat)defaultLineHeight\n{\n\treturn [self.layoutManager defaultLineHeightForFont:self.preferredFont];\n}\n\n- (void)recalculateTextViewSize\n{\n\t[self recalculateTextViewSizeForced:NO];\n}\n\n- (void)recalculateTextViewSizeForced\n{\n\t[self recalculateTextViewSizeForced:YES];\n}\n\n- (void)recalculateTextViewSizeForced:(BOOL)forceRecalculate\n{\n\tTVCMainWindowTextViewAppearance *appearance = self.userInterfaceObjects;\n\n\tNSWindow *window = self.window;\n\n\tNSRect windowFrame = window.frame;\n\n\tCGFloat contentBorderPadding = appearance.backgroundViewContentBorderPadding;\n\n\tCGFloat backgroundHeight = 0;\n\n\tCGFloat backgroundHeightDefault = [self defaultLineHeight];\n\n\tif (self.stringLength < 1) {\n\t\tbackgroundHeight = (backgroundHeightDefault + contentBorderPadding);\n\t} else {\n\t\tCGFloat backgroundHeightMaximum = (NSHeight(windowFrame) - (self.windowContentViewMinimumHeight.constant + contentBorderPadding));\n\n\t\tbackgroundHeight = [self highestHeightBelowHeight:backgroundHeightMaximum withPadding:contentBorderPadding];\n\n\t\tif ((backgroundHeight - contentBorderPadding) < backgroundHeightDefault) {\n\t\t\tbackgroundHeight = (backgroundHeightDefault + contentBorderPadding);\n\t\t}\n\t}\n\n\tself.textViewHeightConstraint.constant = backgroundHeight;\n\n\tid scrollViewContentView = self.enclosingScrollView.contentView;\n\n\tNSRect contentViewBounds = [scrollViewContentView bounds];\n\n\tif (contentViewBounds.origin.x > 0) {\n\t\tcontentViewBounds.origin.x = 0;\n\n\t\t[scrollViewContentView scrollToPoint:contentViewBounds.origin];\n\t}\n}\n\n#pragma mark -\n#pragma mark NSTextView Context Menu Preferences\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:@\"TextFieldAutomaticSpellCheck\"]) {\n\t\tself.continuousSpellCheckingEnabled = [TPCPreferences textFieldAutomaticSpellCheck];\n\t} else if ([keyPath isEqualToString:@\"TextFieldAutomaticGrammarCheck\"]) {\n\t\tself.grammarCheckingEnabled = [TPCPreferences textFieldAutomaticGrammarCheck];\n\t} else if ([keyPath isEqualToString:@\"TextFieldAutomaticSpellCorrection\"]) {\n\t\tself.automaticSpellingCorrectionEnabled = [TPCPreferences textFieldAutomaticSpellCorrection];\n\t} else if ([keyPath isEqualToString:@\"TextFieldSmartCopyPaste\"]) {\n\t\tself.smartInsertDeleteEnabled = [TPCPreferences textFieldSmartCopyPaste];\n\t} else if ([keyPath isEqualToString:@\"TextFieldSmartQuotes\"]) {\n\t\tself.automaticQuoteSubstitutionEnabled = [TPCPreferences textFieldSmartQuotes];\n\t} else if ([keyPath isEqualToString:@\"TextFieldSmartDashes\"]) {\n\t\tself.automaticDashSubstitutionEnabled = [TPCPreferences textFieldSmartDashes];\n\t} else if ([keyPath isEqualToString:@\"TextFieldSmartLinks\"]) {\n\t\tself.automaticLinkDetectionEnabled = [TPCPreferences textFieldSmartLinks];\n\t} else if ([keyPath isEqualToString:@\"TextFieldDataDetectors\"]) {\n\t\tself.automaticDataDetectionEnabled = [TPCPreferences textFieldDataDetectors];\n\t} else if ([keyPath isEqualToString:@\"TextFieldTextReplacement\"]) {\n\t\tself.automaticTextReplacementEnabled = [TPCPreferences textFieldTextReplacement];\n\t} else if ([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]) {\n\t\t[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];\n\t}\n}\n\n- (void)setContinuousSpellCheckingEnabled:(BOOL)continuousSpellCheckingEnabled\n{\n\t[TPCPreferences setTextFieldAutomaticSpellCheck:continuousSpellCheckingEnabled];\n\n\tsuper.continuousSpellCheckingEnabled = continuousSpellCheckingEnabled;\n}\n\n- (void)setGrammarCheckingEnabled:(BOOL)grammarCheckingEnabled\n{\n\t[TPCPreferences setTextFieldAutomaticGrammarCheck:grammarCheckingEnabled];\n\n\tsuper.grammarCheckingEnabled = grammarCheckingEnabled;\n}\n\n- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)automaticSpellingCorrectionEnabled\n{\n\t[TPCPreferences setTextFieldAutomaticSpellCorrection:automaticSpellingCorrectionEnabled];\n\n\tsuper.automaticSpellingCorrectionEnabled = automaticSpellingCorrectionEnabled;\n}\n\n- (void)setSmartInsertDeleteEnabled:(BOOL)smartInsertDeleteEnabled\n{\n\t[TPCPreferences setTextFieldSmartCopyPaste:smartInsertDeleteEnabled];\n\n\tsuper.smartInsertDeleteEnabled = smartInsertDeleteEnabled;\n}\n\n- (void)setAutomaticQuoteSubstitutionEnabled:(BOOL)automaticQuoteSubstitutionEnabled\n{\n\t[TPCPreferences setTextFieldSmartQuotes:automaticQuoteSubstitutionEnabled];\n\n\tsuper.automaticQuoteSubstitutionEnabled = automaticQuoteSubstitutionEnabled;\n}\n\n- (void)setAutomaticDashSubstitutionEnabled:(BOOL)automaticDashSubstitutionEnabled\n{\n\t[TPCPreferences setTextFieldSmartDashes:automaticDashSubstitutionEnabled];\n\n\tsuper.automaticDashSubstitutionEnabled = automaticDashSubstitutionEnabled;\n}\n\n- (void)setAutomaticLinkDetectionEnabled:(BOOL)automaticLinkDetectionEnabled\n{\n\t[TPCPreferences setTextFieldSmartLinks:automaticLinkDetectionEnabled];\n\n\tsuper.automaticLinkDetectionEnabled = automaticLinkDetectionEnabled;\n}\n\n- (void)setAutomaticDataDetectionEnabled:(BOOL)automaticDataDetectionEnabled\n{\n\t[TPCPreferences setTextFieldDataDetectors:automaticDataDetectionEnabled];\n\n\tsuper.automaticDataDetectionEnabled = automaticDataDetectionEnabled;\n}\n\n- (void)setAutomaticTextReplacementEnabled:(BOOL)automaticTextReplacementEnabled\n{\n\t[TPCPreferences setTextFieldTextReplacement:automaticTextReplacementEnabled];\n\n\tsuper.automaticTextReplacementEnabled = automaticTextReplacementEnabled;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Background Drawing\n\n@implementation TVCMainWindowTextViewBackground\n\n- (void)drawControllerForWithAppearance:(TVCMainWindowTextViewAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tif (appearance.isDarkAppearance == NO) {\n\t\t[self drawLightControllerForWithAppearance:appearance];\n\t} else {\n\t\t[self drawDarkControllerForWithAppearance:appearance];\n\t}\n}\n\n- (void)drawDarkControllerForWithAppearance:(TVCMainWindowTextViewAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tBOOL isWindowActive = self.mainWindow.activeForDrawing;\n\n\tNSRect cellBounds = self.frame;\n\n\tNSRect controlFrame = NSMakeRect(0.0, 1.0,   cellBounds.size.width,\n\t\t\t\t\t\t\t\t\t\t\t\t(cellBounds.size.height - 2.0));\n\n\t/* Inner background color */\n\tNSColor *backgroundColor = nil;\n\n\tif (isWindowActive) {\n\t\tbackgroundColor = appearance.textViewBackgroundColorActiveWindow;\n\t} else {\n\t\tbackgroundColor = appearance.textViewBackgroundColorInactiveWindow;\n\t} // isWindowActive\n\n\t/* Shadow colors */\n\tNSShadow *outsideShadow = [NSShadow new];\n\n\toutsideShadow.shadowBlurRadius = 0.0;\n\toutsideShadow.shadowOffset = NSMakeSize(0.0, (-1.0));\n\n\tif (isWindowActive) {\n\t\toutsideShadow.shadowColor = appearance.textViewOutsidePrimaryShadowColorActiveWindow;\n\t} else {\n\t\toutsideShadow.shadowColor = appearance.textViewOutsidePrimaryShadowColorInactiveWindow;\n\t} // isWindowActive\n\n\t/* Rectangle drawing */\n\tNSBezierPath *rectanglePath = [NSBezierPath bezierPathWithRoundedRect:controlFrame xRadius:3.0 yRadius:3.0];\n\n\t[NSGraphicsContext saveGraphicsState];\n\n\t[outsideShadow set];\n\n\t[backgroundColor setFill];\n\n\t[rectanglePath fill];\n\n\t[NSGraphicsContext restoreGraphicsState];\n}\n\n- (void)drawLightControllerForWithAppearance:(TVCMainWindowTextViewAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\t/* To be honest, I don't remember what any of this does. */\n\n\tBOOL isWindowActive = self.mainWindow.activeForDrawing;\n\n\tNSRect cellBounds = self.frame;\n\n\tNSRect controlFrame = NSMakeRect(0.0, 1.0,   cellBounds.size.width,\n\t\t\t\t\t\t\t\t\t\t\t\t(cellBounds.size.height - 2.0));\n\n\tCGContextRef context = RZGraphicsCurrentContext().CGContext;\n\n\t/* Inner gradient color */\n\tNSGradient *insideGradient = nil;\n\n\tif (isWindowActive) {\n\t\tinsideGradient = appearance.textViewInsideGradientActiveWindow;\n\t} else {\n\t\tinsideGradient = appearance.textViewInsideGradientInactiveWindow;\n\t} // isWindowActive\n\n\t/* Inside shadow */\n\tNSShadow *insideShadow = [NSShadow new];\n\n\tinsideShadow.shadowBlurRadius = 0.0;\n\tinsideShadow.shadowOffset = NSMakeSize(0.0, (-1.0));\n\n\tNSColor *insideShadowColor = nil;\n\n\tif (isWindowActive) {\n\t\tinsideShadowColor = appearance.textViewInsideShadowColorActiveWindow;\n\t} else {\n\t\tinsideShadowColor = appearance.textViewInsideShadowColorInactiveWindow;\n\t}\n\n\tinsideShadow.shadowColor = insideShadowColor;\n\n\t/* Outside shadow */\n\tNSShadow *outsideShadow = [NSShadow new];\n\n\tif (appearance.isHighResolutionAppearance == NO) {\n\t\toutsideShadow.shadowBlurRadius = 0.0;\n\t\toutsideShadow.shadowOffset = NSMakeSize(0.0, (-1.0));\n\t} else {\n\t\toutsideShadow.shadowBlurRadius = 0.0;\n\t\toutsideShadow.shadowOffset = NSMakeSize(0.0, (-0.5));\n\t} // high resolution\n\n\tif (isWindowActive) {\n\t\toutsideShadow.shadowColor = appearance.textViewOutsidePrimaryShadowColorActiveWindow;\n\t} else {\n\t\toutsideShadow.shadowColor = appearance.textViewOutsidePrimaryShadowColorInactiveWindow;\n\t} // isWindowActive\n\n\t/* Rectangle drawing */\n\tNSBezierPath *rectanglePath = [NSBezierPath bezierPathWithRoundedRect:controlFrame xRadius:3.0 yRadius:3.0];\n\n\t[outsideShadow set];\n\n\tCGContextBeginTransparencyLayer(context, NULL);\n\n\t[insideGradient drawInBezierPath:rectanglePath angle:(-90)];\n\n\tCGContextEndTransparencyLayer(context);\n\n\t/* Prepare drawing for inside shadow */\n\tCGContextSetShadowWithColor(context, CGSizeZero, 0, NULL);\n\n\tCGContextSetAlpha(context, insideShadowColor.alphaComponent);\n\n\tCGContextBeginTransparencyLayer(context, NULL);\n\n\t{\n\t\t/* Inside shadow drawing */\n\t\t[insideShadow set];\n\n\t\tCGContextSetBlendMode(context, kCGBlendModeSourceOut);\n\n\t\tCGContextBeginTransparencyLayer(context, NULL);\n\n\t\t/* Fill shadow */\n\t\t[insideShadowColor setFill];\n\n\t\t[rectanglePath fill];\n\n\t\t/* Complete drawing */\n\t\tCGContextEndTransparencyLayer(context);\n\t}\n\n\tCGContextEndTransparencyLayer(context);\n\n\t/* On retina, we fake a second shadow under the bottommost one */\n\tif (appearance.isHighResolutionAppearance) {\n\t\tNSColor *controlColor = nil;\n\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.textViewOutsideSecondaryShadowColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.textViewOutsideSecondaryShadowColorInactiveWindow;\n\t\t} // isWindowActive\n\n\t\t[controlColor setStroke];\n\n\t\tNSPoint linePoint1 = NSMakePoint(2.0, 0.0);\n\t\tNSPoint linePoint2 = NSMakePoint((cellBounds.size.width - 2.0), 0.0);\n\n\t\t[NSBezierPath strokeLineFromPoint:linePoint1 toPoint:linePoint2];\n\t} // high resolution\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tTVCMainWindowTextViewAppearance *appearance = self.textView.userInterfaceObjects;\n\n\tif (appearance == nil) {\n\t\treturn;\n\t}\n\n\t[self drawControllerForWithAppearance:appearance];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Text Field Background Vibrant View\n\n@implementation TVCMainWindowTextViewContentView\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tTVCMainWindowTextViewAppearance *appearance = self.textView.userInterfaceObjects;\n\n\tif (appearance == nil) {\n\t\treturn;\n\t}\n\n\t/* Draw background color */\n\tNSColor *backgroundColor = appearance.backgroundViewBackgroundColor;\n\n\t[backgroundColor set];\n\n\tNSRectFill(dirtyRect);\n\n\t/* Draw divider */\n\tNSRect contentViewFrame = self.frame;\n\n\tcontentViewFrame.origin.x = 0.0;\n\tcontentViewFrame.origin.y = (NSMaxY(contentViewFrame) - 1.0);\n\n\tcontentViewFrame.size.height = 1.0;\n\n\tNSBezierPath *dividerPath = [NSBezierPath bezierPathWithRect:contentViewFrame];\n\n\tNSColor *dividerColor = appearance.backgroundViewDividerColor;\n\n\t[dividerColor set];\n\n\t[dividerPath fill];\n}\n\n- (BOOL)allowsVibrancy\n{\n\treturn NO;\n}\n\n- (BOOL)isOpaque\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowTextViewAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCAppearancePrivate.h\"\n#import \"TVCMainWindowTextViewAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMainWindowTextViewAppearance ()\n#pragma mark -\n#pragma mark Text View\n\n@property (nonatomic, assign, readwrite) NSSize textViewInset;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewPlaceholderTextColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutlineColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutlineColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewInsideShadowColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewInsideShadowColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSGradient *textViewInsideGradientActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSGradient *textViewInsideGradientInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutsidePrimaryShadowColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutsidePrimaryShadowColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutsideSecondaryShadowColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *textViewOutsideSecondaryShadowColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *textViewFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *textViewFontLarge;\n@property (nonatomic, copy, nullable, readwrite) NSFont *textViewFontExtraLarge;\n@property (nonatomic, copy, nullable, readwrite) NSFont *textViewFontHumongous;\n\n@property (nonatomic, assign, readwrite) TVCMainWindowTextViewFontSize textViewPreferredFontSize;\n\n#pragma mark -\n#pragma mark Background View\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *backgroundViewBackgroundColor;\n@property (nonatomic, copy, nullable, readwrite) NSColor *backgroundViewDividerColor;\n@property (nonatomic, assign, readwrite) CGFloat backgroundViewContentBorderPadding;\n@end\n\n@implementation TVCMainWindowTextViewAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (nullable instancetype)initWithWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(mainWindow != nil);\n\n\tNSURL *appearanceLocation = [self.class appearanceLocation];\n\n\tBOOL forRetinaDisplay = mainWindow.runningInHighResolutionMode;\n\n\tif ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (NSURL *)appearanceLocation\n{\n\treturn [RZMainBundle() URLForResource:@\"TVCMainWindowTextViewAppearance\" withExtension:@\"plist\"];\n}\n\n- (void)prepareInitialState\n{\n\tNSDictionary *properties = self.appearanceProperties;\n\n\tNSDictionary *textView = properties[@\"Text View\"];\n\n\tself.textViewInset = [self sizeInGroup:textView withKey:@\"inset\"];\n\tself.textViewTextColor = [self colorInGroup:textView withKey:@\"normalTextColor\"];\n\tself.textViewPlaceholderTextColor = [self colorInGroup:textView withKey:@\"placeholderTextColor\"];\n\tself.textViewBackgroundColorActiveWindow = [self colorInGroup:textView withKey:@\"backgroundColor\" forActiveWindow:YES];\n\tself.textViewBackgroundColorInactiveWindow = [self colorInGroup:textView withKey:@\"backgroundColor\" forActiveWindow:NO];\n\tself.textViewOutlineColorActiveWindow = [self colorInGroup:textView withKey:@\"outlineColor\" forActiveWindow:YES];\n\tself.textViewOutlineColorInactiveWindow = [self colorInGroup:textView withKey:@\"outlineColor\" forActiveWindow:NO];\n\tself.textViewInsideShadowColorActiveWindow = [self colorInGroup:textView withKey:@\"insideShadowColor\" forActiveWindow:YES];\n\tself.textViewInsideShadowColorInactiveWindow = [self colorInGroup:textView withKey:@\"insideShadowColor\" forActiveWindow:NO];\n\tself.textViewInsideGradientActiveWindow = [self gradientInGroup:textView withKey:@\"insideGradient\" forActiveWindow:YES];\n\tself.textViewInsideGradientInactiveWindow = [self gradientInGroup:textView withKey:@\"insideGradient\" forActiveWindow:NO];\n\tself.textViewOutsidePrimaryShadowColorActiveWindow = [self colorInGroup:textView withKey:@\"outsidePrimaryShadowColor\" forActiveWindow:YES];\n\tself.textViewOutsidePrimaryShadowColorInactiveWindow = [self colorInGroup:textView withKey:@\"outsidePrimaryShadowColor\" forActiveWindow:NO];\n\tself.textViewOutsideSecondaryShadowColorActiveWindow = [self colorInGroup:textView withKey:@\"outsideSecondaryShadowColor\" forActiveWindow:YES];\n\tself.textViewOutsideSecondaryShadowColorInactiveWindow = [self colorInGroup:textView withKey:@\"outsideSecondaryShadowColor\" forActiveWindow:NO];\n\tself.textViewFont = [self fontInGroup:textView withKey:@\"font\"];\n\tself.textViewFontLarge = [self fontInGroup:textView withKey:@\"fontLarge\"];\n\tself.textViewFontExtraLarge = [self fontInGroup:textView withKey:@\"fontExtraLarge\"];\n\tself.textViewFontHumongous = [self fontInGroup:textView withKey:@\"fontHumongous\"];\n\n\tNSDictionary *backgroundView = properties[@\"Background View\"];\n\n\tself.backgroundViewBackgroundColor = [self colorInGroup:backgroundView withKey:@\"backgroundColor\"];\n\tself.backgroundViewDividerColor = [self colorInGroup:backgroundView withKey:@\"dividerColor\"];\n\tself.backgroundViewContentBorderPadding = [self measurementInGroup:backgroundView withKey:@\"contentBorderPadding\"];\n\n\t[self flushAppearanceProperties];\n}\n\n#pragma mark -\n#pragma mark Everything Else\n\n- (BOOL)preferredTextViewFontChanged\n{\n\treturn (self.textViewPreferredFontSize != [TPCPreferences mainTextViewFontSize]);\n}\n\n- (nullable NSFont *)textViewPreferredFont\n{\n\tTVCMainWindowTextViewFontSize preferredFontSize = [TPCPreferences mainTextViewFontSize];\n\n\tself.textViewPreferredFontSize = preferredFontSize;\n\n\tNSFont *preferredFont = nil;\n\n\tif (preferredFontSize == TVCMainWindowTextViewFontSizeNormal) {\n\t\tpreferredFont = self.textViewFont;\n\t} else if (preferredFontSize == TVCMainWindowTextViewFontSizeLarge) {\n\t\tpreferredFont = self.textViewFontLarge;\n\t} else if (preferredFontSize == TVCMainWindowTextViewFontSizeExtraLarge) {\n\t\tpreferredFont = self.textViewFontExtraLarge;\n\t} else if (preferredFontSize == TVCMainWindowTextViewFontSizeHumongous) {\n\t\tpreferredFont = self.textViewFontHumongous;\n\t}\n\n\treturn preferredFont;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Main Window/TVCMainWindowTitlebarAccessoryView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMainWindowAppearance.h\"\n#import \"TVCMainWindowTitlebarAccessoryViewPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TVCMainWindowTitlebarAccessoryView\n@end\n\n@implementation TVCMainWindowTitlebarAccessoryViewController\n@end\n\n@interface TVCMainWindowTitlebarAccessoryViewLockButton ()\n@property (nonatomic, assign) BOOL drawsCustomBackgroundColor;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *lockButtonLeftMarginConstraint;\n@property (nonatomic, weak) IBOutlet NSLayoutConstraint *lockButtonRightMarginConstraint;\n\n/* Accessory views are wrapped around an NSToolbarFullScreenWindow object\n when in full screen. That means the view cannot use the helper property\n in NSView named -mainWindow which wraps around -window. Instead, we have\n to be explicit and use a reference. */\n\n@property (nonatomic, weak) IBOutlet TVCMainWindow *mainWindowRef;\n@end\n\n@implementation TVCMainWindowTitlebarAccessoryViewLockButton\n\n- (void)sizeToFit\n{\n\t[super sizeToFit];\n\n\t/* NSTitlebarAccessoryViewController is not very friendly when it comes\n\t to allowing us to specify an NSLayoutConstraint based width for our view\n\t and updating the width of its clip view based on changes to that. Lucky\n\t for us NSTitlebarAccessoryViewController at least monitors the frame\n\t value for its associated view which means if we manually specify the \n\t width in its frame, then we can at least force a resize then. */\n\tCGFloat buttonWidth = NSWidth(self.frame);\n\n\tCGFloat buttonLeftMargin = self.lockButtonLeftMarginConstraint.constant;\n\tCGFloat buttonRightMargin = self.lockButtonRightMarginConstraint.constant;\n\n\tCGFloat totalViewWidth = (buttonLeftMargin + buttonWidth + buttonRightMargin);\n\n\tNSRect superviewFrame = self.superview.frame;\n\n\tsuperviewFrame.size.width = totalViewWidth;\n\n\tself.superview.frame = superviewFrame;\n\n\treturn;\n}\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\t[self disableDrawingCustomBackgroundColor];\n}\n\n- (void)positionImageOverContent\n{\n\t[self.cell setImagePosition:NSImageOverlaps];\n}\n\n- (void)positionImageOnLeftSide\n{\n\t[self.cell setImagePosition:NSImageLeft];\n}\n\n- (void)setIconAsLocked\n{\n\tNSImage *iconImage = [NSImage imageNamed:@\"NSLockLockedTemplate\"];\n\n\tself.image = iconImage;\n}\n\n- (void)setIconAsUnlocked\n{\n\tNSImage *iconImage = [NSImage imageNamed:@\"NSLockUnlockedTemplate\"];\n\n\tself.image = iconImage;\n}\n\n- (void)disableDrawingCustomBackgroundColor\n{\n\tself.cell.backgroundStyle = NSBackgroundStyleRaised;\n\n\tself.drawsCustomBackgroundColor = NO;\n}\n\n- (void)enableDrawingCustomBackgroundColor\n{\n\tself.cell.backgroundStyle = NSBackgroundStyleLowered;\n\n\tself.drawsCustomBackgroundColor = YES;\n}\n\n- (void)drawRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tif (self.drawsCustomBackgroundColor) {\n\t\t[self drawInterior];\n\t}\n\n\t[super drawRect:dirtyRect];\n}\n\n- (void)drawInterior\n{\n\tif (self.mainWindow.isActiveForDrawing == NO) {\n\t\treturn;\n\t}\n\n\tTVCMainWindowAppearance *appearance = self.mainWindowRef.userInterfaceObjects;\n\n\tif (appearance == nil) {\n\t\treturn;\n\t}\n\n\t[self drawInteriorForActiveWindowWithAppearance:appearance];\n}\n\n- (void)drawInteriorForActiveWindowWithAppearance:(TVCMainWindowAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\t/* We get the bounds of the object and tweak it just slightly to match what it\n\t actually is. After that, we draw our color in behind it to fake the background. */\n\tNSRect controllerFrame = self.bounds;\n\n\tcontrollerFrame.size.height -= 1.0;\n\n\tNSColor *controllerBackgroundColor = appearance.titlebarAccessoryViewBackgroundColorActiveWindow;\n\n\tNSBezierPath *drawingPath = [NSBezierPath bezierPathWithRoundedRect:controllerFrame xRadius:4.0 yRadius:4.0];\n\n\t[controllerBackgroundColor set];\n\n\t[drawingPath fill];\n}\n\n- (void)applicationAppearanceChanged\n{\n\tTVCMainWindowAppearance *appearance = self.mainWindowRef.userInterfaceObjects;\n\n\t[self _updateAppearance:appearance];\n}\n\n- (void)_updateAppearance:(TVCMainWindowAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tself.lockButtonLeftMarginConstraint.constant = appearance.titlebarAccessoryViewLeftMargin;\n\tself.lockButtonRightMarginConstraint.constant = appearance.titlebarAccessoryViewRightMargin;\n\n\t[self sizeToFit];\n\n\tself.needsDisplay = YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Preferences/TVCNotificationConfigurationViewController.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n#import \"TLONotificationConfigurationPrivate.h\"\n#import \"TLOSoundPlayer.h\"\n#import \"TVCNotificationConfigurationViewControllerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _alertSoundsDefaultSoundIndex\t\t\t0\n#define _alertSoundsNoSoundIndex\t\t\t\t2\n\n@interface TVCNotificationConfigurationViewController ()\n@property (nonatomic, weak) NSView *attachedView;\n@property (nonatomic, strong) IBOutlet NSView *contentView;\n@property (nonatomic, weak) IBOutlet NSButton *alertBounceDockIconButton;\n@property (nonatomic, weak) IBOutlet NSButton *alertBounceDockIconRepeatedlyButton;\n@property (nonatomic, weak) IBOutlet NSButton *alertDisableWhileAwayButton;\n@property (nonatomic, weak) IBOutlet NSButton *alertPushNotificationButton;\n@property (nonatomic, weak) IBOutlet NSButton *alertSpeakEventButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *alertSoundChoiceButton;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *alertTypeChoiceButton;\n@property (nonatomic, weak) IBOutlet NSTextField *alertNotificationDestinationTextField;\n@property (nonatomic, strong) TLONotificationConfiguration *activeAlert;\n@property (nonatomic, assign) BOOL activeAlertPropertyChangedByUser;\n@property (nonatomic, copy) NSArray *alertSounds;\n\n- (IBAction)onChangedAlertBounceDockIcon:(id)sender;\n- (IBAction)onChangedAlertBounceDockIconRepeatedly:(id)sender;\n- (IBAction)onChangedAlertDisableWhileAway:(id)sender;\n- (IBAction)onChangedAlertPushNotification:(id)sender;\n- (IBAction)onChangedAlertSound:(id)sender;\n- (IBAction)onChangedAlertSpoken:(id)sender;\n- (IBAction)onChangedAlertType:(id)sender;\n@end\n\n@implementation TVCNotificationConfigurationViewController\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self stopObservingActiveAlert];\n}\n\n- (void)prepareInitialState\n{\n\t[RZMainBundle() loadNibNamed:@\"TVCNotificationConfigurationView\" owner:self topLevelObjects:nil];\n\n\t[self updateAvailableSounds];\n\n\tself.alertNotificationDestinationTextField.stringValue = TXTLS(@\"TVCNotificationConfigurationView[br6-di]\");\n}\n\n- (void)attachToView:(NSView *)view\n{\n\tNSParameterAssert(view != nil);\n\n\tif (self.attachedView == nil) {\n\t\tself.attachedView = view;\n\t} else {\n\t\tNSAssert(NO, @\"View is already attached to a view\");\n\t}\n\n\tNSView *contentView = self.contentView;\n\n\t[view addSubview:contentView];\n\n\t[view addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"H:|-0-[contentView]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(contentView)]];\n\n\t[view addConstraints:\n\t [NSLayoutConstraint constraintsWithVisualFormat:@\"V:|-0-[contentView]-0-|\"\n\t\t\t\t\t\t\t\t\t\t\t options:NSLayoutFormatDirectionLeadingToTrailing\n\t\t\t\t\t\t\t\t\t\t\t metrics:nil\n\t\t\t\t\t\t\t\t\t\t\t   views:NSDictionaryOfVariableBindings(contentView)]];\n}\n\n- (void)setAllowsMixedState:(BOOL)allowsMixedState\n{\n\tif (self->_allowsMixedState != allowsMixedState) {\n\t\tself->_allowsMixedState = allowsMixedState;\n\n\t\t[self updateMixedState];\n\t}\n}\n\n- (void)updateMixedState\n{\n\tBOOL allowsMixedState = self.allowsMixedState;\n\n\tself.alertSpeakEventButton.allowsMixedState = allowsMixedState;\n\tself.alertBounceDockIconButton.allowsMixedState = allowsMixedState;\n\tself.alertBounceDockIconRepeatedlyButton.allowsMixedState = allowsMixedState;\n\tself.alertDisableWhileAwayButton.allowsMixedState = allowsMixedState;\n\tself.alertPushNotificationButton.allowsMixedState = allowsMixedState;\n}\n\n- (void)setNotifications:(NSArray *)notifications\n{\n\tif (self->_notifications != notifications) {\n\t\tself->_notifications = [notifications copy];\n\n\t\t[self availableAlertsChanged];\n\t}\n}\n\n- (void)availableAlertsChanged\n{\n\tif (self.notifications.count == 0) {\n\t\t[self resetControls];\n\t} else {\n\t\t[self updateAlertSelection];\n\t}\n}\n\n- (void)resetControls\n{\n\t[self.alertTypeChoiceButton removeAllItems];\n\n\tself.alertSpeakEventButton.state = NSControlStateValueOff;\n\tself.alertBounceDockIconButton.state = NSControlStateValueOff;\n\tself.alertBounceDockIconRepeatedlyButton.enabled = NO;\n\tself.alertBounceDockIconRepeatedlyButton.state = NSControlStateValueOff;\n\tself.alertDisableWhileAwayButton.state = NSControlStateValueOff;\n\tself.alertPushNotificationButton.state = NSControlStateValueOff;\n\n\t[self.alertSoundChoiceButton removeAllItems];\n}\n\n- (void)updateAlertSelection\n{\n\t[self.alertTypeChoiceButton removeAllItems];\n\n\t[self.notifications enumerateObjectsUsingBlock:^(id alert, NSUInteger index, BOOL *stop) {\n\t\tif ([alert isKindOfClass:[TLONotificationConfiguration class]]) {\n\t\t\tNSMenuItem *item = [NSMenuItem new];\n\n\t\t\titem.tag = index;\n\n\t\t\titem.title = [alert displayName];\n\n\t\t\t[self.alertTypeChoiceButton.menu addItem:item];\n\t\t} else {\n\t\t\t[self.alertTypeChoiceButton.menu addItem:[NSMenuItem separatorItem]];\n\t\t}\n\t}];\n\n\t[self.alertTypeChoiceButton selectItemAtIndex:0];\n\n\t[self onChangedAlertType:nil];\n}\n\n- (void)reload\n{\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\tself.alertSpeakEventButton.state = alert.speakEvent;\n\tself.alertBounceDockIconButton.state = alert.bounceDockIcon;\n\tself.alertBounceDockIconRepeatedlyButton.enabled = (self.alertBounceDockIconButton.state != NSControlStateValueOff);\n\tself.alertBounceDockIconRepeatedlyButton.state = alert.bounceDockIconRepeatedly;\n\tself.alertDisableWhileAwayButton.state = alert.disabledWhileAway;\n\tself.alertPushNotificationButton.state = alert.pushNotification;\n\n\tNSString *alertSound = alert.alertSound;\n\n\tif (alertSound == nil) {\n\t\t[self.alertSoundChoiceButton selectItemAtIndex:_alertSoundsDefaultSoundIndex];\n\t} else if ([alertSound isEqualToString:TXNoAlertSoundPreferenceValue]) {\n\t\t[self.alertSoundChoiceButton selectItemAtIndex:_alertSoundsNoSoundIndex];\n\t} else {\n\t\tNSUInteger soundIndex = [self.alertSounds indexOfObject:alert.alertSound];\n\n\t\tif (soundIndex == NSNotFound) {\n\t\t\t[self.alertSoundChoiceButton selectItemAtIndex:_alertSoundsNoSoundIndex];\n\t\t} else {\n\t\t\t[self.alertSoundChoiceButton selectItemAtIndex:soundIndex];\n\t\t}\n\t}\n}\n\n- (void)onChangedAlertType:(id)sender\n{\n\tTXNotificationType alertTag = (TXNotificationType)self.alertTypeChoiceButton.selectedTag;\n\n\tself.activeAlert = self.notifications[alertTag];\n\n\t[self reload];\n}\n\n- (void)onChangedAlertPushNotification:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\talert.pushNotification = self.alertPushNotificationButton.state;\n}\n\n- (void)onChangedAlertSpoken:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\talert.speakEvent = self.alertSpeakEventButton.state;\n}\n\n- (void)onChangedAlertDisableWhileAway:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\talert.disabledWhileAway = self.alertDisableWhileAwayButton.state;\n}\n\n- (void)onChangedAlertBounceDockIcon:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\talert.bounceDockIcon = self.alertBounceDockIconButton.state;\n\n\tself.alertBounceDockIconRepeatedlyButton.enabled = (self.alertBounceDockIconButton.state == NSControlStateValueOn);\n}\n\n- (void)onChangedAlertBounceDockIconRepeatedly:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\talert.bounceDockIconRepeatedly = self.alertBounceDockIconRepeatedlyButton.state;\n}\n\n- (void)onChangedAlertSound:(id)sender\n{\n\tself.activeAlertPropertyChangedByUser = YES;\n\n\tTLONotificationConfiguration *alert = self.activeAlert;\n\n\tNSString *alertSound = self.alertSoundChoiceButton.titleOfSelectedItem;\n\n\tif ([alertSound isEqualToString:[TLONotificationConfiguration localizedAlertDefaultSoundTitle]]) {\n\t\talertSound = nil;\n\t} else if ([alertSound isEqualToString:[TLONotificationConfiguration localizedAlertNoSoundTitle]]) {\n\t\talertSound = TXNoAlertSoundPreferenceValue;\n\t}\n\n\tif (alertSound) {\n\t\t[TLOSoundPlayer playAlertSound:alertSound];\n\t}\n\n\talert.alertSound = alertSound;\n}\n\n- (void)setActiveAlert:(TLONotificationConfiguration *)activeAlert\n{\n\tNSParameterAssert(activeAlert != nil);\n\n\tif (self->_activeAlert != activeAlert) {\n\t\t[self stopObservingActiveAlert];\n\n\t\tself->_activeAlert = activeAlert;\n\n\t\t[self startObservingActiveAlert];\n\t}\n}\n\n- (void)startObservingActiveAlert\n{\n\tTLONotificationConfiguration *activeAlert = self.activeAlert;\n\n\tif (activeAlert == nil) {\n\t\treturn;\n\t}\n\n\t[activeAlert addObserver:self forKeyPath:@\"alertSound\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[activeAlert addObserver:self forKeyPath:@\"speakEvent\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[activeAlert addObserver:self forKeyPath:@\"pushNotification\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[activeAlert addObserver:self forKeyPath:@\"disableWhileAway\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[activeAlert addObserver:self forKeyPath:@\"bounceDockIcon\" options:NSKeyValueObservingOptionNew context:NULL];\n\t[activeAlert addObserver:self forKeyPath:@\"bounceDockIconRepeatedly\" options:NSKeyValueObservingOptionNew context:NULL];\n}\n\n- (void)stopObservingActiveAlert\n{\n\tTLONotificationConfiguration *activeAlert = self.activeAlert;\n\n\tif (activeAlert == nil) {\n\t\treturn;\n\t}\n\n\t[activeAlert removeObserver:self forKeyPath:@\"alertSound\"];\n\t[activeAlert removeObserver:self forKeyPath:@\"speakEvent\"];\n\t[activeAlert removeObserver:self forKeyPath:@\"pushNotification\"];\n\t[activeAlert removeObserver:self forKeyPath:@\"disableWhileAway\"];\n\t[activeAlert removeObserver:self forKeyPath:@\"bounceDockIcon\"];\n\t[activeAlert removeObserver:self forKeyPath:@\"bounceDockIconRepeatedly\"];\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif (object == self.activeAlert) {\n\t\tif (self.activeAlertPropertyChangedByUser) {\n\t\t\tself.activeAlertPropertyChangedByUser = NO;\n\n\t\t\treturn;\n\t\t}\n\n\t\tLogToConsoleDebug(\"Reloading user interface because key %{public}@ changed remotely\", keyPath);\n\n\t\t[self reload];\n\t}\n}\n\n- (void)updateAvailableSounds\n{\n\t[self.alertSoundChoiceButton removeAllItems];\n\n\tself.alertSounds = [self availableSounds];\n\n\t[self.alertSounds enumerateObjectsUsingBlock:^(id alertSound, NSUInteger index, BOOL *stop) {\n\t\tif ([alertSound isKindOfClass:[NSString class]]) {\n\t\t\tNSMenuItem *item = [NSMenuItem new];\n\n\t\t\titem.title = alertSound;\n\n\t\t\t[self.alertSoundChoiceButton.menu addItem:item];\n\t\t} else {\n\t\t\t[self.alertSoundChoiceButton.menu addItem:alertSound];\n\t\t}\n\t}];\n\n\t[self.alertSoundChoiceButton selectItemAtIndex:0];\n}\n\n- (NSArray *)availableSounds\n{\n\tNSMutableArray *sounds = [NSMutableArray array];\n\n\t[sounds addObject:[TLONotificationConfiguration localizedAlertDefaultSoundTitle]];\n\t[sounds addObject:[NSMenuItem separatorItem]];\n\t[sounds addObject:[TLONotificationConfiguration localizedAlertNoSoundTitle]];\n\t[sounds addObject:[NSMenuItem separatorItem]];\n\n\t[sounds addObjectsFromArray:[TLOSoundPlayer uniqueListOfSounds]];\n\n\treturn [sounds copy];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Server List/TVCServerList.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCServerListAppearancePrivate.h\"\n#import \"TVCServerListCellPrivate.h\"\n#import \"TVCServerListPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TVCServerListDragType = @\"TVCServerListDragType\";\n\n@interface TVCServerList ()\n@property (nonatomic, strong, readwrite) TVCServerListAppearance *userInterfaceObjects;\n@property (nonatomic, weak, readwrite) IBOutlet NSVisualEffectView *visualEffectView;\n@property (nonatomic, assign, readwrite) BOOL leftMouseIsDownInView;\n@end\n\n@implementation TVCServerList\n\n- (void)viewDidMoveToWindow\n{\n\t[super viewDidMoveToWindow];\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tif (mainWindow == nil) {\n\t\t[RZNotificationCenter() removeObserver:self];\n\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(windowDidBecomeKey:)\n\t\t\t\t\t\t\t\t   name:NSWindowDidBecomeKeyNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(windowDidResignKey:)\n\t\t\t\t\t\t\t\t   name:NSWindowDidResignKeyNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(mainWindowRequiresRedraw:)\n\t\t\t\t\t\t\t\t   name:TVCMainWindowRedrawSubviewsNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n}\n\n#pragma mark -\n#pragma mark Additions/Removal\n\n- (void)addItemToList:(NSUInteger)rowIndex inParent:(nullable id)parent\n{\n\t[self insertItemsAtIndexes:[NSIndexSet indexSetWithIndex:rowIndex]\n\t\t\t\t\t  inParent:parent\n\t\t\t\t withAnimation:(NSTableViewAnimationEffectFade | NSTableViewAnimationSlideRight)];\n\n\tif (parent) {\n\t\t[self reloadItem:parent];\n\t}\n}\n\n- (void)removeItemFromList:(id)object\n{\n\tNSParameterAssert(object != nil);\n\n\tNSInteger rowIndex = [self rowForItem:object];\n\n\tNSAssert((rowIndex >= 0),\n\t\t@\"Object does not exist on outline view\");\n\n\tid parentItem = [self parentForItem:object];\n\n\tif (parentItem) {\n\t\tNSArray *childrenItems = [self itemsFromParentGroup:parentItem];\n\n\t\trowIndex = [childrenItems indexOfObject:object];\n\t} else {\n\t\tNSArray *groupItems = self.groupItems;\n\n\t\trowIndex = [groupItems indexOfObject:object];\n\t}\n\n\tNSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:rowIndex];\n\n\t[self removeItemsAtIndexes:indexSet\n\t\t\t\t\t  inParent:parentItem\n\t\t\t\t withAnimation:(NSTableViewAnimationEffectFade | NSTableViewAnimationSlideLeft)];\n\n\tif (parentItem) {\n\t\t[self reloadItem:parentItem];\n\t}\n}\n\n- (void)moveItemAtIndex:(NSInteger)fromIndex inParent:(nullable id)oldParent toIndex:(NSInteger)toIndex inParent:(nullable id)newParent\n{\n\tif (fromIndex < toIndex) {\n\t\t[super moveItemAtIndex:fromIndex inParent:oldParent toIndex:(toIndex - 1) inParent:newParent];\n\t} else {\n\t\t[super moveItemAtIndex:fromIndex inParent:oldParent toIndex:toIndex inParent:newParent];\n\t}\n}\n\n#pragma mark -\n#pragma mark Drawing Updates\n\n- (void)refreshAllDrawings\n{\n\t[self refreshAllDrawings:NO];\n}\n\n- (void)refreshAllDrawings:(BOOL)skipOcclusionCheck\n{\n\tfor (NSUInteger i = 0; i < self.numberOfRows; i++) {\n\t\t[self refreshDrawingForRow:i skipOcclusionCheck:skipOcclusionCheck];\n\t}\n}\n\n- (void)refreshDrawingForRows:(NSIndexSet *)rowIndexes\n{\n\t[self refreshDrawingForRows:rowIndexes skipOcclusionCheck:NO];\n}\n\n- (void)refreshDrawingForRows:(NSIndexSet *)rowIndexes skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tNSParameterAssert(rowIndexes != nil);\n\n\t[rowIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\t[self refreshDrawingForRow:index skipOcclusionCheck:skipOcclusionCheck];\n\t}];\n}\n\n- (void)refreshDrawingForRow:(NSInteger)rowIndex\n{\n\t[self refreshDrawingForRow:rowIndex skipOcclusionCheck:NO];\n}\n\n- (void)refreshDrawingForRow:(NSInteger)rowIndex skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tif (rowIndex < 0) {\n\t\treturn;\n\t}\n\n\tif (skipOcclusionCheck == NO && self.mainWindow.occluded) {\n\t\treturn;\n\t}\n\n\t__kindof TVCServerListCell *rowView = [self viewAtColumn:0 row:rowIndex makeIfNecessary:NO];\n\n\trowView.needsDisplay = YES;\n}\n\n- (void)refreshDrawingForItem:(IRCTreeItem *)cellItem\n{\n\t[self refreshDrawingForItem:cellItem skipOcclusionCheck:NO];\n}\n\n- (void)refreshDrawingForItem:(IRCTreeItem *)cellItem skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tNSParameterAssert(cellItem != nil);\n\n\tNSInteger rowIndex = [self rowForItem:cellItem];\n\n\t[self refreshDrawingForRow:rowIndex skipOcclusionCheck:skipOcclusionCheck];\n}\n\n- (void)refreshMessageCountForItem:(IRCTreeItem *)cellItem\n{\n\t[self refreshMessageCountForItem:cellItem skipOcclusionCheck:NO];\n}\n\n- (void)refreshMessageCountForItem:(IRCTreeItem *)cellItem skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tNSParameterAssert(cellItem != nil);\n\n\tNSInteger rowIndex = [self rowForItem:cellItem];\n\n\t[self refreshMessageCountForRow:rowIndex skipOcclusionCheck:skipOcclusionCheck];\n}\n\n- (void)refreshAllUnreadMessageCountBadges\n{\n\t[self refreshAllUnreadMessageCountBadges:NO];\n}\n\n- (void)refreshAllUnreadMessageCountBadges:(BOOL)skipOcclusionCheck\n{\n\tfor (NSUInteger i = 0; i < self.numberOfRows; i++) {\n\t\t[self refreshMessageCountForRow:i skipOcclusionCheck:skipOcclusionCheck];\n\t}\n}\n\n- (void)refreshMessageCountForRows:(NSIndexSet *)rowIndexes\n{\n\t[self refreshMessageCountForRows:rowIndexes skipOcclusionCheck:NO];\n}\n\n- (void)refreshMessageCountForRows:(NSIndexSet *)rowIndexes skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tNSParameterAssert(rowIndexes != nil);\n\n\t[rowIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\t[self refreshMessageCountForRow:index skipOcclusionCheck:skipOcclusionCheck];\n\t}];\n}\n\n- (void)refreshMessageCountForRow:(NSInteger)rowIndex\n{\n\t[self refreshMessageCountForRow:rowIndex skipOcclusionCheck:NO];\n}\n\n- (void)refreshMessageCountForRow:(NSInteger)rowIndex skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tif (rowIndex < 0) {\n\t\treturn;\n\t}\n\n\tif (skipOcclusionCheck == NO && self.mainWindow.occluded) {\n\t\treturn;\n\t}\n\n\t__kindof TVCServerListCell *rowView = [self viewAtColumn:0 row:rowIndex makeIfNecessary:NO];\n\n\tBOOL isChildItem = [rowView isKindOfClass:[TVCServerListCellChildItem class]];\n\n\tif (isChildItem) {\n\t\t[rowView populateMessageCountBadge];\n\t}\n}\n\n- (BOOL)allowsVibrancy\n{\n\treturn YES;\n}\n\n- (void)updateVibrancyWithAppearance:(TVCServerListAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tNSVisualEffectView *visualEffectView = self.visualEffectView;\n\n\tif ([TPCPreferences disableSidebarTranslucency]) {\n\t\tvisualEffectView.state = NSVisualEffectStateInactive;\n\t} else {\n\t\tvisualEffectView.state = NSVisualEffectStateFollowsWindowActiveState;\n\t}\n\n\tvisualEffectView.material = NSVisualEffectMaterialSidebar;\n}\n\n- (void)applicationAppearanceChanged\n{\n\tTVCServerListAppearance *appearance = self.mainWindow.userInterfaceObjects.serverList;\n\n\t[self _updateAppearance:appearance];\n\n\t[self invalidateBackgroundForSelection];\n\n\t[self refreshAllDrawings:YES];\n}\n\n- (void)systemAppearanceChanged\n{\n//\t[self invalidateBackgroundForSelection];\n}\n\n- (void)_updateAppearance:(TVCServerListAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\t/* We assign a strong reference to these instead of returning the original\n\t value every time so that there are no race conditions for when it changes. */\n\tself.userInterfaceObjects = appearance;\n\n\t[self updateVibrancyWithAppearance:appearance];\n\n\tif (appearance.isDarkAppearance) {\n\t\tself.enclosingScrollView.scrollerKnobStyle = NSScrollerKnobStyleLight;\n\t} else {\n\t\tself.enclosingScrollView.scrollerKnobStyle = NSScrollerKnobStyleDark;\n\t}\n\n\tself.needsDisplay = YES;\n}\n\n- (void)windowDidBecomeKey:(NSNotification *)notification\n{\n\t[self windowKeyStateChanged:notification];\n}\n\n- (void)windowDidResignKey:(NSNotification *)notification\n{\n\t[self windowKeyStateChanged:notification];\n}\n\n- (void)windowKeyStateChanged:(NSNotification *)notification\n{\n\t[self respondToRequiresRedraw];\n}\n\n- (void)mainWindowRequiresRedraw:(NSNotification *)notification\n{\n\t[self respondToRequiresRedraw];\n}\n\n- (void)respondToRequiresRedraw\n{\n\t[self refreshAllDrawings:YES];\n}\n\n#pragma mark -\n#pragma mark Events\n\n- (nullable NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tNSInteger rowBeneathMouse = self.rowBeneathMouse;\n\n\tif (rowBeneathMouse >= 0) {\n\t\tif (rowBeneathMouse != self.selectedRow || self.numberOfSelectedRows > 1) {\n\t\t\t[self selectItemAtIndex:rowBeneathMouse];\n\t\t}\n\t} else {\n\t\treturn menuController().serverListNoSelectionMenu;\n\t}\n\n\treturn self.menu;\n}\n\n- (void)mouseDown:(NSEvent *)theEvent\n{\n\tself.leftMouseIsDownInView = YES;\n\n\t[super mouseDown:theEvent];\n}\n\n- (void)mouseUp:(NSEvent *)theEvent\n{\n\tself.leftMouseIsDownInView = NO;\n\n\t[super mouseUp:theEvent];\n}\n\n- (void)keyDown:(NSEvent *)e\n{\n\tif (self.keyDelegate == nil) {\n\t\treturn;\n\t}\n\n\tswitch (e.keyCode) {\n\t\tcase 125: // down arrow\n\t\tcase 126: // up arrow\n\t\tcase 123: // left arrow\n\t\tcase 124: // right arrow\n\t\tcase 116: // page up\n\t\tcase 121: // page down\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t[self.keyDelegate serverListKeyDown:e];\n\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Server List/TVCServerListAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSColorHelper.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSViewHelperPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCAppearancePrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TVCServerListAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCServerListAppearance ()\n@property (nonatomic, weak, readwrite) TVCServerList *serverList;\n\n@property (nonatomic, assign, readwrite) CGFloat defaultWidth;\n@property (nonatomic, assign, readwrite) CGFloat minimumWidth;\n@property (nonatomic, assign, readwrite) CGFloat maximumWidth;\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *rowSelectionColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *rowSelectionColorInactiveWindow;\n\n#pragma mark -\n#pragma mark Server Cell\n\n@property (nonatomic, assign, readwrite) BOOL serverRowEmphasized;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverDisabledTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverDisabledTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverSelectedTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *serverSelectedTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *serverFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *serverFontSelected;\n\n#pragma mark -\n#pragma mark Channel Cell\n\n@property (nonatomic, assign, readwrite) BOOL channelRowEmphasized;\n@property (nonatomic, assign, readwrite) CGFloat serverLabelLeftMargin;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelDisabledTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelDisabledTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelSelectedTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelSelectedTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelErroneousTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelErroneousTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelHighlightTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *channelHighlightTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *channelFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *channelFontSelected;\n\n#pragma mark -\n#pragma mark Message Count Badge\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeSelectedBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeSelectedBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeHighlightBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeHighlightBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeSelectedTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeSelectedTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeHighlightTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *unreadBadgeHighlightTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *unreadBadgeFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *unreadBadgeFontSelected;\n@property (nonatomic, assign, readwrite) CGFloat unreadBadgeMinimumWidth;\n@property (nonatomic, assign, readwrite) CGFloat unreadBadgeHeight;\n@property (nonatomic, assign, readwrite) CGFloat unreadBadgePadding;\n@end\n\n@implementation TVCServerListAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (nullable instancetype)initWithServerList:(TVCServerList *)serverList inWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(serverList != nil);\n\tNSParameterAssert(mainWindow != nil);\n\n\tNSURL *appearanceLocation = [self.class appearanceLocation];\n\n\t/* Don't access -mainWindow in serverList to get this value\n\t because it may not be on a window at the time this is called. */\n\tBOOL forRetinaDisplay = mainWindow.runningInHighResolutionMode;\n\n\tif ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\tself.serverList = serverList;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (NSURL *)appearanceLocation\n{\n\treturn [RZMainBundle() URLForResource:@\"TVCServerListAppearance\" withExtension:@\"plist\"];\n}\n\n- (void)prepareInitialState\n{\n\tNSDictionary *properties = self.appearanceProperties;\n\n\tself.defaultWidth = [self measurementForKey:@\"defaultWidth\"];\n\tself.minimumWidth = [self measurementForKey:@\"minimumWidth\"];\n\tself.maximumWidth = [self measurementForKey:@\"maximumWidth\"];\n\n\tself.rowSelectionColorActiveWindow = [self colorForKey:@\"selectionColor\" forActiveWindow:YES];\n\tself.rowSelectionColorInactiveWindow = [self colorForKey:@\"selectionColor\" forActiveWindow:NO];\n\n\tNSDictionary *serverCell = properties[@\"Server Cell\"];\n\n\tself.serverRowEmphasized = [serverCell boolForKey:@\"rowEmphasized\"];\n\tself.serverLabelLeftMargin = [serverCell floatForKey:@\"labelLeftMargin\"];\n\tself.serverTextColorActiveWindow = [self colorInGroup:serverCell withKey:@\"normalTextColor\" forActiveWindow:YES];\n\tself.serverTextColorInactiveWindow = [self colorInGroup:serverCell withKey:@\"normalTextColor\" forActiveWindow:NO];\n\tself.serverDisabledTextColorActiveWindow = [self colorInGroup:serverCell withKey:@\"disabledTextColor\" forActiveWindow:YES];\n\tself.serverDisabledTextColorInactiveWindow = [self colorInGroup:serverCell withKey:@\"disabledTextColor\" forActiveWindow:NO];\n\tself.serverSelectedTextColorActiveWindow = [self colorInGroup:serverCell withKey:@\"selectedTextColor\" forActiveWindow:YES];\n\tself.serverSelectedTextColorInactiveWindow = [self colorInGroup:serverCell withKey:@\"selectedTextColor\" forActiveWindow:NO];\n\tself.serverFont = [self fontInGroup:serverCell withKey:@\"font\"];\n\tself.serverFontSelected = [self fontInGroup:serverCell withKey:@\"fontSelected\"];\n\n\tNSDictionary *channelCell = properties[@\"Channel Cell\"];\n\n\tself.channelRowEmphasized = [channelCell boolForKey:@\"rowEmphasized\"];\n\tself.channelTextColorActiveWindow = [self colorInGroup:channelCell withKey:@\"normalTextColor\" forActiveWindow:YES];\n\tself.channelTextColorInactiveWindow = [self colorInGroup:channelCell withKey:@\"normalTextColor\" forActiveWindow:NO];\n\tself.channelDisabledTextColorActiveWindow = [self colorInGroup:channelCell withKey:@\"disabledTextColor\" forActiveWindow:YES];\n\tself.channelDisabledTextColorInactiveWindow = [self colorInGroup:channelCell withKey:@\"disabledTextColor\" forActiveWindow:NO];\n\tself.channelSelectedTextColorActiveWindow = [self colorInGroup:channelCell withKey:@\"selectedTextColor\" forActiveWindow:YES];\n\tself.channelSelectedTextColorInactiveWindow = [self colorInGroup:channelCell withKey:@\"selectedTextColor\" forActiveWindow:NO];\n\tself.channelErroneousTextColorActiveWindow = [self colorInGroup:channelCell withKey:@\"erroneousTextColor\" forActiveWindow:YES];\n\tself.channelErroneousTextColorInactiveWindow = [self colorInGroup:channelCell withKey:@\"erroneousTextColor\" forActiveWindow:NO];\n\tself.channelHighlightTextColorActiveWindow = [self colorInGroup:channelCell withKey:@\"highlightTextColor\" forActiveWindow:YES];\n\tself.channelHighlightTextColorInactiveWindow = [self colorInGroup:channelCell withKey:@\"highlightTextColor\" forActiveWindow:NO];\n\tself.channelFont = [self fontInGroup:channelCell withKey:@\"font\"];\n\tself.channelFontSelected = [self fontInGroup:channelCell withKey:@\"fontSelected\"];\n\n\tNSDictionary *unreadBadge = properties[@\"Unread Badge\"];\n\n\tself.unreadBadgeBackgroundColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"normalBackgroundColor\" forActiveWindow:YES];\n\tself.unreadBadgeBackgroundColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"normalBackgroundColor\" forActiveWindow:NO];\n\tself.unreadBadgeSelectedBackgroundColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"selectedBackgroundColor\" forActiveWindow:YES];\n\tself.unreadBadgeSelectedBackgroundColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"selectedBackgroundColor\" forActiveWindow:NO];\n\tself.unreadBadgeHighlightBackgroundColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"highlightBackgroundColor\" forActiveWindow:YES];\n\tself.unreadBadgeHighlightBackgroundColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"highlightBackgroundColor\" forActiveWindow:NO];\n\tself.unreadBadgeTextColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"normalTextColor\" forActiveWindow:YES];\n\tself.unreadBadgeTextColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"normalTextColor\" forActiveWindow:NO];\n\tself.unreadBadgeSelectedTextColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"selectedTextColor\" forActiveWindow:YES];\n\tself.unreadBadgeSelectedTextColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"selectedTextColor\" forActiveWindow:NO];\n\tself.unreadBadgeHighlightTextColorActiveWindow = [self colorInGroup:unreadBadge withKey:@\"highlightTextColor\" forActiveWindow:YES];\n\tself.unreadBadgeHighlightTextColorInactiveWindow = [self colorInGroup:unreadBadge withKey:@\"highlightTextColor\" forActiveWindow:NO];\n\tself.unreadBadgeFont = [self fontInGroup:unreadBadge withKey:@\"font\"];\n\tself.unreadBadgeFontSelected = [self fontInGroup:unreadBadge withKey:@\"fontSelected\"];\n\tself.unreadBadgeMinimumWidth = [self measurementInGroup:unreadBadge withKey:@\"minimumWidth\"];\n\tself.unreadBadgeHeight = [self measurementInGroup:unreadBadge withKey:@\"height\"];\n\tself.unreadBadgePadding = [self measurementInGroup:unreadBadge withKey:@\"padding\"];\n\n\t[self flushAppearanceProperties];\n}\n\n#pragma mark -\n#pragma mark Everything Else\n\n- (nullable NSString *)statusIconForActiveChannel:(BOOL)isActive selected:(BOOL)isSelected activeWindow:(BOOL)isActiveWindow treatAsTemplate:(BOOL *)treatAsTemplate\n{\n\tNSParameterAssert(treatAsTemplate != NULL);\n\n\tTXAppearanceType appearanceType = self.appearanceType;\n\n\tswitch (appearanceType) {\n\t\tcase TXAppearanceTypeBigSurLight:\n\t\t{\n\t\t\t/* When the window is not in focus, when this item is selected, and when we are not\n\t\t\t using vibrant dark mode; the outline view does not turn our icon to a light variant\n\t\t\t like it would do if the window was in focus and used as a template. To workaround\n\t\t\t this oddity that Apple does, we fudge the icon by using another variant of it. */\n\t\t\tif (isActiveWindow == NO && isSelected) {\n\t\t\t\t*treatAsTemplate = NO;\n\n\t\t\t\tif (isActive) {\n\t\t\t\t\treturn @\"channelRoomStatusIconDarkActive\";\n\t\t\t\t} else {\n\t\t\t\t\treturn @\"channelRoomStatusIconDarkInactive\";\n\t\t\t\t}\n\t\t\t} // quirk fix\n\n\t\t\t*treatAsTemplate = YES;\n\n\t\t\tif (isActive) {\n\t\t\t\treturn @\"channelRoomStatusIconLightActive\";\n\t\t\t} else {\n\t\t\t\treturn @\"channelRoomStatusIconLightInactive\";\n\t\t\t}\n\t\t} // Big Sur\n\t\tcase TXAppearanceTypeBigSurDark:\n\t\t{\n\t\t\t*treatAsTemplate = NO;\n\n\t\t\tif (isActive) {\n\t\t\t\treturn @\"channelRoomStatusIconDarkActive\";\n\t\t\t} else {\n\t\t\t\treturn @\"channelRoomStatusIconDarkInactive\";\n\t\t\t}\n\t\t} // Big Sur\n\t} // switch()\n}\n\n- (nullable NSString *)statusIconForActiveQuery:(BOOL)isActive selected:(BOOL)isSelected activeWindow:(BOOL)isActiveWindow treatAsTemplate:(BOOL *)treatAsTemplate\n{\n\tNSParameterAssert(treatAsTemplate != NULL);\n\n\tTXAppearanceType appearanceType = self.appearanceType;\n\n\tswitch (appearanceType) {\n\t\tcase TXAppearanceTypeBigSurLight:\n\t\t{\n\t\t\t*treatAsTemplate = YES;\n\n\t\t\tif (isActive) {\n\t\t\t\treturn @\"VibrantLightServerListViewPrivateMessageUserIconActive\";\n\t\t\t} else {\n\t\t\t\treturn @\"VibrantLightServerListViewPrivateMessageUserIconInactive\";\n\t\t\t}\n\t\t} // Big Sur\n\t\tcase TXAppearanceTypeBigSurDark:\n\t\t{\n\t\t\t*treatAsTemplate = NO;\n\n\t\t\tif (isActive) {\n\t\t\t\treturn @\"VibrantDarkServerListViewPrivateMessageUserIconActive\";\n\t\t\t} else {\n\t\t\t\treturn @\"VibrantDarkServerListViewPrivateMessageUserIconInactive\";\n\t\t\t}\n\t\t} // Big Sur\n\t} // switch()\n}\n\n- (nullable NSColor *)unreadBadgeHighlightBackgroundColorByUser\n{\n\treturn [RZUserDefaults() colorForKey:@\"Server List Unread Message Count Badge Colors -> Highlight\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/Server List/TVCServerListCell.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSViewHelperPrivate.h\"\n#import \"TXGlobalModels.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCServerListAppearancePrivate.h\"\n#import \"TVCServerListPrivate.h\"\n#import \"TVCServerListCellPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCServerListCellDrawingContext;\n\n@interface TVCServerListRowCell ()\n@property (nonatomic, weak) TVCServerList *serverList;\n@property (nonatomic, weak) __kindof TVCServerListCell *childCell;\n@property (readonly) TVCServerListAppearance *userInterfaceObjects;\n@property (readonly) BOOL isGroupItem;\n@end\n\n@interface TVCServerListCell ()\n@property (nonatomic, weak) IBOutlet NSTextField *cellTextField;\n@property (nonatomic, weak) IBOutlet NSImageView *messageCountBadgeImageView;\n// Deactivating the constraints will dereference them.\n// We need to maintain a strong reference.\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *cellTextFieldLeftMarginConstraint;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *messageCountBadgeLeadingConstraint;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *messageCountBadgeTrailingConstraint;\n@property (readonly) BOOL isGroupItem;\n@property (readonly) TVCServerList *serverList;\n@property (readonly) __kindof TVCServerListRowCell *rowCell;\n@property (readonly) TVCServerListAppearance *userInterfaceObjects;\n@property (readonly) TVCServerListCellDrawingContext *drawingContext;\n@property (readonly) IRCTreeItem *cellItem;\n@end\n\n@interface TVCServerListCellGroupItem ()\n@property (nonatomic, weak, nullable) NSButton *disclosureTriangle;\n@end\n\n@interface TVCServerListCellDrawingContext : NSObject\n@property (nonatomic, assign) BOOL isActive;\n@property (nonatomic, assign) BOOL isGroupItem;\n@property (nonatomic, assign) BOOL isInverted;\n@property (nonatomic, assign) BOOL isSelected;\n@property (nonatomic, assign) BOOL isSelectedFrontmost;\n@property (nonatomic, assign) BOOL isWindowActive;\n@end\n\n@implementation TVCServerListCell\n\n#pragma mark -\n#pragma mark Cell Drawing\n\n- (void)defineConstraints\n{\n\n}\n\n- (BOOL)wantsUpdateLayer\n{\n\treturn YES;\n}\n\n- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy\n{\n\treturn NSViewLayerContentsRedrawOnSetNeedsDisplay;\n}\n\n- (void)updateLayer\n{\n\t[self updateDrawing];\n}\n\n- (void)updateDrawing\n{\n\tTVCServerListCellDrawingContext *drawingContext = self.drawingContext;\n\n\t[self updateTextFieldInContext:drawingContext];\n\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\t[self updateDrawingForWithAppearance:appearance inContext:drawingContext];\n}\n\n- (void)updateTextFieldInContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(drawingContext != nil);\n\n\t/* Update string value */\n\tIRCTreeItem *cellItem = self.cellItem;\n\n\tNSString *stringValueNew = cellItem.label;\n\n\tNSTextField *textField = self.cellTextField;\n\n\tNSString *stringValueOld = textField.stringValue;\n\n\tif ([stringValueOld isEqualTo:stringValueNew]) {\n\t\treturn;\n\t}\n\n\ttextField.stringValue = stringValueNew;\n\n\t/* Update accessibility */\n\tBOOL isActive = drawingContext.isActive;\n\tBOOL isGroupItem = drawingContext.isGroupItem;\n\n\tNSTextFieldCell *textFieldCell = textField.cell;\n\n\tif (isGroupItem) {\n\t\tif (isActive) {\n\t\t\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[bmy-d2]\", stringValueNew)];\n\t\t} else {\n\t\t\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[tu4-8u]\", stringValueNew)];\n\t\t} // isActive\n\t} else {\n\t\tif (((IRCChannel *)cellItem).isChannel == NO) {\n\t\t\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[9sn-xp]\", stringValueNew)];\n\t\t} else {\n\t\t\tif (isActive) {\n\t\t\t\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[75f-og]\", stringValueNew)];\n\t\t\t} else {\n\t\t\t\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[edc-7o]\", stringValueNew)];\n\t\t\t} // isActive\n\t\t} // isChannel\n\n\t\t[self.imageView.cell setAccessibilityLabel:nil];\n\t} // isGroupItem\n}\n\n- (void)updateDrawingForWithAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isActive = drawingContext.isActive;\n\tBOOL isGroupItem = drawingContext.isGroupItem;\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\tif (isGroupItem == NO) {\n\t\tIRCTreeItem *cellItem = self.cellItem;\n\n\t\tIRCChannel *channel = (IRCChannel *)cellItem;\n\n\t\tNSString *iconName = nil;\n\n\t\tBOOL iconIsTemplate = NO;\n\n\t\tif (channel.isChannel) {\n\t\t\ticonName = [appearance statusIconForActiveChannel:isActive selected:isSelected activeWindow:isWindowActive treatAsTemplate:&iconIsTemplate];\n\t\t} else {\n\t\t\ticonName = [appearance statusIconForActiveQuery:isActive selected:isSelected activeWindow:isWindowActive treatAsTemplate:&iconIsTemplate];\n\t\t} // isChannel\n\n\t\tNSImage *icon = [NSImage imageNamed:iconName];\n\n\t\ticon.template = iconIsTemplate;\n\n\t\tself.imageView.image = icon;\n\t}\n\n\tNSAttributedString *newValue = [self attributedTextFieldValueWithAppearance:appearance inContext:drawingContext];\n\n\tself.cellTextField.attributedStringValue = newValue;\n\n\tif (isGroupItem == NO) {\n\t\t[self populateMessageCountBadgeWithAppearance:appearance inContext:drawingContext];\n\t}\n}\n\n- (NSAttributedString *)attributedTextFieldValueWithAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isActive = drawingContext.isActive;\n\tBOOL isGroupItem = drawingContext.isGroupItem;\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\tIRCTreeItem *cellItem = self.cellItem;\n\n\tBOOL isErroneous = NO;\n\n\tBOOL isHighlight = NO;\n\n\tif (isGroupItem == NO) {\n\t\tIRCChannel *associatedChannel = (id)cellItem;\n\n\t\tisErroneous = associatedChannel.errorOnLastJoinAttempt;\n\n\t\tisHighlight = (associatedChannel.nicknameHighlightCount > 0);\n\t}\n\n\tNSTextField *textField = self.cellTextField;\n\n\tNSAttributedString *stringValue = textField.attributedStringValue;\n\n\tNSMutableAttributedString *mutableStringValue = [stringValue mutableCopy];\n\n\t[mutableStringValue beginEditing];\n\n\tNSFont *controlFont = nil;\n\n\tNSColor *controlColor = nil;\n\n\tif (isGroupItem)\n\t{\n\t\tif (isSelected) {\n\t\t\tcontrolFont = appearance.serverFontSelected;\n\t\t} else {\n\t\t\tcontrolFont = appearance.serverFont;\n\t\t} // isSelected\n\n\t\tif (isSelected) {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.serverSelectedTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.serverSelectedTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} else if (isActive) {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.serverTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.serverTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} else {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.serverDisabledTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.serverDisabledTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t}\n\t}\n\telse // isGroupItem\n\t{\n\t\tif (isSelected) {\n\t\t\tcontrolFont = appearance.channelFontSelected;\n\t\t} else {\n\t\t\tcontrolFont = appearance.channelFont;\n\t\t} // isSelected\n\n\t\tif (isSelected) {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.channelSelectedTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.channelSelectedTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} else if (isActive && isHighlight) {\n\t\t\tNSColor *customColor = appearance.unreadBadgeHighlightBackgroundColorByUser;\n\n\t\t\tif (customColor && [customColor isEqual:[NSColor clearColor]] == NO) {\n\t\t\t\tcontrolColor = customColor;\n\t\t\t} else {\n\t\t\t\tif (isWindowActive) {\n\t\t\t\t\tcontrolColor = appearance.channelHighlightTextColorActiveWindow;\n\t\t\t\t} else {\n\t\t\t\t\tcontrolColor = appearance.channelHighlightTextColorInactiveWindow;\n\t\t\t\t} // isWindowActive\n\t\t\t} // custom color set\n\t\t} else if (isActive) {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.channelTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.channelTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} else if (isErroneous) {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.channelErroneousTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.channelErroneousTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} else {\n\t\t\tif (isWindowActive) {\n\t\t\t\tcontrolColor = appearance.channelDisabledTextColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tcontrolColor = appearance.channelDisabledTextColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t}\n\t} // isGroupItem\n\n\tNSRange stringValueRange = stringValue.range;\n\n\tif (controlFont) {\n\t\t[mutableStringValue addAttribute:NSFontAttributeName value:controlFont range:stringValueRange];\n\t}\n\n\tif (controlColor) {\n\t\t[mutableStringValue addAttribute:NSForegroundColorAttributeName value:controlColor\trange:stringValueRange];\n\t}\n\n\t[mutableStringValue endEditing];\n\n\treturn mutableStringValue;\n}\n\n#pragma mark -\n#pragma mark Badge Drawing\n\n- (void)populateMessageCountBadge\n{\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\tTVCServerListCellDrawingContext *drawingContext = self.drawingContext;\n\n\t[self populateMessageCountBadgeWithAppearance:appearance inContext:drawingContext];\n}\n\n- (void)populateMessageCountBadgeWithAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isSelectedFrontmost = drawingContext.isSelectedFrontmost;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\tBOOL multipleRowsSelected = (self.serverList.numberOfSelectedRows > 1);\n\n\tIRCChannel *associatedChannel = (id)self.cellItem;\n\n\tBOOL drawMessageBadge = (isSelected == NO ||\n\t\t\t\t\t\t\t(isSelectedFrontmost == NO && isSelected && multipleRowsSelected) ||\n\t\t\t\t\t\t\t(isWindowActive == NO && isSelected));\n\n\tif (associatedChannel.config.showTreeBadgeCount == NO) {\n\t\tdrawMessageBadge = NO;\n\t}\n\n\tNSUInteger treeUnreadCount = associatedChannel.treeUnreadCount;\n\tNSUInteger nicknameHighlightCount = associatedChannel.nicknameHighlightCount;\n\n\tBOOL isHighlight = (nicknameHighlightCount > 0);\n\n\tif (associatedChannel.config.ignoreHighlights) {\n\t\tisHighlight = NO;\n\t}\n\n\t/* Begin draw if we want to. */\n\tif (treeUnreadCount > 0 && drawMessageBadge) {\n\t\tNSAttributedString *stringToDraw = [self messageCountBadgeTextForCount:treeUnreadCount isHighlight:isHighlight withAppearance:appearance inContext:drawingContext];\n\n\t\tNSRect badgeRect = [self messageCountBadgeRectForText:stringToDraw withAppearance:appearance inContext:drawingContext];\n\n\t\t[self drawMessageCountBadgeWithString:stringToDraw inRect:badgeRect isHighlight:isHighlight withAppearance:appearance inContext:drawingContext];\n\n\t\tself.messageCountBadgeLeadingConstraint.active = YES;\n\t\tself.messageCountBadgeTrailingConstraint.active = YES;\n\t} else {\n\t\tself.messageCountBadgeImageView.image = nil;\n\n\t\t/* Disable constraints when badge is not visible to\n\t\t allow text field to hug the right of the table view. */\n\t\tself.messageCountBadgeLeadingConstraint.active = NO;\n\t\tself.messageCountBadgeTrailingConstraint.active = NO;\n\t}\n}\n\n- (NSAttributedString *)messageCountBadgeTextForCount:(NSUInteger)messageCount isHighlight:(BOOL)isHighlight withAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\tNSString *messageCountString = TXFormattedNumber(messageCount);\n\n\tNSFont *controlFont = nil;\n\n\tif (isSelected) {\n\t\tcontrolFont = appearance.unreadBadgeFontSelected;\n\t} else {\n\t\tcontrolFont = appearance.unreadBadgeFont;\n\t} // isSelected\n\n\tNSColor *controlColor = nil;\n\n\tif (isSelected) {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.unreadBadgeSelectedTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.unreadBadgeSelectedTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else if (isHighlight) {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.unreadBadgeHighlightTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.unreadBadgeHighlightTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.unreadBadgeTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.unreadBadgeTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t}\n\n\tNSDictionary *attributes = @{NSForegroundColorAttributeName : controlColor, NSFontAttributeName : controlFont};\n\n\tNSAttributedString *stringToDraw = [NSAttributedString attributedStringWithString:messageCountString attributes:attributes];\n\n\treturn stringToDraw;\n}\n\n- (NSRect)messageCountBadgeRectForText:(NSAttributedString *)stringToDraw withAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tCGFloat messageCountWidth = (stringToDraw.size.width + (appearance.unreadBadgePadding * 2.0));\n\n\tNSRect badgeFrame = NSMakeRect(0.0, 0.0, messageCountWidth, appearance.unreadBadgeHeight);\n\n\tCGFloat minimumWidth = appearance.unreadBadgeMinimumWidth;\n\n\tif (badgeFrame.size.width < minimumWidth) {\n\t\tCGFloat widthDiff  = (minimumWidth - badgeFrame.size.width);\n\n\t\tbadgeFrame.size.width += widthDiff;\n\n\t\tbadgeFrame.origin.x -= widthDiff;\n\t}\n\n\treturn badgeFrame;\n}\n\n- (void)drawMessageCountBadgeWithString:(NSAttributedString *)stringToDraw inRect:(NSRect)rectToDraw isHighlight:(BOOL)isHighlight withAppearance:(TVCServerListAppearance *)appearance inContext:(TVCServerListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\t/* Create image that we will draw into. */\n\tNSRect badgeFrame = NSMakeRect(0.0, 0.0, NSWidth(rectToDraw), NSHeight(rectToDraw));\n\n\tNSImage *badgeImage = [NSImage newImageWithSize:NSMakeSize(NSWidth(rectToDraw),  NSHeight(rectToDraw))];\n\n\t[badgeImage lockFocus];\n\n\t/* Draw the background color. */\n\tNSColor *backgroundColor = nil;\n\n\tif (isSelected) {\n\t\tif (isWindowActive) {\n\t\t\tbackgroundColor = appearance.unreadBadgeSelectedBackgroundColorActiveWindow;\n\t\t} else {\n\t\t\tbackgroundColor = appearance.unreadBadgeSelectedBackgroundColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else if (isHighlight) {\n\t\tNSColor *customColor = appearance.unreadBadgeHighlightBackgroundColorByUser;\n\n\t\tif (customColor && [customColor isEqual:[NSColor clearColor]] == NO) {\n\t\t\tbackgroundColor = customColor;\n\t\t} else {\n\t\t\tif (isWindowActive) {\n\t\t\t\tbackgroundColor = appearance.unreadBadgeHighlightBackgroundColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tbackgroundColor = appearance.unreadBadgeHighlightBackgroundColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} // custom color set\n\t} else {\n\t\tif (isWindowActive) {\n\t\t\tbackgroundColor = appearance.unreadBadgeBackgroundColorActiveWindow;\n\t\t} else {\n\t\t\tbackgroundColor = appearance.unreadBadgeBackgroundColorActiveWindow;\n\t\t} // isWindowActive\n\t}\n\n\t/* Draw the background of the badge */\n\tNSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeFrame xRadius:7.0 yRadius:7.0];\n\n\t[backgroundColor set];\n\n\t[badgePath fill];\n\n\t/* Center the text relative to the badge itself */\n\tNSPoint badgeTextPoint =\n\tNSMakePoint((NSMidX(badgeFrame) - (stringToDraw.size.width  / 2.0)),\n\t\t\t\t(NSMidY(badgeFrame) - (stringToDraw.size.height / 2.0)));\n\n\t/* Perform draw and set image */\n\t[stringToDraw drawAtPoint:badgeTextPoint];\n\n\t[badgeImage unlockFocus];\n\n\tself.messageCountBadgeImageView.image = badgeImage;\n}\n\n#pragma mark -\n#pragma mark Cell Information\n\n- (BOOL)isGroupItem\n{\n\treturn [self isKindOfClass:[TVCServerListCellGroupItem class]];\n}\n\n- (__kindof TVCServerListRowCell *)rowCell\n{\n\treturn (id)self.superview;\n}\n\n- (IRCTreeItem *)cellItem\n{\n\treturn self.objectValue;\n}\n\n- (TVCServerList *)serverList\n{\n\treturn self.rowCell.serverList;\n}\n\n- (TVCServerListAppearance *)userInterfaceObjects\n{\n\treturn self.rowCell.userInterfaceObjects;\n}\n\n- (TVCServerListCellDrawingContext *)drawingContext\n{\n\tTVCServerList *serverList = self.serverList;\n\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\tIRCTreeItem *cellItem = self.cellItem;\n\n\tNSInteger rowIndex = [serverList rowForItem:cellItem];\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tTVCServerListCellDrawingContext *drawingContext = [TVCServerListCellDrawingContext new];\n\n\tdrawingContext.isActive = cellItem.isActive;\n\tdrawingContext.isGroupItem = self.isGroupItem;\n\tdrawingContext.isInverted = appearance.isDarkAppearance;\n\tdrawingContext.isSelected = [serverList isRowSelected:rowIndex];\n\tdrawingContext.isSelectedFrontmost = [mainWindow isItemSelected:cellItem];\n\tdrawingContext.isWindowActive = mainWindow.isActiveForDrawing;\n\n\treturn drawingContext;\n}\n\n- (BOOL)needsDisplayWhenApplicationAppearanceChanges\n{\n\treturn NO;\n}\n\n- (BOOL)needsDisplayWhenSystemAppearanceChanges\n{\n\treturn NO;\n}\n\n@end\n\n@implementation TVCServerListCellGroupItem\n\n- (void)defineConstraints\n{\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\tself.cellTextFieldLeftMarginConstraint.constant = appearance.serverLabelLeftMargin;\n}\n\n- (void)applicationAppearanceChanged\n{\n\t[super defineConstraints];\n\n\t[self defineConstraints];\n}\n\n@end\n\n@implementation TVCServerListCellChildItem\n@end\n\n@implementation TVCServerListCellDrawingContext\n@end\n\n#pragma mark -\n#pragma mark Row Cell\n\n@implementation TVCServerListRowCell\n\n- (instancetype)initWithServerList:(TVCServerList *)serverList\n{\n\tif ((self = [super initWithFrame:NSZeroRect])) {\n\t\tself.serverList = serverList;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)drawDraggingDestinationFeedbackInRect:(NSRect)dirtyRect\n{\n\t; // Do nothing for this...\n}\n\n- (void)setSelected:(BOOL)selected\n{\n\tsuper.selected = selected;\n\n\tif (selected == NO && self.invalidatingBackgroundForSelection) {\n\t\treturn;\n\t}\n\n\t[self setNeedsDisplayOnChild];\n}\n\n- (void)setNeedsDisplayOnChild\n{\n\tself.childCell.needsDisplay = YES;\n}\n\n- (void)drawSelectionInRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tBOOL isWindowActive = self.mainWindow.isActiveForDrawing;\n\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\tNSColor *selectionColor = nil;\n\n\tif (isWindowActive) {\n\t\tselectionColor = appearance.rowSelectionColorActiveWindow;\n\t} else {\n\t\tselectionColor = appearance.rowSelectionColorInactiveWindow;\n\t} // isWindowActive\n\n\tif (selectionColor) {\n\t\t[selectionColor set];\n\n\t\tNSRect selectionRect = self.bounds;\n\n\t\tNSRectFill(selectionRect);\n\t} else {\n\t\t[super drawSelectionInRect:dirtyRect];\n\t} // selectionColor\n}\n\n- (void)didAddSubview:(NSView *)subview\n{\n\tTVCServerListCellGroupItem *childCell = self.childCell;\n\n\t[childCell defineConstraints];\n\n\t[super didAddSubview:subview];\n}\n\n#pragma mark -\n#pragma mark Cell Information\n\n- (BOOL)isEmphasized\n{\n\tTVCServerListAppearance *appearance = self.userInterfaceObjects;\n\n\tBOOL emphasized = NO;\n\n\tif (self.isGroupItem) {\n\t\temphasized = appearance.serverRowEmphasized;\n\t} else {\n\t\temphasized = appearance.channelRowEmphasized;\n\t}\n\n\tNSWindow *window = self.window;\n\n\treturn (emphasized &&\n\t\t\t(window == nil || window.isKeyWindow));\n}\n\n- (__kindof TVCServerListCell * _Nullable)childCell\n{\n\tif (self->_childCell == nil) {\n\t\tif (self.numberOfColumns == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tself->_childCell = [self viewAtColumn:0];\n\t}\n\n\treturn self->_childCell;\n}\n\n- (TVCServerListAppearance *)userInterfaceObjects\n{\n\treturn self.serverList.userInterfaceObjects;\n}\n\n- (BOOL)isGroupItem\n{\n\treturn [self isKindOfClass:[TVCServerListGroupRowCell class]];\n}\n\n@end\n\n@implementation TVCServerListGroupRowCell\n@end\n\n@implementation TVCServerListChildRowCell\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/TVCAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TVCAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TVCListAppearanceColorType)\n{\n\tTVCListAppearanceColorTypeCalibratedWhite = 1, // <white value> [alpha]\n\tTVCListAppearanceColorTypeRGB = 2, // <r> <g> <b> [alpha]\n\tTVCListAppearanceColorTypeSystem = 3, // selector\n};\n\ntypedef NS_ENUM(NSUInteger, TVCListAppearanceImageType)\n{\n\tTVCListAppearanceImageTypeAsset = 1,\n};\n\n@interface TVCAppearance ()\n@property (nonatomic, assign, readwrite) BOOL isHighResolutionAppearance;\n@property (nonatomic, copy, nullable, readwrite) NSDictionary<NSString *, id> *appearanceProperties;\n@end\n\n@implementation TVCAppearance\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (nullable instancetype)initWithAppearanceNamed:(NSString *)appearanceName atURL:(NSURL *)appearanceLocation forRetinaDisplay:(BOOL)forRetinaDisplay\n{\n\tNSParameterAssert(appearanceName != nil);\n\tNSParameterAssert(appearanceLocation != nil);\n\n\tif ((self = [super init])) {\n\t\tif ([self _loadAppearanceNamed:appearanceName atURL:appearanceLocation forRetinaDisplay:forRetinaDisplay] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tself.isHighResolutionAppearance = forRetinaDisplay;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)_loadAppearanceNamed:(NSString *)appearanceName atURL:(NSURL *)appearanceLocation forRetinaDisplay:(BOOL)forRetinaDisplay\n{\n\tNSParameterAssert(appearanceName != nil);\n\tNSParameterAssert(appearanceLocation != nil);\n\n\t/* Load file */\n\tNSDictionary *appearances = [NSDictionary dictionaryWithContentsOfURL:appearanceLocation];\n\n\tif (appearances == nil) {\n\t\treturn NO;\n\t}\n\n\t/* Find the appearance */\n\tNSDictionary *appearance = [appearances dictionaryForKey:appearanceName];\n\n\tif (appearance == nil) {\n\t\treturn NO;\n\t}\n\n\t/* Combine any appearances it may inherit from */\n\tappearance = [self.class _combineAppearance:appearance withOtherAppearances:appearances];\n\n\tif (appearance == nil) {\n\t\treturn NO;\n\t}\n\n\t/* Save appearance */\n\tself.appearanceProperties = appearance;\n\n\treturn YES;\n}\n\n- (void)flushAppearanceProperties\n{\n\tself.appearanceProperties = nil;\n}\n\n#pragma mark -\n#pragma mark Inheritance\n\n/* TVCListAppearance allows for one appearance to inherit properties\n from another group recursively. */\n/* For example: \tAppearanceDarkRetina ->\n\t\t\t\t\tAppearanceDarkBase ->\n\t\t\t\t\tAppearanceBase */\n/* -_combineAppearance:withOtherAppearances: is the staging ground for\n this logic. The first argument is the properties for the appearance\n that was specified in -init. The second argument is the contents of\n the file that appearance originated from. */\n+ (nullable NSDictionary *)_combineAppearance:(NSDictionary<NSString *, id> *)appearanceIn withOtherAppearances:(NSDictionary<NSString *, id> *)otherAppearances\n {\n\t NSParameterAssert(appearanceIn != nil);\n\t NSParameterAssert(otherAppearances != nil);\n\n\t /* Object can be an array of strings or a string. */\n\t id inheritedName = [appearanceIn objectForKey:@\"inheritFrom\"];\n\n\t if (inheritedName == nil) {\n\t\t return appearanceIn;\n\t }\n\n\t /* The array of references is the dictionaries that will be combined. */\n\t __block NSMutableArray<NSDictionary<NSString *, id> *> *inheritedProperties = [NSMutableArray array];\n\n\t typedef void (^inheritLogicType)(id);\n\t __weak __block inheritLogicType inheritLogicWeak = nil;\n\n\t inheritLogicType inheritLogic = ^(id inheritedName)\n\t {\n\t\t NSDictionary *lastInheritance = nil;\n\n\t\t /* Allow for multiple inheritance */\n\t\t if ([inheritedName isKindOfClass:[NSArray class]]) {\n\t\t\t for (id name in ((NSArray *)inheritedName).reverseObjectEnumerator) {\n\t\t\t\t inheritLogicWeak(name);\n\t\t\t }\n\n\t\t\t return;\n\t\t } else if ([inheritedName isKindOfClass:[NSString class]]) {\n\t\t\t lastInheritance = [otherAppearances dictionaryForKey:inheritedName];\n\t\t }\n\n\t\t /* No inheritance */\n\t\t if (lastInheritance == nil) {\n\t\t\t return;\n\t\t }\n\n\t\t /* Add the properties to the beginning of the array\n\t\t  so that we don't need to use a revers enumerator. */\n\t\t [inheritedProperties insertObject:lastInheritance atIndex:0];\n\n\t\t /* Is there deeper inheritance? */\n\t\t id nextInheritance = [lastInheritance objectForKey:@\"inheritFrom\"];\n\n\t\t if (nextInheritance == nil) {\n\t\t\t return;\n\t\t }\n\n\t\t inheritLogicWeak(nextInheritance);\n\t };\n\n\t /* Inherit from the first appearance. */\n\t inheritLogicWeak = inheritLogic;\n\n\t inheritLogic(inheritedName);\n\n\t /* If nothing was inherited, return original input. */\n\t if (inheritedProperties == nil) {\n\t\t return appearanceIn;\n\t }\n\n\t /* Blocks used for combining properties */\n\t /* I may over engineered this */\n\t typedef void (^mergingLogicType)(NSMutableDictionary *, NSDictionary *);\n\t __weak __block mergingLogicType mergingLogicWeak = nil;\n\n\t NSDictionary *(^mergeImmutableDictionary)(NSDictionary *, NSDictionary *) =\n\t ^NSDictionary *(NSDictionary *firstDictionary, NSDictionary *secondDictionary)\n\t {\n\t\t NSMutableDictionary *mutableFirstDictionary = [firstDictionary mutableCopy];\n\n\t\t mergingLogicWeak(mutableFirstDictionary, secondDictionary);\n\n\t\t return [mutableFirstDictionary copy];\n\t }; // mergeImmutableDictionary\n\n\t mergingLogicType mergingLogic =\n\t ^(NSMutableDictionary *localDictionary, NSDictionary *remoteDictionary)\n\t {\n\t\t [remoteDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id remoteObject, BOOL *stop) {\n\t\t\t id localObject = localDictionary[key];\n\n\t\t\t if (localObject == nil) {\n\t\t\t\t [localDictionary setObject:remoteObject forKey:key];\n\n\t\t\t\t return;\n\t\t\t }\n\n\t\t\t /* I tried to be clever by checking checking if localObject\n\t\t\t  is kind of class NSMutableDictionary so we can call this\n\t\t\t  block recursively on it instead of creating new mutable copy.\n\t\t\t  Yeah, I will never make that mistake. Cluster classes take a\n\t\t\t  crap on -isKindOfClass: */\n\t\t\t if ([remoteObject isKindOfClass:[NSDictionary class]] &&\n\t\t\t\t [localObject isKindOfClass:[NSDictionary class]])\n\t\t\t {\n\t\t\t\t localObject = mergeImmutableDictionary(localObject, remoteObject);\n\t\t\t } else {\n\t\t\t\t localObject = remoteObject;\n\t\t\t }\n\n\t\t\t [localDictionary setObject:localObject forKey:key];\n\t\t }];\n\t }; // mergingLogic\n\n\t mergingLogicWeak = mergingLogic;\n\n\t /* Combine properties */\n\t NSMutableDictionary *appearanceOut = [NSMutableDictionary dictionary];\n\n\t for (NSDictionary *properties in inheritedProperties) {\n\t\t mergingLogic(appearanceOut, properties);\n\t }\n\n\t /* Add top most appearance as final combination. */\n\t mergingLogic(appearanceOut, appearanceIn);\n\n\t [appearanceOut removeObjectForKey:@\"inheritFrom\"];\n\n\t return [appearanceOut copy];\n }\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable id)_valueForKey:(NSString *)key expectedType:(Class)expectedType\n{\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _valueInGroup:group withKey:key expectedType:expectedType];\n}\n\n- (nullable id)_valueInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key expectedType:(Class)expectedType\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tid referenceObject = nil;\n\n\tif (self.isHighResolutionAppearance == NO) {\n\t\treferenceObject = group[key];\n\t} else {\n\t\tNSString *retinaKey = [key stringByAppendingString:@\"@2x\"];\n\n\t\treferenceObject = ((group[retinaKey]) ?: group[key]);\n\t}\n\n\tif (referenceObject == nil || [referenceObject isKindOfClass:expectedType] == NO) {\n\t\treturn nil;\n\t}\n\n\treturn referenceObject;\n}\n\n#pragma mark -\n#pragma mark Color\n\n- (nullable NSColor *)colorForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self colorInGroup:group withKey:key];\n}\n\n- (nullable NSColor *)colorInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *colorProperties = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (colorProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _colorWithProperties:colorProperties];\n}\n\n- (nullable NSColor *)colorForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self colorInGroup:group withKey:key forActiveWindow:forActiveWindow];\n}\n\n- (nullable NSColor *)colorInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (referenceObject == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *colorKey = ((forActiveWindow) ? @\"activeWindow\" : @\"inactiveWindow\");\n\n\tNSDictionary *colorProperties = [referenceObject dictionaryForKey:colorKey];\n\n\tif (colorProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _colorWithProperties:colorProperties];\n}\n\n- (nullable NSColor *)_colorWithProperties:(NSDictionary<NSString *, id> *)colorProperties\n{\n\tNSParameterAssert(colorProperties != nil);\n\n\tNSString *colorValue = [colorProperties stringForKey:@\"value\"];\n\n\tif (colorValue == nil) {\n\t\treturn nil;\n\t}\n\n\tTVCListAppearanceColorType colorType = [colorProperties unsignedIntegerForKey:@\"type\"];\n\n\tswitch (colorType) {\n\t\tcase TVCListAppearanceColorTypeCalibratedWhite:\n\t\t{\n\t\t\tNSArray *components = [colorValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tif (components.count == 0) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tCGFloat white = [components doubleAtIndex:0];\n\n\t\t\tCGFloat alpha = 1.0;\n\n\t\t\tif (components.count == 2) {\n\t\t\t\talpha = [components doubleAtIndex:1];\n\t\t\t}\n\n\t\t\treturn [NSColor colorWithCalibratedWhite:white alpha:alpha];\n\t\t}\n\t\tcase TVCListAppearanceColorTypeRGB:\n\t\t{\n\t\t\tNSArray *components = [colorValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];\n\n\t\t\tif (components.count < 3) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tCGFloat red = [components doubleAtIndex:0];\n\t\t\tCGFloat green = [components doubleAtIndex:1];\n\t\t\tCGFloat blue = [components doubleAtIndex:2];\n\n\t\t\tCGFloat alpha = 1.0;\n\n\t\t\tif (components.count == 4) {\n\t\t\t\talpha = [components doubleAtIndex:3];\n\t\t\t}\n\n\t\t\treturn [NSColor calibratedColorWithRed:red green:green blue:blue alpha:alpha];\n\t\t}\n\t\tcase TVCListAppearanceColorTypeSystem:\n\t\t{\n\t\t\tSEL selector = NSSelectorFromString(colorValue);\n\n\t\t\tif ([NSColor respondsToSelector:selector] == NO) {\n\t\t\t\tLogToConsoleError(\"Missing color: %{public}@\", colorValue);\n\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\treturn [NSColor performSelector:selector];\n\t\t}\n\t} // switch()\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark Gradient\n\n- (nullable NSGradient *)gradientForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self gradientInGroup:group withKey:key];\n}\n\n- (nullable NSGradient *)gradientInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSArray *gradientColors = [self _valueInGroup:group withKey:key expectedType:[NSArray class]];\n\n\tif (gradientColors == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _gradientWithColors:gradientColors];\n}\n\n- (nullable NSGradient *)gradientForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self gradientInGroup:group withKey:key forActiveWindow:forActiveWindow];\n}\n\n- (nullable NSGradient *)gradientInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (referenceObject == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *gradientKey = ((forActiveWindow) ? @\"activeWindow\" : @\"inactiveWindow\");\n\n\tNSArray *gradientColors = [referenceObject arrayForKey:gradientKey];\n\n\tif (gradientColors == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _gradientWithColors:gradientColors];\n}\n\n- (nullable NSGradient *)_gradientWithColors:(NSArray<NSDictionary<NSString *, id> *> *)gradientColorsIn\n{\n\tNSParameterAssert(gradientColorsIn != nil);\n\n\tNSMutableArray<NSColor *> *gradientColorsOut = nil;\n\n\tfor (NSDictionary<NSString *, id> *color in gradientColorsIn) {\n\t\tNSColor *colorObject = [self _colorWithProperties:color];\n\n\t\tif (colorObject == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (gradientColorsOut == nil) {\n\t\t\tgradientColorsOut = [NSMutableArray array];\n\t\t}\n\n\t\t[gradientColorsOut addObject:colorObject];\n\t}\n\n\tif (gradientColorsOut == nil || gradientColorsOut.count < 2) {\n\t\treturn nil;\n\t}\n\n\treturn [[NSGradient alloc] initWithColors:gradientColorsOut];\n}\n\n#pragma mark -\n#pragma mark Font\n\n- (nullable NSFont *)fontForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self fontInGroup:group withKey:key];\n}\n\n- (nullable NSFont *)fontInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *fontProperties = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (fontProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _fontWithProperties:fontProperties];\n}\n\n- (nullable NSFont *)fontForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self fontInGroup:group withKey:key forActiveWindow:forActiveWindow];\n}\n\n- (nullable NSFont *)fontInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (referenceObject == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *fontKey = ((forActiveWindow) ? @\"activeWindow\" : @\"inactiveWindow\");\n\n\tNSDictionary *fontProperties = [referenceObject dictionaryForKey:fontKey];\n\n\tif (fontProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _fontWithProperties:fontProperties];\n}\n\n- (nullable NSFont *)_fontWithProperties:(NSDictionary<NSString *, id> *)fontProperties\n{\n\tNSParameterAssert(fontProperties != nil);\n\n\tNSString *name = [fontProperties stringForKey:@\"name\"];\n\n\tCGFloat size = [fontProperties doubleForKey:@\"size\"];\n\n\t/* Minimum font size is 5 points */\n\tif (name == nil || size < 5.0) {\n\t\treturn nil;\n\t}\n\n\tCGFloat weight = [fontProperties doubleForKey:@\"weight\"];\n\n\tif ([name isEqualToString:@\"System\"])\n\t{\n\t\treturn [NSFont systemFontOfSize:size weight:weight];\n\t}\n\telse if ([name isEqualToString:@\"SystemBold\"])\n\t{\n\t\treturn [NSFont boldSystemFontOfSize:size];\n\t}\n\telse if ([name isEqualToString:@\"SystemMonospace\"])\n\t{\n\t\treturn [NSFont monospacedDigitSystemFontOfSize:size weight:weight];\n\t}\n\telse if ([name isEqualToString:@\"SystemMonospaceBold\"])\n\t{\n\t\treturn [NSFont monospacedDigitSystemFontOfSize:size weight:NSFontWeightBold];\n\t}\n\n\tif (weight > 0) {\n\t\treturn [[NSFontManager sharedFontManager] fontWithFamily:name traits:0 weight:weight size:size];\n\t} else {\n\t\treturn [NSFont fontWithName:name size:size];\n\t}\n}\n\n#pragma mark -\n#pragma mark Image\n\n- (nullable NSImage *)imageForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self imageInGroup:group withKey:key];\n}\n\n- (nullable NSImage *)imageInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *imageProperties = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (imageProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _imageWithProperties:imageProperties];\n}\n\n- (nullable NSImage *)imageForKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self imageInGroup:group withKey:key forActiveWindow:forActiveWindow];\n}\n\n- (nullable NSImage *)imageInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key forActiveWindow:(BOOL)forActiveWindow\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (referenceObject == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *imageKey = ((forActiveWindow) ? @\"activeWindow\" : @\"inactiveWindow\");\n\n\tNSDictionary *imageProperties = [referenceObject dictionaryForKey:imageKey];\n\n\tif (imageProperties == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self _imageWithProperties:imageProperties];\n}\n\n- (nullable NSImage *)_imageWithProperties:(NSDictionary<NSString *, id> *)imageProperties\n{\n\tNSParameterAssert(imageProperties != nil);\n\n\tid imageValue = [imageProperties stringForKey:@\"value\"];\n\n\tif (imageValue == nil) {\n\t\treturn nil;\n\t}\n\n\tTVCListAppearanceImageType imageType = [imageProperties unsignedIntegerForKey:@\"type\"];\n\n\tswitch (imageType) {\n\t\tcase TVCListAppearanceImageTypeAsset:\n\t\t{\n\t\t\treturn [NSImage imageNamed:imageValue];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark Size\n\n- (NSSize)sizeForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn NSZeroSize;\n\t}\n\n\treturn [self sizeInGroup:group withKey:key];\n}\n\n- (NSSize)sizeInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSDictionary *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSDictionary class]];\n\n\tif (referenceObject == nil) {\n\t\treturn NSZeroSize;\n\t}\n\n\tCGFloat width = [referenceObject doubleForKey:@\"width\"];\n\tCGFloat height = [referenceObject doubleForKey:@\"height\"];\n\n\treturn NSMakeSize(width, height);\n}\n\n#pragma mark -\n#pragma mark Measurement\n\n- (CGFloat)measurementForKey:(NSString *)key\n{\n\tNSParameterAssert(key != nil);\n\n\tNSDictionary *group = self.appearanceProperties;\n\n\tif (group == nil) {\n\t\treturn 0;\n\t}\n\n\treturn [self measurementInGroup:group withKey:key];\n}\n\n- (CGFloat)measurementInGroup:(NSDictionary<NSString *, id> *)group withKey:(NSString *)key\n{\n\tNSParameterAssert(group != nil);\n\tNSParameterAssert(key != nil);\n\n\tNSNumber *referenceObject = [self _valueInGroup:group withKey:key expectedType:[NSNumber class]];\n\n\tif (referenceObject == nil) {\n\t\treturn 0;\n\t}\n\n\treturn referenceObject.doubleValue;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Application Appearance\n\n@interface TVCApplicationAppearance ()\n@property (nonatomic, strong) TXAppearancePropertyCollection *applicationProperties;\n@end\n\n@implementation TVCApplicationAppearance\n\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN\n- (nullable instancetype)initWithAppearanceNamed:(NSString *)appearanceName atURL:(NSURL *)appearanceLocation forRetinaDisplay:(BOOL)forRetinaDisplay\n{\n\tNSAssert(NO, @\"Use -initWithAppearanceAtURL:forRetinaDisplay: instead\");\n\n\treturn nil;\n}\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_END\n\n- (nullable instancetype)initWithAppearanceAtURL:(NSURL *)appearanceLocation forRetinaDisplay:(BOOL)forRetinaDisplay\n{\n\tNSParameterAssert(appearanceLocation != nil);\n\n\tTXAppearancePropertyCollection *applicationProperties = [TXSharedApplication sharedAppearance].properties;\n\n\tNSString *appearanceName = applicationProperties.appearanceName;\n\n\tif ((self = [super initWithAppearanceNamed:appearanceName atURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\tself.applicationProperties = applicationProperties;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (NSString *)appearanceName\n{\n\treturn self.applicationProperties.appearanceName;\n}\n\n- (TXAppearanceType)appearanceType\n{\n\treturn self.applicationProperties.appearanceType;\n}\n\n- (NSString *)shortAppearanceDescription\n{\n\treturn self.applicationProperties.shortAppearanceDescription;\n}\n\n- (BOOL)isDarkAppearance\n{\n\treturn self.applicationProperties.isDarkAppearance;\n}\n\n- (TXAppKitAppearanceTarget)appKitAppearanceTarget\n{\n\treturn self.applicationProperties.appKitAppearanceTarget;\n}\n\n- (nullable NSAppearance *)appKitAppearance\n{\n\treturn self.applicationProperties.appKitAppearance;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/TVCBasicTableView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <objc/runtime.h>\n\n#import \"TVCBasicTableView.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TVCBasicTableView\n\n#pragma mark -\n#pragma mark Table View\n\n- (BOOL)respondsToSelector:(SEL)aSelector\n{\n\t/* AppKit will stop on a response that has copy: but if we have\n\t no delegate for this method, then it's best to lie about having\n\t it in our class. */\n\tif (aSelector == @selector(copy:)) {\n\t\treturn [self.pasteboardDelegate respondsToSelector:@selector(copy:)];\n\t}\n\n\treturn class_respondsToSelector(self.class, aSelector);\n}\n\n- (void)copy:(id)sender\n{\n\t/* There is no need for a delegate response check here because it\n\t is assumed the only way we can lead to this path is if we responded\n\t to the call to -respondsToSelector: */\n\t[self.pasteboardDelegate copy:sender];\n}\n\n- (nullable NSMenu *)menuForEvent:(NSEvent *)event\n{\n\tif (self.selectedRow < 0 && self.presentMenuForEmptySelection == NO) {\n\t\treturn nil;\n\t}\n\n\treturn self.menu;\n}\n\n- (void)rightMouseDown:(NSEvent *)e\n{\n\tNSInteger rowBeneathMouse = self.rowBeneathMouse;\n\n\tif (rowBeneathMouse >= 0) {\n\t\tif ([self.selectedRowIndexes containsIndex:rowBeneathMouse] == NO) {\n\t\t\t[self selectItemAtIndex:rowBeneathMouse];\n\t\t}\n\t}\n\n\t[super rightMouseDown:e];\n}\n\n- (void)textDidEndEditing:(NSNotification *)note\n{\n\tif ([self.textEditingDelegate respondsToSelector:@selector(textDidEndEditing:)]) {\n\t\t[self.textEditingDelegate textDidEndEditing:note];\n\n\t\treturn;\n\t}\n\n\t[super textDidEndEditing:note];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/TVCContentNavigationOutlineView.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSViewHelper.h\"\n#import \"TVCContentNavigationOutlineViewPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCContentNavigationOutlineView () <NSOutlineViewDelegate, NSOutlineViewDataSource>\n@property (nonatomic, strong) IBOutlet NSView *contentView;\n@property (nonatomic, weak, nullable, readwrite) TVCContentNavigationOutlineViewItem *selectedItem;\n@property (nonatomic, weak, nullable) TVCContentNavigationOutlineViewItem *lastSelection;\n@property (readonly, nullable) TVCContentNavigationOutlineViewItem *parentOfLastSelection;\n@end\n\n@implementation TVCContentNavigationOutlineView\n\n#pragma mark -\n#pragma mark Basic Class\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\tself.dataSource = (id)self;\n\tself.delegate = (id)self;\n\n\tself.doubleAction = @selector(outlineViewDoubleClicked:);\n}\n\n- (void)setNavigationTreeMatrix:(NSArray<TVCContentNavigationOutlineViewItem *> *)navigationTreeMatrix\n{\n\tNSParameterAssert(navigationTreeMatrix != nil);\n\n\tif (self->_navigationTreeMatrix != navigationTreeMatrix) {\n\t\tself->_navigationTreeMatrix = navigationTreeMatrix;\n\n\t\t[self resetOutlineView];\n\t}\n}\n\n- (void)resetOutlineView\n{\n\tself.lastSelection = nil;\n\n\tself.selectedItem = nil;\n\n\t[self reloadData];\n}\n\n- (void)navigateToItemWithIdentifier:(NSUInteger)identifier\n{\n\tfor (TVCContentNavigationOutlineViewItem *groupItem in self.groupItems) {\n\t\tif (groupItem.identifier == identifier) {\n\t\t\t[self selectItemAtIndex:[self rowForItem:groupItem]];\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor (TVCContentNavigationOutlineViewItem *childItem in groupItem.children) {\n\t\t\tif (childItem.identifier == identifier) {\n\t\t\t\t[self selectItemAtIndex:[self rowForItem:childItem]];\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t} // children\n\t} // parents\n}\n\n- (nullable TVCContentNavigationOutlineViewItem *)parentOfLastSelection\n{\n\tTVCContentNavigationOutlineViewItem *selectedItem = self.lastSelection;\n\n\tif (selectedItem == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self parentForItem:selectedItem];\n}\n\n#pragma mark -\n#pragma mark Collapse/Expand Logic\n\n- (void)outlineViewDoubleClicked:(id)sender\n{\n\tif (self.expandParentOnDoubleClick == NO) {\n\t\treturn;\n\t}\n\n\tNSInteger clickedRow = self.clickedRow;\n\n\tif (clickedRow < 0) {\n\t\treturn;\n\t}\n\n\tTVCContentNavigationOutlineViewItem *itemAtRow = [self itemAtRow:clickedRow];\n\n\tif (itemAtRow.isGroupItem == NO) {\n\t\treturn;\n\t}\n\n\t[self expandItem:itemAtRow];\n}\n\n#pragma mark -\n#pragma mark NSOutlineViewDelegate Delegates\n\n- (NSInteger)outlineView:(NSOutlineView *)sender numberOfChildrenOfItem:(nullable TVCContentNavigationOutlineViewItem *)item\n{\n\tif (item.isGroupItem) {\n\t\treturn item.children.count;\n\t}\n\n\treturn self.navigationTreeMatrix.count;\n}\n\n- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(nullable TVCContentNavigationOutlineViewItem *)item\n{\n\tif (item.isGroupItem) {\n\t\treturn item.children[index];\n\t}\n\n\treturn self.navigationTreeMatrix[index];\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldCollapseItem:(TVCContentNavigationOutlineViewItem *)item\n{\n\treturn YES;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)sender isItemExpandable:(TVCContentNavigationOutlineViewItem *)item\n{\n\treturn item.isGroupItem;\n}\n\n- (void)outlineViewItemDidExpand:(NSNotification *)notification\n{\n\tTVCContentNavigationOutlineViewItem *parentItem = self.parentOfLastSelection;\n\n\tTVCContentNavigationOutlineViewItem *itemExpanded = notification.userInfo[@\"NSObject\"];\n\n\tif (parentItem == nil || parentItem != itemExpanded) {\n\t\treturn;\n\t}\n\n\tNSInteger childIndex = [self rowForItem:self.lastSelection];\n\n\tif (childIndex >= 0) {\n\t\t[self selectItemAtIndex:childIndex];\n\t}\n}\n\n- (nullable id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable TVCContentNavigationOutlineViewItem *)item\n{\n\treturn item.label;\n}\n\n- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(TVCContentNavigationOutlineViewItem *)item\n{\n\treturn (item.view != nil);\n}\n\n- (nullable id)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(nullable NSTableColumn *)tableColumn item:(id)item\n{\n\tNSTableCellView *newView = [outlineView makeViewWithIdentifier:@\"navEntry\" owner:self];\n\n\treturn newView;\n}\n\n- (void)outlineViewSelectionDidChange:(NSNotification *)notification\n{\n\tNSInteger selectedRow = self.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\t/* We do not reset -lastSelection because that is used\n\t\t to restore selection to item when the group item that\n\t\t was collapsed is expanded. */\n\t\tself.selectedItem = nil;\n\n\t\treturn;\n\t}\n\n\tTVCContentNavigationOutlineViewItem *item = [self itemAtRow:selectedRow];\n\n\tself.selectedItem = item;\n\n\tself.lastSelection = item;\n\n\t[self presentView:item.view];\n\n\tid firstResponder = item.firstResponder;\n\n\tif (firstResponder) {\n\t\t[self.window makeFirstResponder:firstResponder];\n\t}\n}\n\n- (void)presentView:(NSView *)newView\n{\n\t[self.contentView replaceFirstSubview:newView];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Item Parent\n\n@interface TVCContentNavigationOutlineViewItem ()\n@property (nonatomic, copy, readwrite) NSString *label;\n@property (nonatomic, assign, readwrite) NSUInteger identifier;\n@property (nonatomic, weak, nullable, readwrite) NSView *view;\n@property (nonatomic, weak, nullable, readwrite) NSControl *firstResponder;\n@property (nonatomic, copy, nullable, readwrite) NSArray<TVCContentNavigationOutlineViewItem *> *children;\n@end\n\n@implementation TVCContentNavigationOutlineViewItem\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithLabel:(NSString *)label identifier:(NSUInteger)identifier view:(NSView *)view firstResponder:(nullable NSControl *)firstResponder\n{\n\tNSParameterAssert(label != nil);\n\tNSParameterAssert(view != nil);\n\n\treturn [self initWithLabel:label identifier:identifier view:view firstResponder:firstResponder children:nil];\n}\n\n- (instancetype)initWithLabel:(NSString *)label identifier:(NSUInteger)identifier view:(nullable NSView *)view firstResponder:(nullable NSControl *)firstResponder children:(nullable NSArray<TVCContentNavigationOutlineViewItem *> *)children\n{\n\tNSParameterAssert(label != nil);\n\tNSParameterAssert(view != nil || children != nil);\n\n\tif ((self = [super init])) {\n\t\tself.label = label;\n\t\tself.identifier = identifier;\n\t\tself.view = view;\n\t\tself.firstResponder = firstResponder;\n\t\tself.children = children;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)isGroupItem\n{\n\treturn (self.children != nil);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/TVCDockIcon.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TXMasterController.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCClient.h\"\n#import \"IRCChannel.h\"\n#import \"IRCWorld.h\"\n#import \"TVCDockIconPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _badgeSeperationSpace\t\t1.0\n\n@implementation TVCDockIcon\n\nstatic NSInteger _cachedHighlightCount = (-1);\nstatic NSInteger _cachedMessageCount = (-1);\n\n+ (void)updateDockIcon\n{\n\tif ([TPCPreferences displayDockBadge] == NO) {\n\t\treturn;\n\t}\n\n\tNSUInteger highlightCount = 0;\n\tNSUInteger messageCount = 0;\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\tif (c.config.pushNotifications) {\n\t\t\t\tmessageCount += c.dockUnreadCount;\n\t\t\t}\n\n\t\t\thighlightCount += c.nicknameHighlightCount;\n\t\t}\n\t}\n\n\tif (messageCount == 0 && highlightCount == 0) {\n\t\t[self drawWithoutCount];\n\t} else {\n\t\t[self drawWithHighlightCount:highlightCount messageCount:messageCount];\n\t}\n}\n\n+ (NSImage *)applicationIcon\n{\n\t/* THIS IS A SECRET!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\t Birthday icon designed by Alex Sørlie Glomsaas. */\n\n\tNSCalendar *sysCalendar = [NSCalendar currentCalendar];\n\n\tNSDateComponents *breakdownInfo = [sysCalendar components:(NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];\n\n\t/* The first public commit of Textual occurred on July, 23, 2010. This is the day\n\t that we consider the birthday of the application. */\n\tif (breakdownInfo.month == 7 && breakdownInfo.day == 23) {\n\t\treturn [NSImage imageNamed:@\"applicationIconBirthday\"];\n\t} else {\n\t\treturn [NSImage imageNamed:@\"NSApplicationIcon\"];\n\t}\n}\n\n+ (void)resetCachedCount\n{\n\t_cachedMessageCount = (-1);\n\t_cachedHighlightCount = (-1);\n}\n\n+ (void)drawWithoutCount\n{\n\tif (_cachedHighlightCount == 0 && _cachedMessageCount == 0) {\n\t\treturn;\n\t}\n\n\t_cachedMessageCount = 0;\n\t_cachedHighlightCount = 0;\n\n\t[NSApp setApplicationIconImage:[self applicationIcon]];\n}\n\n+ (void)drawWithHighlightCount:(NSUInteger)highlightCount messageCount:(NSUInteger)messageCount\n{\n\tif (_cachedHighlightCount == highlightCount && _cachedMessageCount == messageCount) {\n\t\treturn;\n\t}\n\n\t_cachedHighlightCount = highlightCount;\n\t_cachedMessageCount = messageCount;\n\n\tif (messageCount > 9999) {\n\t\tmessageCount = 9999;\n\t}\n\n\tif (highlightCount > 9999) {\n\t\thighlightCount = 9999;\n\t}\n\n\tBOOL showRedBadge = (messageCount >= 1);\n\tBOOL showGreenBadge = (highlightCount >= 1);\n\n\t/* ////////////////////////////////////////////////////////// */\n\t/* Define Text Drawing Globals */\n\t/* ////////////////////////////////////////////////////////// */\n\n\tNSSize badgeTextSize = NSZeroSize;\n\n\tNSMutableAttributedString *badgeText = [NSMutableAttributedString alloc];\n\n\tCGFloat badgeTextFrameCorrection = 2.0;\n\n\tNSDictionary *badgeTextAttributes = @{\n\t\tNSFontAttributeName\t\t\t\t: [NSFont fontWithName:@\"Helvetica\" size:24.0],\n\t\tNSForegroundColorAttributeName\t: [NSColor whiteColor]\n\t};\n\n\t/* ////////////////////////////////////////////////////////// */\n\t/* Load Drawing Images */\n\t/* ////////////////////////////////////////////////////////// */\n\n\tNSImage *appIcon = [[self applicationIcon] copy];\n\n\tNSImage *redBadgeLeft = [NSImage imageNamed:@\"DIRedBadgeLeft.png\"];\n\tNSImage *redBadgeCenter = [NSImage imageNamed:@\"DIRedBadgeCenter.png\"];\n\tNSImage *redBadgeRight = [NSImage imageNamed:@\"DIRedBadgeRight.png\"];\n\n\tNSImage *greenBadgeLeft = [NSImage imageNamed:@\"DIGreenBadgeLeft.png\"];\n\tNSImage *greenBadgeCenter = [NSImage imageNamed:@\"DIGreenBadgeCenter.png\"];\n\tNSImage *greenBadgeRight = [NSImage imageNamed:@\"DIGreenBadgeRight.png\"];\n\n\t/* ////////////////////////////////////////////////////////// */\n\t/* Build Scaling Frames */\n\t/* ////////////////////////////////////////////////////////// */\n\n\tNSRect redBadgeLeftFrame, greenBadgeLeftFrame;\n\tNSRect redBadgeRightFrame, greenBadgeRightFrame;\n\tNSRect redBadgeCenterFrame, greenBadgeCenterFrame;\n\n\t[appIcon lockFocus];\n\n\t/* Red Badge Size */\n\tredBadgeRightFrame.size.height = 53.0;\n\tredBadgeCenterFrame.size.height = 53.0;\n\tredBadgeLeftFrame.size.height = 53.0;\n\n\tredBadgeLeftFrame.size.width = 27.0;\n\tredBadgeCenterFrame.size.width = [self badgeCenterTileWidth:messageCount];\n\tredBadgeRightFrame.size.width = 26.0;\n\n\t/* Green Badge Size */\n\tgreenBadgeRightFrame.size.height = 53.0;\n\tgreenBadgeCenterFrame.size.height = 53.0;\n\tgreenBadgeLeftFrame.size.height\t= 53.0;\n\n\tgreenBadgeLeftFrame.size.width = 27.0;\n\tgreenBadgeCenterFrame.size.width = [self badgeCenterTileWidth:highlightCount];\n\tgreenBadgeRightFrame.size.width\t= 26.0;\n\n\t/* ////////////////////////////////////////////////////////// */\n\n\t/* If there is no red badge, then the green one is drawn in the same\n\t position of the red at the top right of the icon. The following is the\n\t math required to position it correctly relative to the icon. If the\n\t red icon does exist in this drawing, then we will update these points\n\t of origin later on in the drawing. For now, assume it is at the top. */\n\n\t/* Green Badge Drawing Position */\n\tgreenBadgeLeftFrame.origin =\n\tNSMakePoint((appIcon.size.width - (greenBadgeRightFrame.size.width +\n\t\t\t\t\t\t\t\t\t   greenBadgeCenterFrame.size.width +\n\t\t\t\t\t\t\t\t\t   greenBadgeLeftFrame.size.width)), // End X Axis\n\t\t\t\t(appIcon.size.height - greenBadgeRightFrame.size.height));\n\n\tgreenBadgeCenterFrame.origin =\n\tNSMakePoint((appIcon.size.width - (greenBadgeRightFrame.size.width +\n\t\t\t\t\t\t\t\t\t   greenBadgeCenterFrame.size.width)), // End X Axis\n\t\t\t\t(appIcon.size.height - greenBadgeRightFrame.size.height));\n\n\tgreenBadgeRightFrame.origin =\n\tNSMakePoint((appIcon.size.width - greenBadgeRightFrame.size.width), // End X Axis\n\t\t\t\t(appIcon.size.height - greenBadgeRightFrame.size.height));\n\n\t/* Update origin if red badge will be drawn */\n\tif (showRedBadge) {\n\t\tgreenBadgeLeftFrame.origin.y =\n\t\t(appIcon.size.height - (greenBadgeLeftFrame.size.height +\n\t\t\t\t\t\t\t\tredBadgeLeftFrame.size.height +\n\t\t\t\t\t\t\t\t_badgeSeperationSpace));\n\n\t\tgreenBadgeCenterFrame.origin.y =\n\t\t(appIcon.size.height - (greenBadgeCenterFrame.size.height +\n\t\t\t\t\t\t\t\tredBadgeCenterFrame.size.height +\n\t\t\t\t\t\t\t\t_badgeSeperationSpace));\n\n\t\tgreenBadgeRightFrame.origin.y =\n\t\t(appIcon.size.height - (greenBadgeRightFrame.size.height +\n\t\t\t\t\t\t\t\tredBadgeRightFrame.size.height +\n\t\t\t\t\t\t\t\t_badgeSeperationSpace));\n\t}\n\n\t/* Red Badge Drawing Position */\n\tredBadgeLeftFrame.origin =\n\tNSMakePoint((appIcon.size.width - (redBadgeRightFrame.size.width +\n\t\t\t\t\t\t\t\t\t   redBadgeCenterFrame.size.width +\n\t\t\t\t\t\t\t\t\t   redBadgeLeftFrame.size.width)), // End X Axis\n\t\t\t\t(appIcon.size.height - redBadgeRightFrame.size.height));\n\n\tredBadgeCenterFrame.origin =\n\tNSMakePoint((appIcon.size.width - (redBadgeRightFrame.size.width +\n\t\t\t\t\t\t\t\t\t   redBadgeCenterFrame.size.width)), // End X Axis\n\t\t\t\t(appIcon.size.height - redBadgeRightFrame.size.height));\n\n\tredBadgeRightFrame.origin =\n\tNSMakePoint((appIcon.size.width - redBadgeRightFrame.size.width), // End X Axis\n\t\t\t\t(appIcon.size.height - redBadgeRightFrame.size.height));\n\n\t/* ////////////////////////////////////////////////////////// */\n\t/* Draw Badges */\n\t/* ////////////////////////////////////////////////////////// */\n\n\t/* Red Badge */\n\tif (showRedBadge) {\n\t\t[redBadgeLeft drawInRect:redBadgeLeftFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\t\t[redBadgeCenter drawInRect:redBadgeCenterFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\t\t[redBadgeRight drawInRect:redBadgeRightFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\n\t\t/* Red Badge Text */\n\t\tbadgeText = [badgeText initWithString:[NSString stringWithInteger:messageCount] attributes:badgeTextAttributes];\n\n\t\tbadgeTextSize = [badgeText size];\n\n\t\tCGFloat redBadgeTotalWidth = (redBadgeLeftFrame.size.width +\n\t\t\t\t\t\t\t\t\t  redBadgeCenterFrame.size.width +\n\t\t\t\t\t\t\t\t\t  redBadgeRightFrame.size.width);\n\n\t\tCGFloat redBadgeTotalHeight = redBadgeCenterFrame.size.height;\n\n\t\tCGFloat redBadgeWidthCenter  = ((redBadgeTotalWidth - badgeTextSize.width) / 2.0);\n\t\tCGFloat redBadgeHeightCenter = ((redBadgeTotalHeight - badgeTextSize.height) / 2.0);\n\n\t\tNSPoint badgeTextDrawPath =\n\t\tNSMakePoint((appIcon.size.width - redBadgeTotalWidth + redBadgeWidthCenter),\n\t\t\t\t\t(appIcon.size.height - redBadgeTotalHeight + redBadgeHeightCenter + badgeTextFrameCorrection));\n\n\t\t[badgeText drawAtPoint:badgeTextDrawPath];\n\t}\n\n\tif (showGreenBadge) {\n\t\t/* Green Badge */\n\t\t[greenBadgeLeft\tdrawInRect:greenBadgeLeftFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\t\t[greenBadgeCenter drawInRect:greenBadgeCenterFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\t\t[greenBadgeRight drawInRect:greenBadgeRightFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];\n\n\t\t/* Green Badge Text */\n\t\tbadgeText = [badgeText initWithString:[NSString stringWithInteger:highlightCount] attributes:badgeTextAttributes];\n\n\t\tbadgeTextSize = [badgeText size];\n\n\t\tCGFloat greenBadgeTotalWidth = (greenBadgeLeftFrame.size.width +\n\t\t\t\t\t\t\t\t\t\tgreenBadgeCenterFrame.size.width +\n\t\t\t\t\t\t\t\t\t\tgreenBadgeRightFrame.size.width);\n\n\t\tCGFloat greenBadgeTotalHeight = greenBadgeCenterFrame.size.height;\n\n\t\tCGFloat greenBadgeWidthCenter  = ((greenBadgeTotalWidth - badgeTextSize.width) / 2.0);\n\t\tCGFloat greenBadgeHeightCenter = ((greenBadgeTotalHeight - badgeTextSize.height) / 2.0);\n\n\t\tNSPoint badgeTextDrawPath =\n\t\tNSMakePoint((appIcon.size.width - greenBadgeTotalWidth + greenBadgeWidthCenter),\n\t\t\t\t\t(appIcon.size.height - greenBadgeTotalHeight + greenBadgeHeightCenter + badgeTextFrameCorrection));\n\n\t\tif (showRedBadge) {\n\t\t\tbadgeTextDrawPath.y -= (redBadgeCenterFrame.size.height + _badgeSeperationSpace);\n\t\t}\n\n\t\t[badgeText drawAtPoint:badgeTextDrawPath];\n\t}\n\n\t/* ////////////////////////////////////////////////////////// */\n\t/* Finish Icon */\n\t/* ////////////////////////////////////////////////////////// */\n\n\t[appIcon unlockFocus];\n\n\t[NSApp setApplicationIconImage:appIcon];\n}\n\n+ (CGFloat)badgeCenterTileWidth:(NSUInteger)badgeCount\n{\n\tswitch (badgeCount) {\n\t\tcase 1 ... 9:\n\t\t{\n\t\t\treturn 1.0;\n\t\t}\n\t\tcase 10 ... 99:\n\t\t{\n\t\t\treturn 1.0;\n\t\t}\n\t\tcase 100 ... 999:\n\t\t{\n\t\t\treturn 18.0;\n\t\t}\n\t\tcase 1000 ... 9999:\n\t\t{\n\t\t\treturn 28.0;\n\t\t}\n\t}\n\n\treturn 1.0;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/User List/TVCMemberList.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCUser.h\"\n#import \"IRCChannelUser.h\"\n#import \"IRCChannelMemberListControllerPrivate.h\"\n#import \"NSViewHelperPrivate.h\"\n#import \"TXMasterController.h\"\n#import \"TXMenuControllerPrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"TVCMemberListCellPrivate.h\"\n#import \"TVCMemberListAppearancePrivate.h\"\n#import \"TVCMemberListUserInfoPopoverPrivate.h\"\n#import \"TVCMemberListPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TVCMemberListDragType = @\"TVCMemberListDragType\";\n\n@interface TVCMemberList ()\n@property (nonatomic, strong) id userPopoverTrackingArea;\n@property (nonatomic, assign) BOOL userPopoverMouseIsInView;\n@property (nonatomic, assign) BOOL userPopoverTimerIsActive;\n@property (nonatomic, assign) NSPoint userPopoverLastKnownLocalPoint;\n@property (nonatomic, assign) NSInteger lastRowShownUserInfoPopover;\n@property (nonatomic, strong, readwrite) TVCMemberListAppearance *userInterfaceObjects;\n@property (nonatomic, weak, readwrite) IBOutlet NSVisualEffectView *visualEffectView;\n@property (nonatomic, strong, readwrite) IBOutlet TVCMemberListUserInfoPopover *memberListUserInfoPopover;\n@property (nonatomic, strong, readwrite) IBOutlet IRCChannelMemberListController *contentController;\n@end\n\n@implementation TVCMemberList\n\n- (void)awakeFromNib\n{\n\t[super awakeFromNib];\n\n\t[self updateTrackingAreas];\n\n\t[self registerForDraggedTypes:@[NSFilenamesPboardType]];\n}\n\n- (void)viewDidMoveToWindow\n{\n\t[super viewDidMoveToWindow];\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tif (mainWindow == nil) {\n\t\t[RZNotificationCenter() removeObserver:self];\n\n\t\treturn;\n\t}\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(windowDidBecomeKey:)\n\t\t\t\t\t\t\t\t   name:NSWindowDidBecomeKeyNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(windowDidResignKey:)\n\t\t\t\t\t\t\t\t   name:NSWindowDidResignKeyNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(mainWindowRequiresRedraw:)\n\t\t\t\t\t\t\t\t   name:TVCMainWindowRedrawSubviewsNotification\n\t\t\t\t\t\t\t\t object:mainWindow];\n\n\t[RZNotificationCenter() addObserver:self\n\t\t\t\t\t\t\t   selector:@selector(scrollViewBoundsDidChangeNotification:)\n\t\t\t\t\t\t\t\t   name:NSViewBoundsDidChangeNotification\n\t\t\t\t\t\t\t\t object:[self scrollViewContentView]];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)assignToChannel:(nullable IRCChannel *)channel\n{\n\t[self.contentController assignToChannel:channel];\n}\n\n- (nullable id)itemAtRow:(NSInteger)row\n{\n\tNSParameterAssert(row >= 0);\n\n\tNSArray *rows = self.contentController.arrangedObjects;\n\n\tif (row >= rows.count) {\n\t\treturn nil;\n\t}\n\n\treturn rows[row];\n}\n\n- (NSInteger)rowForItem:(nullable id)item\n{\n\tif (item == nil) {\n\t\treturn (-1);\n\t}\n\n\tNSArray *rows = self.contentController.arrangedObjects;\n\n\tNSInteger index = [rows indexOfObjectIdenticalTo:item];\n\n\tif (index == NSNotFound) {\n\t\treturn (-1);\n\t}\n\n\treturn index;\n}\n\n#pragma mark -\n#pragma mark Mouse Tracking\n\n- (void)updateTrackingAreas\n{\n\t[super updateTrackingAreas];\n\n\tif (self.userPopoverTrackingArea) {\n\t\t[self removeTrackingArea:self.userPopoverTrackingArea];\n\t}\n\n\tself.userPopoverTrackingArea =\n\t[[NSTrackingArea alloc] initWithRect:self.frame\n\t\t\t\t\t\t\t\t options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInActiveApp)\n\t\t\t\t\t\t\t\t   owner:self\n\t\t\t\t\t\t\t\tuserInfo:nil];\n\n\t[self addTrackingArea:self.userPopoverTrackingArea];\n}\n\n- (void)destroyUserInfoPopoverOnWindowKeyChange\n{\n\t[self destroyUserInfoPopover]; // Destroy anything shown\n}\n\n- (void)destroyUserInfoPopover\n{\n\t[self cancelPerformRequestsWithSelector:@selector(popDelayedUserInfoExpansionFrame) object:nil];\n\n\tself.lastRowShownUserInfoPopover = (-1);\n\n\tself.userPopoverMouseIsInView = NO;\n\tself.userPopoverTimerIsActive = NO;\n\n\tself.userPopoverLastKnownLocalPoint = NSZeroPoint;\n\n\tif (self.memberListUserInfoPopover.shown) {\n\t\t[self.memberListUserInfoPopover close];\n\t}\n}\n\n- (void)mouseEntered:(NSEvent *)theEvent\n{\n\tself.userPopoverMouseIsInView = YES;\n\n\tif (self.userPopoverTimerIsActive == NO) {\n\t\tself.userPopoverTimerIsActive = YES;\n\n\t\t[self performSelector:@selector(popDelayedUserInfoExpansionFrame) withObject:nil afterDelay:1.0];\n\t}\n}\n\n- (void)mouseExited:(NSEvent *)theEvent\n{\n\t[self destroyUserInfoPopover];\n}\n\n- (void)mouseMoved:(NSEvent *)theEvent\n{\n\tNSPoint localPoint = [self convertPoint:theEvent.locationInWindow fromView:nil];\n\n\t[self popUserInfoExpansionFrameAtPoint:localPoint ignoreTimerCheck:NO];\n}\n\n- (void)popUserInfoExpansionFrameAtPoint:(NSPoint)localPoint ignoreTimerCheck:(BOOL)ignoreTimer\n{\n\tself.userPopoverLastKnownLocalPoint = localPoint;\n\n\tif ([XRAccessibility isVoiceOverEnabled]) {\n\t\treturn;\n\t}\n\n\tif (self.userPopoverTimerIsActive && ignoreTimer == NO) {\n\t\treturn; // Only allow the timer to pop it\n\t}\n\n\tif (self.window.keyWindow == NO) {\n\t\treturn;\n\t}\n\n\tNSInteger row = [self rowAtPoint:localPoint];\n\n\tif (row < 0) {\n\t\treturn;\n\t}\n\n\tif (self.lastRowShownUserInfoPopover != row) {\n\t\tself.lastRowShownUserInfoPopover = row;\n\n\t\tid rowView = [self viewAtColumn:0 row:row makeIfNecessary:NO];\n\n\t\t[rowView drawWithExpansionFrame];\n\t}\n}\n\n- (void)popDelayedUserInfoExpansionFrame\n{\n\t/* Basically we delay the expansion frame (also known as the popover)\n\t by one second from the time the user enters the frame so that if they\n\t are just moving the mouse through it to another portion of the window\n\t we do not try to show a popover. We only want to show a popover if the\n\t user has some intention of being in the list. */\n\n\tif (self.userPopoverMouseIsInView) {\n\t\t[self popUserInfoExpansionFrameAtPoint:self.userPopoverLastKnownLocalPoint ignoreTimerCheck:YES];\n\t}\n\n\tself.userPopoverTimerIsActive = NO;\n}\n\n#pragma mark -\n#pragma mark Scroll View\n\n- (void)scrollViewBoundsDidChangeNotification:(NSNotification *)notification\n{\n\tif ([TPCPreferences memberListUpdatesUserInfoPopoverOnScroll] == NO) {\n\t\treturn;\n\t}\n\n\tif (notification.object != [self scrollViewContentView]) {\n\t\treturn;\n\t}\n\n\tNSPoint mouseLocation = [NSEvent mouseLocation];\n\n\tNSRect mouseLocationFaked = NSMakeRect(mouseLocation.x, mouseLocation.y, 1.0, 1.0);\n\n\tNSRect remotePoint = [self.window convertRectFromScreen:mouseLocationFaked];\n\n\tNSPoint localPoint = [self convertPoint:remotePoint.origin fromView:nil];\n\n\t[self popUserInfoExpansionFrameAtPoint:localPoint ignoreTimerCheck:YES];\n}\n\n- (id)scrollViewContentView\n{\n\treturn self.enclosingScrollView.contentView;\n}\n\n#pragma mark -\n#pragma mark Drag and Drop\n\n- (NSInteger)draggedRow:(id <NSDraggingInfo>)sender\n{\n\tNSPoint p = [self convertPoint:[sender draggingLocation] fromView:nil];\n\n\treturn [self rowAtPoint:p];\n}\n\n- (NSArray *)draggedFiles:(id <NSDraggingInfo>)sender\n{\n\treturn [[sender draggingPasteboard] propertyListForType:NSFilenamesPboardType];\n}\n\n- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender\n{\n\treturn [self draggingUpdated:sender];\n}\n\n- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender\n{\n\tNSArray *files = [self draggedFiles:sender];\n\n\tif (files.count > 0 && [self draggedRow:sender] >= 0) {\n\t\treturn NSDragOperationCopy;\n\t} else {\n\t\treturn NSDragOperationNone;\n\t}\n}\n\n- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender\n{\n\tNSArray *files = [self draggedFiles:sender];\n\n\treturn (files.count > 0 && [self draggedRow:sender] >= 0);\n}\n\n- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender\n{\n\tNSArray *files = [self draggedFiles:sender];\n\n\tif (files.count > 0) {\n\t\tNSInteger row = [self draggedRow:sender];\n\n\t\tif (row >= 0) {\n\t\t\t[menuController() memberSendDroppedFiles:files row:row];\n\n\t\t\treturn YES;\n\t\t}\n\t}\n\n\treturn NO;\n}\n\n#pragma mark -\n#pragma mark Drawing Updates\n\n- (void)refreshAllDrawings\n{\n\t[self refreshAllDrawings:NO];\n}\n\n- (void)refreshAllDrawings:(BOOL)skipOcclusionCheck\n{\n\tfor (NSUInteger i = 0; i < self.numberOfRows; i++) {\n\t\t[self refreshDrawingForRow:i skipOcclusionCheck:skipOcclusionCheck];\n\t}\n}\n- (void)refreshDrawingForRows:(NSIndexSet *)rowIndexes\n{\n\t[self refreshDrawingForRows:rowIndexes skipOcclusionCheck:NO];\n}\n\n- (void)refreshDrawingForRows:(NSIndexSet *)rowIndexes skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tNSParameterAssert(rowIndexes != nil);\n\n\t[rowIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) {\n\t\t[self refreshDrawingForRow:index skipOcclusionCheck:skipOcclusionCheck];\n\t}];\n}\n\n- (void)refreshDrawingForRow:(NSInteger)rowIndex\n{\n\t[self refreshDrawingForRow:rowIndex skipOcclusionCheck:NO];\n}\n\n- (void)refreshDrawingForRow:(NSInteger)rowIndex skipOcclusionCheck:(BOOL)skipOcclusionCheck\n{\n\tif (rowIndex < 0) {\n\t\treturn;\n\t}\n\n\tif (skipOcclusionCheck == NO && self.mainWindow.occluded) {\n\t\treturn;\n\t}\n\n\tTVCMemberListCell *rowView = [self viewAtColumn:0 row:rowIndex makeIfNecessary:NO];\n\n\trowView.needsDisplay = YES;\n}\n\n- (void)refreshDrawingForMember:(IRCChannelUser *)cellItem\n{\n\tNSParameterAssert(cellItem != nil);\n\n\tNSInteger rowIndex = [self rowForItem:cellItem];\n\n\t[self refreshDrawingForRow:rowIndex];\n}\n\n- (void)refreshDrawingForChangesToPreference:(NSString *)preferenceKey\n{\n\tstatic NSDictionary<NSString *, NSNumber *> *preferenceMap = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tpreferenceMap = @{\n\t\t\t@\"User List Mode Badge Colors -> +y\" : @(IRCUserRankIRCopByMode),\n\t\t\t@\"User List Mode Badge Colors -> +q\" : @(IRCUserRankChannelOwner),\n\t\t\t@\"User List Mode Badge Colors -> +a\" : @(IRCUserRankSuperOperator),\n\t\t\t@\"User List Mode Badge Colors -> +o\" : @(IRCUserRankNormalOperator),\n\t\t\t@\"User List Mode Badge Colors -> +h\" : @(IRCUserRankHalfOperator),\n\t\t\t@\"User List Mode Badge Colors -> +v\" : @(IRCUserRankVoiced),\n\t\t\t@\"User List Mode Badge Colors -> no mode\" : @(IRCUserRankNone)\n\t\t};\n\t});\n\n\tNSNumber *rank = preferenceMap[preferenceKey];\n\n\tif (rank == nil) {\n\t\treturn;\n\t}\n\n\tIRCUserRank rankEnum = rank.unsignedIntegerValue;\n\n\t[self refreshDrawingForMembersWithRank:rankEnum isIRCop:(rankEnum == IRCUserRankIRCopByMode)];\n}\n\n- (void)refreshDrawingForMembersWithRank:(IRCUserRank)rank isIRCop:(BOOL)isIRCop\n{\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\tNSArray *rows = self.contentController.arrangedObjects;\n\n\t[rows enumerateObjectsUsingBlock:^(IRCChannelUser *member, NSUInteger index, BOOL *stop) {\n\t\tif ((member.ranks & rank) == 0 && (isIRCop && isIRCop != member.user.isIRCop)) {\n\t\t\treturn;\n\t\t}\n\n\t\t[appearance invalidateUserMarkBadgeCacheForSymbol:member.mark rank:rank];\n\n\t\t[self refreshDrawingForRow:index];\n\t}];\n}\n\n- (void)drawContextMenuHighlightForRow:(int)row\n{\n\t// Do not draw focus ring ...\n}\n\n- (BOOL)allowsVibrancy\n{\n\treturn YES;\n}\n\n- (void)updateVibrancyWithAppearance:(TVCMemberListAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\tNSVisualEffectView *visualEffectView = self.visualEffectView;\n\n\tif ([TPCPreferences disableSidebarTranslucency]) {\n\t\tvisualEffectView.state = NSVisualEffectStateInactive;\n\t} else {\n\t\tvisualEffectView.state = NSVisualEffectStateFollowsWindowActiveState;\n\t}\n\n\tvisualEffectView.material = NSVisualEffectMaterialSidebar;\n}\n\n- (void)applicationAppearanceChanged\n{\n\tTVCMemberListAppearance *appearance = self.mainWindow.userInterfaceObjects.memberList;\n\n\t[self _updateAppearance:appearance];\n\n\t[self invalidateBackgroundForSelection];\n\n\t[self refreshAllDrawings:YES];\n}\n\n- (void)systemAppearanceChanged\n{\n//\t[self invalidateBackgroundForSelection];\n}\n\n- (void)_updateAppearance:(TVCMemberListAppearance *)appearance\n{\n\tNSParameterAssert(appearance != nil);\n\n\t/* We assign a strong reference to these instead of returning the original\n\t value every time so that there are no race conditions for when it changes. */\n\tself.userInterfaceObjects = appearance;\n\n\t[self updateVibrancyWithAppearance:appearance];\n\n\tif (appearance.isDarkAppearance) {\n\t\tself.enclosingScrollView.scrollerKnobStyle = NSScrollerKnobStyleLight;\n\t} else {\n\t\tself.enclosingScrollView.scrollerKnobStyle = NSScrollerKnobStyleDark;\n\t}\n\n\tself.needsDisplay = YES;\n}\n\n- (void)windowDidBecomeKey:(NSNotification *)notification\n{\n\t[self windowKeyStateChanged:notification];\n}\n\n- (void)windowDidResignKey:(NSNotification *)notification\n{\n\t[self destroyUserInfoPopoverOnWindowKeyChange];\n\n\t[self windowKeyStateChanged:notification];\n}\n\n- (void)windowKeyStateChanged:(NSNotification *)notification\n{\n\t[self respondToRequiresRedraw];\n}\n\n- (void)mainWindowRequiresRedraw:(NSNotification *)notification\n{\n\t[self respondToRequiresRedraw];\n}\n\n- (void)respondToRequiresRedraw\n{\n\t[self refreshAllDrawings:YES];\n}\n\n#pragma mark -\n#pragma mark Events\n\n- (nullable NSMenu *)menuForEvent:(NSEvent *)theEvent\n{\n\tNSInteger rowBeneathMouse = self.rowBeneathMouse;\n\n\tif (rowBeneathMouse >= 0) {\n\t\tif ([self.selectedRowIndexes containsIndex:rowBeneathMouse] == NO) {\n\t\t\t[self selectItemAtIndex:rowBeneathMouse];\n\t\t}\n\n\t\treturn menuController().userControlMenu;\n\t}\n\n\treturn nil;\n}\n\n- (void)keyDown:(NSEvent *)e\n{\n\tif (self.keyDelegate == nil) {\n\t\treturn;\n\t}\n\n\tswitch (e.keyCode) {\n\t\tcase 125: // down arrow\n\t\tcase 126: // up arrow\n\t\t{\n\t\t\t[super keyDown:e];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase 123: // left arrow\n\t\tcase 124: // right arrow\n\t\tcase 116: // page up\n\t\tcase 121: // page down\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\t[self.keyDelegate memberListKeyDown:e];\n\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/User List/TVCMemberListAppearance.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2018 - 2020Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSColorHelper.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"NSViewHelperPrivate.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TVCAppearancePrivate.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMemberListPrivate.h\"\n#import \"TVCMemberListAppearancePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMemberListAppearance ()\n@property (nonatomic, weak, readwrite) TVCMemberList *memberList;\n\n@property (nonatomic, assign, readwrite) CGFloat defaultWidth;\n@property (nonatomic, assign, readwrite) CGFloat minimumWidth;\n@property (nonatomic, assign, readwrite) CGFloat maximumWidth;\n\n@property (nonatomic, copy, nullable, readwrite) NSColor *rowSelectionColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *rowSelectionColorInactiveWindow;\n\n#pragma mark -\n#pragma mark Member Cell\n\n@property (nonatomic, assign, readwrite) BOOL cellRowEmphasized;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellAwayTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellAwayTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellSelectedTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *cellSelectedTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *cellFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *cellFontSelected;\n\n#pragma mark -\n#pragma mark Mark Badge\n\n@property (nonatomic, assign, readwrite) CGFloat markBadgeLeftMargin;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeSelectedBackgroundColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeSelectedBackgroundColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeSelectedTextColorActiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSColor *markBadgeSelectedTextColorInactiveWindow;\n@property (nonatomic, copy, nullable, readwrite) NSFont *markBadgeFont;\n@property (nonatomic, copy, nullable, readwrite) NSFont *markBadgeFontSelected;\n\n@property (nonatomic, strong, nullable) NSCache *cachedUserMarkBadges;\n@end\n\n@implementation TVCMemberListAppearance\n\n#pragma mark -\n#pragma mark Initialization\n\n- (nullable instancetype)initWithMemberList:(TVCMemberList *)memberList inWindow:(TVCMainWindow *)mainWindow\n{\n\tNSParameterAssert(memberList != nil);\n\tNSParameterAssert(mainWindow != nil);\n\n\tNSURL *appearanceLocation = [self.class appearanceLocation];\n\n\t/* Don't access -mainWindow in serverList to get this value\n\t because it may not be on a window at the time this is called. */\n\tBOOL forRetinaDisplay = mainWindow.runningInHighResolutionMode;\n\n\tif ((self = [super initWithAppearanceAtURL:appearanceLocation forRetinaDisplay:forRetinaDisplay])) {\n\t\tself.memberList = memberList;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n+ (NSURL *)appearanceLocation\n{\n\treturn [RZMainBundle() URLForResource:@\"TVCMemberListAppearance\" withExtension:@\"plist\"];\n}\n\n- (void)prepareInitialState\n{\n\tNSDictionary *properties = self.appearanceProperties;\n\n\tself.defaultWidth = [self measurementForKey:@\"defaultWidth\"];\n\tself.minimumWidth = [self measurementForKey:@\"minimumWidth\"];\n\tself.maximumWidth = [self measurementForKey:@\"maximumWidth\"];\n\n\tself.rowSelectionColorActiveWindow = [self colorForKey:@\"selectionColor\" forActiveWindow:YES];\n\tself.rowSelectionColorInactiveWindow = [self colorForKey:@\"selectionColor\" forActiveWindow:NO];\n\n\tNSDictionary *memberCell = properties[@\"Member Cell\"];\n\n\tself.cellRowEmphasized = [memberCell boolForKey:@\"rowEmphasized\"];\n\tself.cellTextColorActiveWindow = [self colorInGroup:memberCell withKey:@\"normalTextColor\" forActiveWindow:YES];\n\tself.cellTextColorInactiveWindow = [self colorInGroup:memberCell withKey:@\"normalTextColor\" forActiveWindow:NO];\n\tself.cellAwayTextColorActiveWindow = [self colorInGroup:memberCell withKey:@\"awayTextColor\" forActiveWindow:YES];\n\tself.cellAwayTextColorInactiveWindow = [self colorInGroup:memberCell withKey:@\"awayTextColor\" forActiveWindow:NO];\n\tself.cellSelectedTextColorActiveWindow = [self colorInGroup:memberCell withKey:@\"selectedTextColor\" forActiveWindow:YES];\n\tself.cellSelectedTextColorInactiveWindow = [self colorInGroup:memberCell withKey:@\"selectedTextColor\" forActiveWindow:NO];\n\tself.cellFont = [self fontInGroup:memberCell withKey:@\"font\"];\n\tself.cellFontSelected = [self fontInGroup:memberCell withKey:@\"fontSelected\"];\n\n\tNSDictionary *markBadge = properties[@\"Mark Badge\"];\n\n\tself.markBadgeLeftMargin = [markBadge floatForKey:@\"leftMargin\"];\n\tself.markBadgeBackgroundColorActiveWindow = [self colorInGroup:markBadge withKey:@\"normalBackgroundColor\" forActiveWindow:YES];\n\tself.markBadgeBackgroundColorInactiveWindow = [self colorInGroup:markBadge withKey:@\"normalBackgroundColor\" forActiveWindow:NO];\n\tself.markBadgeSelectedBackgroundColorActiveWindow = [self colorInGroup:markBadge withKey:@\"selectedBackgroundColor\" forActiveWindow:YES];\n\tself.markBadgeSelectedBackgroundColorInactiveWindow = [self colorInGroup:markBadge withKey:@\"selectedBackgroundColor\" forActiveWindow:NO];\n\tself.markBadgeTextColorActiveWindow = [self colorInGroup:markBadge withKey:@\"normalTextColor\" forActiveWindow:YES];\n\tself.markBadgeTextColorInactiveWindow = [self colorInGroup:markBadge withKey:@\"normalTextColor\" forActiveWindow:NO];\n\tself.markBadgeSelectedTextColorActiveWindow = [self colorInGroup:markBadge withKey:@\"selectedTextColor\" forActiveWindow:YES];\n\tself.markBadgeSelectedTextColorInactiveWindow = [self colorInGroup:markBadge withKey:@\"selectedTextColor\" forActiveWindow:NO];\n\tself.markBadgeFont = [self fontInGroup:markBadge withKey:@\"font\"];\n\tself.markBadgeFontSelected = [self fontInGroup:markBadge withKey:@\"fontSelected\"];\n\n\t[self flushAppearanceProperties];\n}\n\n#pragma mark -\n#pragma mark Everything Else\n\n- (NSString *)_keyForRetrievingCachedUserMarkBadgeWithSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank\n{\n\tif (modeSymbol.length == 0) {\n\t\treturn [NSString stringWithFormat:@\"%lu > (No Rank)\", rank];\n\t} else {\n\t\treturn [NSString stringWithFormat:@\"%lu > %@\", rank, modeSymbol];\n\t}\n}\n\n- (nullable NSImage *)cachedUserMarkBadgeForSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSCache *cache = self.cachedUserMarkBadges;\n\n\tif (cache == nil) {\n\t\treturn nil;\n\t}\n\n\tNSString *key = [self _keyForRetrievingCachedUserMarkBadgeWithSymbol:modeSymbol rank:rank];\n\n\treturn [cache objectForKey:key];\n}\n\n- (void)cacheUserMarkBadge:(NSImage *)badgeImage forSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank\n{\n\tNSParameterAssert(badgeImage != nil);\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSCache *cache = self.cachedUserMarkBadges;\n\n\tif (cache == nil) {\n\t\tcache = [NSCache new];\n\n\t\tself.cachedUserMarkBadges = cache;\n\t}\n\n\tNSString *key = [self _keyForRetrievingCachedUserMarkBadgeWithSymbol:modeSymbol rank:rank];\n\n\t[cache setObject:badgeImage forKey:key];\n}\n\n- (void)invalidateUserMarkBadgeCacheForSymbol:(NSString *)modeSymbol rank:(IRCUserRank)rank\n{\n\tNSParameterAssert(modeSymbol != nil);\n\n\tNSCache *cache = self.cachedUserMarkBadges;\n\n\tif (cache == nil) {\n\t\treturn;\n\t}\n\n\tNSString *key = [self _keyForRetrievingCachedUserMarkBadgeWithSymbol:modeSymbol rank:rank];\n\n\t[cache removeObjectForKey:key];\n}\n\n- (void)invalidateUserMarkBadgeCaches\n{\n\tNSCache *cache = self.cachedUserMarkBadges;\n\n\tif (cache == nil) {\n\t\treturn;\n\t}\n\n\t[cache removeAllObjects];\n}\n\n- (nullable NSColor *)_userMarkBadgeBackgroundColorWithAlphaCorrect:(NSString *)defaultsKey\n{\n\tNSColor *defaultColor = [RZUserDefaults() colorForKey:defaultsKey];\n\n\tif (defaultColor == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [defaultColor colorWithAlphaComponent:0.7];\n}\n\n- (NSColor *)markBadgeBackgroundColor_Y // InspIRCd-2.0\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +y\"];\n}\n\n- (NSColor *)markBadgeBackgroundColor_Q\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +q\"];\n}\n\n- (NSColor *)markBadgeBackgroundColor_A\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +a\"];\n}\n\n- (NSColor *)markBadgeBackgroundColor_O\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +o\"];\n}\n\n- (NSColor *)markBadgeBackgroundColor_H\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +h\"];\n}\n\n- (NSColor *)markBadgeBackgroundColor_V\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> +v\"];\n}\n\n- (nullable NSColor *)markBadgeBackgroundColorByUser\n{\n\treturn [self _userMarkBadgeBackgroundColorWithAlphaCorrect:@\"User List Mode Badge Colors -> no mode\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/User List/TVCMemberListCell.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSStringHelper.h\"\n#import \"NSTableViewHelperPrivate.h\"\n#import \"NSViewHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TPCPreferencesLocal.h\"\n#import \"IRCChannelUser.h\"\n#import \"IRCUser.h\"\n#import \"TVCMainWindow.h\"\n#import \"TVCMemberListAppearance.h\"\n#import \"TVCMemberListPrivate.h\"\n#import \"TVCMemberListUserInfoPopoverPrivate.h\"\n#import \"TVCMemberListCellPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCMemberListCellDrawingContext;\n\n@interface TVCMemberListRowCell ()\n@property (nonatomic, weak) TVCMemberList *memberList;\n@property (nonatomic, weak) TVCMemberListCell *childCell;\n@property (readonly) TVCMemberListAppearance *userInterfaceObjects;\n@end\n\n@interface TVCMemberListCell ()\n@property (nonatomic, weak) IBOutlet NSTextField *cellTextField;\n@property (readonly, copy) TVCMemberListCellDrawingContext *drawingContext;\n@property (readonly) TVCMemberList *memberList;\n@property (readonly) TVCMemberListRowCell *rowCell;\n@property (readonly) TVCMemberListAppearance *userInterfaceObjects;\n@property (readonly) IRCChannelUser *cellItem;\n@property (readonly) NSInteger rowIndex;\n@property (nonatomic, strong) IBOutlet NSLayoutConstraint *markBadgeLeftMarginConstraint;\n@end\n\n@interface TVCMemberListCellDrawingContext : NSObject\n@property (nonatomic, assign) BOOL isInverted;\n@property (nonatomic, assign) BOOL isSelected;\n@property (nonatomic, assign) BOOL isWindowActive;\n@end\n\n@implementation TVCMemberListCell\n\n#pragma mark -\n#pragma mark Drawing\n\n- (void)defineConstraints\n{\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\tself.markBadgeLeftMarginConstraint.constant = appearance.markBadgeLeftMargin;\n}\n\n- (void)applicationAppearanceChanged\n{\n\t[self defineConstraints];\n}\n\n- (BOOL)wantsUpdateLayer\n{\n\treturn YES;\n}\n\n- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy\n{\n\treturn NSViewLayerContentsRedrawOnSetNeedsDisplay;\n}\n\n- (void)updateLayer\n{\n\t[self updateDrawing];\n}\n\n- (void)updateDrawing\n{\n\tTVCMemberListCellDrawingContext *drawingContext = self.drawingContext;\n\n\t[self updateTextFieldInContext:drawingContext];\n\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\t[self updateDrawingWithAppearance:appearance inContext:drawingContext];\n\n\t[self updateMarkBadgeWithAppearance:appearance inContext:drawingContext];\n}\n\n- (void)updateTextFieldInContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(drawingContext != nil);\n\n\t/* Update string value */\n\tIRCChannelUser *cellItem = self.cellItem;\n\n\tNSString *stringValueNew = cellItem.user.nickname;\n\n\tNSTextField *textField = self.cellTextField;\n\n\tNSString *stringValueOld = textField.stringValue;\n\n\tif ([stringValueOld isEqualTo:stringValueNew]) {\n\t\treturn;\n\t}\n\n\ttextField.stringValue = stringValueNew;\n\n\t/* Update accessibility */\n\tNSTextFieldCell *textFieldCell = textField.cell;\n\n\t[textFieldCell setAccessibilityValueDescription:TXTLS(@\"Accessibility[alq-6s]\", stringValueNew)];\n}\n\n- (void)updateDrawingWithAppearance:(TVCMemberListAppearance *)appearance inContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tNSAttributedString *newValue = [self attributedTextFieldValueWithAppearance:appearance inContext:drawingContext];\n\n\tself.cellTextField.attributedStringValue = newValue;\n}\n\n- (NSAttributedString *)attributedTextFieldValueWithAppearance:(TVCMemberListAppearance *)appearance inContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isSelected = drawingContext.isSelected;\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\tIRCChannelUser *cellItem = self.cellItem;\n\n\tNSTextField *textField = self.cellTextField;\n\n\tNSAttributedString *stringValue = textField.attributedStringValue;\n\n\tNSMutableAttributedString *mutableStringValue = [stringValue mutableCopy];\n\n\t[mutableStringValue beginEditing];\n\n\tNSFont *controlFont = nil;\n\n\tif (isSelected) {\n\t\tcontrolFont = appearance.cellFontSelected;\n\t} else {\n\t\tcontrolFont = appearance.cellFont;\n\t} // isSelected\n\n\tNSColor *controlColor = nil;\n\n\tif (isSelected) {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.cellSelectedTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.cellSelectedTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else if (cellItem.user.isAway) {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.cellAwayTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.cellAwayTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.cellTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.cellTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t}\n\n\tNSRange stringValueRange = stringValue.range;\n\n\tif (controlFont) {\n\t\t[mutableStringValue addAttribute:NSFontAttributeName value:controlFont range:stringValueRange];\n\t}\n\n\tif (controlColor) {\n\t\t[mutableStringValue addAttribute:NSForegroundColorAttributeName value:controlColor\trange:stringValueRange];\n\t}\n\n\t[mutableStringValue endEditing];\n\n\treturn mutableStringValue;\n}\n\n#pragma mark -\n#pragma mark Badge Drawing\n\n- (NSAttributedString *)markBadgeTextForModeSymbol:(NSString *)modeSymbol isSelected:(BOOL)isSelected withAppearance:(TVCMemberListAppearance *)appearance inContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\tNSFont *controlFont = nil;\n\n\tif (isSelected) {\n\t\tcontrolFont = appearance.markBadgeFontSelected;\n\t} else {\n\t\tcontrolFont = appearance.markBadgeFont;\n\t} // isSelected\n\n\tNSColor *controlColor = nil;\n\n\tif (isSelected) {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.markBadgeSelectedTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.markBadgeSelectedTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else {\n\t\tif (isWindowActive) {\n\t\t\tcontrolColor = appearance.markBadgeTextColorActiveWindow;\n\t\t} else {\n\t\t\tcontrolColor = appearance.markBadgeTextColorInactiveWindow;\n\t\t} // isWindowActive\n\t} // isSelected\n\n\tNSDictionary *attributes = @{NSForegroundColorAttributeName : controlColor, NSFontAttributeName : controlFont};\n\n\tNSAttributedString *stringToDraw = [NSAttributedString attributedStringWithString:modeSymbol attributes:attributes];\n\n\treturn stringToDraw;\n}\n\n- (void)updateMarkBadgeWithAppearance:(TVCMemberListAppearance *)appearance inContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isSelected = drawingContext.isSelected;\n\n\tIRCChannelUser *cellItem = self.cellItem;\n\n\tNSString *modeSymbol = cellItem.mark;\n\n\tIRCUserRank userRankToDraw = IRCUserRankNone;\n\n\tif ([TPCPreferences memberListSortFavorsServerStaff]) {\n\t\tif (cellItem.user.isIRCop) {\n\t\t\tuserRankToDraw = IRCUserRankIRCopByMode;\n\t\t}\n\t}\n\n\tif (userRankToDraw == IRCUserRankNone) {\n\t\tuserRankToDraw = cellItem.rank;\n\t}\n\n\tNSImage *cachedImage = nil;\n\n\tif (isSelected == NO) {\n\t\tcachedImage = [appearance cachedUserMarkBadgeForSymbol:modeSymbol rank:userRankToDraw];\n\t}\n\n\tif (cachedImage == nil) {\n\t\tcachedImage = [self drawMarkBadgeForRank:userRankToDraw isSelected:isSelected withAppearance:appearance inContext:drawingContext];\n\n\t\tif (isSelected == NO) {\n\t\t\t[appearance cacheUserMarkBadge:cachedImage forSymbol:modeSymbol rank:userRankToDraw];\n\t\t}\n\t}\n\n\tself.imageView.image = cachedImage;\n}\n\n- (NSImage *)drawMarkBadgeForRank:(IRCUserRank)userRank isSelected:(BOOL)isSelected withAppearance:(TVCMemberListAppearance *)appearance inContext:(TVCMemberListCellDrawingContext *)drawingContext\n{\n\tNSParameterAssert(appearance != nil);\n\tNSParameterAssert(drawingContext != nil);\n\n\tBOOL isWindowActive = drawingContext.isWindowActive;\n\n\t/* Create image that we will draw into. */\n\tNSRect imageViewFrame = self.imageView.frame;\n\n\tNSRect badgeFrame = NSMakeRect(0.0, 0.0, imageViewFrame.size.width, imageViewFrame.size.height);\n\n\tNSImage *badgeImage = [NSImage newImageWithSize:NSMakeSize(NSWidth(badgeFrame),  NSHeight(badgeFrame))];\n\n\t[badgeImage lockFocus];\n\n\t/* Decide the background color */\n\tNSColor *backgroundColor = nil;\n\n\tif (isSelected) {\n\t\tif (isWindowActive) {\n\t\t\tbackgroundColor = appearance.markBadgeSelectedBackgroundColorActiveWindow;\n\t\t} else {\n\t\t\tbackgroundColor = appearance.markBadgeSelectedBackgroundColorInactiveWindow;\n\t\t} // isWindowActive\n\t} else if (userRank == IRCUserRankIRCopByMode) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_Y;\n\t} else if (userRank == IRCUserRankChannelOwner) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_Q;\n\t} else if (userRank == IRCUserRankSuperOperator) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_A;\n\t} else if (userRank == IRCUserRankNormalOperator) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_O;\n\t} else if (userRank == IRCUserRankHalfOperator) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_H;\n\t} else if (userRank == IRCUserRankVoiced) {\n\t\tbackgroundColor = appearance.markBadgeBackgroundColor_V;\n\t} else {\n\t\tNSColor *customColor = appearance.markBadgeBackgroundColorByUser;\n\n\t\tif (customColor && [customColor isEqual:[NSColor clearColor]] == NO) {\n\t\t\tbackgroundColor = customColor;\n\t\t} else {\n\t\t\tif (isWindowActive) {\n\t\t\t\tbackgroundColor = appearance.markBadgeBackgroundColorActiveWindow;\n\t\t\t} else {\n\t\t\t\tbackgroundColor = appearance.markBadgeBackgroundColorInactiveWindow;\n\t\t\t} // isWindowActive\n\t\t} // custom color set\n\t}\n\n\t/* Set \"x\" if the user has no modes set */\n\tNSString *stringToDraw = self.cellItem.mark;\n\n\tif ([TPCPreferences memberListDisplayNoModeSymbol]) {\n\t\tif (stringToDraw.length == 0) {\n\t\t\tstringToDraw = @\"×\";\n\t\t}\n\t}\n\n\t/* Draw the background of the badge */\n\tNSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeFrame xRadius:4.0 yRadius:4.0];\n\n\t[backgroundColor set];\n\n\t[badgePath fill];\n\n\t/* Begin building the actual mode string */\n\tif (stringToDraw.length > 0) {\n\t\tNSAttributedString *badgeText = [self markBadgeTextForModeSymbol:stringToDraw isSelected:isSelected withAppearance:appearance inContext:drawingContext];\n\n\t\tNSSize badgeTextSize = badgeText.size;\n\n\t\tNSPoint badgeTextPoint = NSMakePoint((NSMidX(badgeFrame) - (badgeTextSize.width / 2.0)),\n\t\t\t\t\t\t\t\t\t\t\t (NSMidY(badgeFrame) - (badgeTextSize.height / 2.0)));\n\n\t\tif (appearance.isHighResolutionAppearance)\n\t\t{\n\t\t\tif ([stringToDraw isEqualToString:@\"+\"] ||\n\t\t\t\t[stringToDraw isEqualToString:@\"~\"] ||\n\t\t\t\t[stringToDraw isEqualToString:@\"×\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y += 1.0;\n\t\t\t}\n\t\t\telse if ([stringToDraw isEqualToString:@\"^\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y -= 2.0;\n\t\t\t}\n\t\t\telse if ([stringToDraw isEqualToString:@\"*\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y -= 2.5;\n\t\t\t}\n/*\t\t\telse if ([stringToDraw isEqualToString:@\"@\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"!\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"%\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"&\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"#\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"?\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"$\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y -= 0.0;\n\t\t\t} */\n\t\t}\n\t\telse // isDrawingForRetina\n\t\t{\n\t\t\tif ([stringToDraw isEqualToString:@\"+\"] ||\n\t\t\t\t[stringToDraw isEqualToString:@\"~\"] ||\n\t\t\t\t[stringToDraw isEqualToString:@\"×\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y += 2.0;\n\t\t\t}\n\t\t\telse if ([stringToDraw isEqualToString:@\"@\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"!\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"%\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"&\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"#\"] ||\n\t\t\t\t\t [stringToDraw isEqualToString:@\"?\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y += 1.0;\n\t\t\t}\n/*\t\t\telse if ([stringToDraw isEqualToString:@\"^\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y -= 0.0;\n\t\t\t} */\n\t\t\telse if ([stringToDraw isEqualToString:@\"*\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y -= 1.0;\n\t\t\t}\n\t\t\telse if ([stringToDraw isEqualToString:@\"$\"])\n\t\t\t{\n\t\t\t\tbadgeTextPoint.y += 1.0;\n\t\t\t}\n\t\t}\n\n\t\t[badgeText drawAtPoint:badgeTextPoint];\n\t}\n\n\t[badgeImage unlockFocus];\n\n\treturn badgeImage;\n}\n\n#pragma mark -\n#pragma mark Expansion Frame\n\n- (void)drawWithExpansionFrame\n{\n\tTVCMemberList *memberList = self.memberList;\n\n\tTVCMemberListUserInfoPopover *userInfoPopover = memberList.memberListUserInfoPopover;\n\n\tIRCChannelUser *cellItem = self.cellItem;\n\n\t/* =============================================== */\n\n\tuserInfoPopover.nicknameField.stringValue = cellItem.user.nickname;\n\n\t/* =============================================== */\n\n\tNSString *hostmaskUsername = cellItem.user.username;\n\n\tif (hostmaskUsername.length == 0) {\n\t\thostmaskUsername = TXTLS(@\"TVCMainWindow[d85-9n]\");\n\t}\n\n\tuserInfoPopover.usernameField.stringValue = hostmaskUsername;\n\n\t/* =============================================== */\n\n\tBOOL stripIRCFormatting = [TPCPreferences removeAllFormatting];\n\n\tNSString *hostmaskAddress = cellItem.user.address;\n\n\tif (hostmaskAddress.length == 0) {\n\t\thostmaskAddress = TXTLS(@\"TVCMainWindow[d85-9n]\");\n\t}\n\n\tif (stripIRCFormatting) {\n\t\tuserInfoPopover.addressField.stringValue = hostmaskAddress;\n\t} else {\n\t\tNSAttributedString *hostmaskAddressFormatted =\n\t\t[hostmaskAddress attributedStringWithIRCFormatting:[NSFont systemFontOfSize:12.0]\n\t\t\t\t\t\t\t\t\t\tpreferredFontColor:nil\n\t\t\t\t\t\t\t\t honorFormattingPreference:NO];\n\n\t\tuserInfoPopover.addressField.attributedStringValue = hostmaskAddressFormatted;\n\t}\n\n\t/* =============================================== */\n\n\tNSString *realName = cellItem.user.realName;\n\n\tif (realName.length == 0) {\n\t\trealName = TXTLS(@\"TVCMainWindow[d85-9n]\");\n\t}\n\n\tif (stripIRCFormatting) {\n\t\tuserInfoPopover.realNameField.stringValue = realName;\n\t} else {\n\t\tNSAttributedString *realNameFormatted =\n\t\t[realName attributedStringWithIRCFormatting:[NSFont systemFontOfSize:12.0]\n\t\t\t\t\t\t\t\t preferredFontColor:nil\n\t\t\t\t\t\t  honorFormattingPreference:NO];\n\n\t\tuserInfoPopover.realNameField.attributedStringValue = realNameFormatted;\n\t}\n\n\t/* =============================================== */\n\n\tif (cellItem.user.isAway) {\n\t\tuserInfoPopover.awayStatusField.stringValue = TXTLS(@\"TVCMainWindow[jkr-ed]\");\n\t} else {\n\t\tuserInfoPopover.awayStatusField.stringValue = TXTLS(@\"TVCMainWindow[gi6-wf]\");\n\t}\n\n\t/* =============================================== */\n\n\tIRCUserRank userRank = cellItem.rank;\n\n\tif (cellItem.user.isIRCop) {\n\t\tuserRank = IRCUserRankIRCopByMode;\n\t}\n\n\tNSString *userPrivileges = nil;\n\n\tif (userRank == IRCUserRankIRCopByMode) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[i8t-vb]\");\n\t} else if (userRank == IRCUserRankChannelOwner) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[p1z-sc]\");\n\t} else if (userRank == IRCUserRankSuperOperator) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[som-zo]\");\n\t} else if (userRank == IRCUserRankNormalOperator) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[0kn-s5]\");\n\t} else if (userRank == IRCUserRankHalfOperator) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[0nn-te]\");\n\t} else if (userRank == IRCUserRankVoiced) {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[ya1-sk]\");\n\t} else {\n\t\tuserPrivileges = TXTLS(@\"TVCMainWindow[tjj-z2]\");\n\t}\n\n\tuserInfoPopover.privilegesField.stringValue = userPrivileges;\n\n\t/* =============================================== */\n\n\tNSInteger rowIndex = [memberList rowForView:self];\n\n\tNSRect cellFrame = [memberList frameOfCellAtColumn:0 row:rowIndex];\n\n\t/* Presenting the popover will steal focus. To workaround this,\n\t we record the active first responder then set it back. */\n\tNSWindow *window = self.window;\n\n\tNSResponder *activeFirstResponder = window.firstResponder;\n\n\t[userInfoPopover showRelativeToRect:cellFrame\n\t\t\t\t\t\t\t\t ofView:memberList\n\t\t\t\t\t\t  preferredEdge:NSMaxXEdge];\n\n\t[window makeFirstResponder:activeFirstResponder];\n}\n\n- (TVCMemberListRowCell *)rowCell\n{\n\treturn (id)self.superview;\n}\n\n- (IRCChannelUser *)cellItem\n{\n\treturn self.objectValue;\n}\n\n- (TVCMemberList *)memberList\n{\n\treturn self.rowCell.memberList;\n}\n\n- (TVCMemberListAppearance *)userInterfaceObjects\n{\n\treturn self.rowCell.userInterfaceObjects;\n}\n\n- (TVCMemberListCellDrawingContext *)drawingContext\n{\n\tTVCMemberList *memberList = self.memberList;\n\n\tNSInteger rowIndex = [memberList rowForView:self];\n\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\tTVCMemberListCellDrawingContext *drawingContext = [TVCMemberListCellDrawingContext new];\n\n\tTVCMainWindow *mainWindow = self.mainWindow;\n\n\tdrawingContext.isInverted = appearance.isDarkAppearance;\n\tdrawingContext.isSelected = [memberList isRowSelected:rowIndex];\n\tdrawingContext.isWindowActive = mainWindow.isActiveForDrawing;\n\n\treturn drawingContext;\n}\n\n@end\n\n@implementation TVCMemberListCellDrawingContext\n@end\n\n#pragma mark -\n#pragma mark Row View Cell\n\n@implementation TVCMemberListRowCell\n\n- (instancetype)initWithMemberList:(TVCMemberList *)memberList\n{\n\tNSParameterAssert(memberList != nil);\n\n\tif ((self = [super initWithFrame:NSZeroRect])) {\n\t\tself.memberList = memberList;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)setSelected:(BOOL)selected\n{\n\tsuper.selected = selected;\n\n\tif (selected == NO && self.invalidatingBackgroundForSelection) {\n\t\treturn;\n\t}\n\n\t[self setNeedsDisplayOnChild];\n}\n\n- (void)setNeedsDisplayOnChild\n{\n\tself.childCell.needsDisplay = YES;\n}\n\n- (void)drawSelectionInRect:(NSRect)dirtyRect\n{\n\tif ([self needsToDrawRect:dirtyRect] == NO) {\n\t\treturn;\n\t}\n\n\tBOOL isWindowActive = self.mainWindow.isActiveForDrawing;\n\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\tNSColor *selectionColor = nil;\n\n\tif (isWindowActive) {\n\t\tselectionColor = appearance.rowSelectionColorActiveWindow;\n\t} else {\n\t\tselectionColor = appearance.rowSelectionColorInactiveWindow;\n\t} // isWindowActive\n\n\tif (selectionColor) {\n\t\t[selectionColor set];\n\n\t\tNSRect selectionRect = self.bounds;\n\n\t\tNSRectFill(selectionRect);\n\t} else {\n\t\t[super drawSelectionInRect:dirtyRect];\n\t} // selectionColor\n}\n\n- (void)didAddSubview:(NSView *)subview\n{\n\tTVCMemberListCell *childCell = self.childCell;\n\n\t[childCell defineConstraints];\n\n\t[super didAddSubview:subview];\n}\n\n#pragma mark -\n#pragma mark Cell Information\n\n- (BOOL)isEmphasized\n{\n\tTVCMemberListAppearance *appearance = self.userInterfaceObjects;\n\n\tNSWindow *window = self.window;\n\n\treturn (appearance.cellRowEmphasized &&\n\t\t\t(window == nil || window.isKeyWindow));\n}\n\n- (TVCMemberListCell * _Nullable)childCell\n{\n\tif (self->_childCell == nil) {\n\t\tif (self.numberOfColumns == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tself->_childCell = [self viewAtColumn:0];\n\t}\n\n\treturn self->_childCell;\n}\n\n- (TVCMemberListAppearance *)userInterfaceObjects\n{\n\treturn self.memberList.userInterfaceObjects;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Classes/Views/User List/TVCMemberListUserInfoPopover.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCMemberListUserInfoPopoverPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCMemberListUserInfoPopover ()\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *nicknameField;\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *usernameField;\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *addressField;\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *realNameField;\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *privilegesField;\n@property (nonatomic, weak, readwrite) IBOutlet NSTextField *awayStatusField;\n@end\n\n@implementation TVCMemberListUserInfoPopover\n\n- (void)mouseDown:(NSEvent *)event\n{\n\t[self close];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/App/Configurations/Sandbox/Debug.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>com.codeux.apps.textual</string>\n\t\t<string>com.codeux.apps.textual.group</string>\n\t\t<string>8482Q6EPL6.com.codeux.apps.textual</string>\n\t\t<string>8482Q6EPL6.com.codeux.irc.textual</string>\n\t</array>\n\t<key>com.apple.security.automation.apple-events</key>\n\t<true/>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n\t<key>com.apple.security.files.bookmarks.app-scope</key>\n\t<true/>\n\t<key>com.apple.security.files.downloads.read-write</key>\n\t<true/>\n\t<key>com.apple.security.files.user-selected.read-write</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n\t<key>com.apple.security.print</key>\n\t<true/>\n\t<key>com.apple.security.temporary-exception.apple-events</key>\n\t<array>\n\t\t<string>com.apple.itunes</string>\n\t\t<string>com.apple.safari</string>\n\t</array>\n\t<key>com.apple.security.temporary-exception.shared-preference.read-write</key>\n\t<array>\n\t\t<string>com.codeux.apps.textual</string>\n\t\t<string>com.codeux.apps.textual-mas</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Configurations/Sandbox/Sandbox Disabled.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Configurations/Sandbox/Standard Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>com.codeux.apps.textual</string>\n\t\t<string>com.codeux.apps.textual.group</string>\n\t\t<string>8482Q6EPL6.com.codeux.apps.textual</string>\n\t\t<string>8482Q6EPL6.com.codeux.irc.textual</string>\n\t</array>\n\t<key>com.apple.security.automation.apple-events</key>\n\t<true/>\n\t<key>com.apple.security.cs.disable-library-validation</key>\n\t<true/>\n\t<key>com.apple.security.files.bookmarks.app-scope</key>\n\t<true/>\n\t<key>com.apple.security.files.downloads.read-write</key>\n\t<true/>\n\t<key>com.apple.security.files.user-selected.read-write</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n\t<key>com.apple.security.network.server</key>\n\t<true/>\n\t<key>com.apple.security.print</key>\n\t<true/>\n\t<key>com.apple.security.temporary-exception.apple-events</key>\n\t<array>\n\t\t<string>com.apple.itunes</string>\n\t\t<string>com.apple.safari</string>\n\t</array>\n\t<key>com.apple.security.temporary-exception.files.home-relative-path.read-only</key>\n\t<array>\n\t\t<string>/Library/Application Support/Textual/Textual_Trial_Information_v2.plist</string>\n\t\t<string>/Library/Application Support/Textual/Textual_User_License_v2.plist</string>\n\t</array>\n\t<key>com.apple.security.temporary-exception.shared-preference.read-write</key>\n\t<array>\n\t\t<string>com.codeux.apps.textual</string>\n\t\t<string>com.codeux.apps.textual-mas</string>\n\t</array>\n\t<key>com.apple.security.temporary-exception.mach-lookup.global-name</key>\n\t<array>\n\t\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)-spks</string>\n\t\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)-spki</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Images/Copyright Information for Images.txt",
    "content": "Please see acknowledgements.pdf for copyright information"
  },
  {
    "path": "Sources/App/Resources/Language Files/_randomToken",
    "content": "#!/usr/bin/php\n<?php\n\t\n\tfunction randomString()\n\t{\n\t\t$characters = '0123456789abcdefghijklmnopqrstuvwxyz';\n\t\t\n\t\t$charactersLength = (strlen($characters) - 1);\n\t\t\n\t\t$randomString = '';\n\t\t\n\t\t$randomString .= $characters[mt_rand(0, $charactersLength)];\n\t\t$randomString .= $characters[mt_rand(0, $charactersLength)];\n\t\t$randomString .= $characters[mt_rand(0, $charactersLength)];\n\t\t$randomString .= \"-\";\n\t\t$randomString .= $characters[mt_rand(0, $charactersLength)];\n\t\t$randomString .= $characters[mt_rand(0, $charactersLength)];\n\t\t\n\t\treturn $randomString;\n\t}\n\t\n\tfor ($i = 0; $i < 10; $i++) {\n\t\techo randomString().\"\\n\";\n\t}\n\t\n\texit(0);\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/Accessibility.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"alq-6s\" = \"User %@ in User List\";\n\n\"bmy-d2\" = \"Connection %@, Connected\";\n\"tu4-8u\" = \"Connection %@, Disconnected\";\n\n\"75f-og\" = \"Channel %@, Channel Joined\";\n\"edc-7o\" = \"Channel %@, Channel Not Joined\";\n\n\"9sn-xp\" = \"Query with User %@\";\n\n\"k79-1a\" = \"Main Window\"; // Main window title description\n\n\"wbj-gr\" = \"Alert dialog %@\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"71l-y7\" = \"None\";\n\"vbl-xi\" = \"Unknown\";\n\n\"1dd-0f\" = \"Textual IRC Client: www.textualapp.com\";\n\"vfu-c0\" = \"Untitled Connection\";\n\n\"zhr-lq\" = \"My %@ has gone to sleep. ZZZzzz…\";\n\"qi7-5y\" = \"My Mac has gone to sleep. ZZZzzz…\";\n\n\"hri-l0\" = \"Close Query\";\n\"1f6-bg\" = \"Close Window\";\n\"w3a-je\" = \"Disconnect from %@\";\n\"5td-3f\" = \"Leave Channel\";\n\"x97-ro\" = \"Quit Textual\";\n\n\"6cw-ni\" = \"Copy Log as HTML\";\n\"ngd-ms\" = \"Force Reload Style\";\n\"tfj-m9\" = \"Open Web Inspector\";\n\"o5l-4s\" = \"Look Up in Dictionary\";\n\"zxs-yy\" = \"Look Up “%@”\";\n\"1ll-h9\" = \"Search With %@\";\n\n\"eoq-pr-128\" = \"seconds\";\n\"eoq-pr-64\" = \"minutes\";\n\"eoq-pr-32\" = \"hours\";\n\"eoq-pr-16\" = \"days\";\n\"eoq-pr-8\" = \"months\";\n\"eoq-pr-4\" = \"years\";\n\n\"fko-64-128\" = \"second\";\n\"fko-64-64\" = \"minute\";\n\"fko-64-32\" = \"hour\";\n\"fko-64-16\" = \"day\";\n\"fko-64-8\" = \"month\";\n\"fko-64-4\" = \"year\";\n\n\"4um-w4\" = \"%@ ago\";\n\n\"7kc-mo\" = \"No Actions Available\";\n\n\"7lm-bq\" = \"Built-in\";\n\"bm2-4p\" = \"Custom\";\n\n\"fo8-1h\" = \"Fill out this field\";\n\n\"iwp-cg\" = \"IRC Colors\";\n\"ham-vk\" = \"Color %ld\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/CommonErrors.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"yyx-l3\" = \"Please enter a properly formatted server address or pick from the list of preconfigured networks.\";\n\"l0c-nb\" = \"Please enter a whole number between 1 and 65,535.\";\n\"och-j5\" = \"Please enter a properly formatted nickname.\";\n\"pgl-zg\" = \"Please enter a properly formatted e-mail address.\";\n\"gas-v8\" = \"Cannot contain more than one line.\";\n\"2cb-af\" = \"Maximum length is %ld characters.\";\n\"qi9-i8\" = \"Minimum length is %ld characters.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/IRC.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Script errors */\n\"d3c-9b\" = \"The command \\002%@\\002 is defined by a plugin and a script. Ignoring command because of inability to determine priority.\";\n\n\"ax0-mt\" = \"Script Execution Failure: %@\";\n\"2mc-h0\" = \"Script Execution Failure (%1$@: %2$@): %3$@\";\n\n/* Generic messages */\n\"0r1-5l\" = \"Textual has prevented you from banning yourself on %@\";\n\n\"6rj-2r\" = \"Failed to send data to server. Not connected.\";\n\n/* Default G:Line reason */\n\"56r-wn\" = \"35d Your behavior is not conducive to the desired environment\";\n\"2aw-rf\" = \"Your behavior is not conducive to the desired environment\";\n\"yy6-fx\" = \"Your behavior is not conducive to the desired environment\";\n\"80c-i8\" = \"1d Shunned\";\n\n/* Network not available messages */\n\"3s6-e6\" = \"Delaying auto connect for %lu seconds\";\n\n/* File transfer server console messages */\n\"ags-s8\" = \"Trying file transfer to %1$@, %2$@ (%3$qi bytes)\";\n\"snf-45\" = \"Received file transfer request from %1$@, %2$@ (%3$qi bytes)\";\n\"y3w-la\" = \"Textual has received a DCC request from %@ that could not be processed.\";\n\n/* Version info */\n\"vzu-u7\" = \"%1$@ IRC Client: www.textualapp.com — v%2$@\";\n\n/* Specific IRC related, app-specific errors */\n\"iaa-0u\" = \"There are no servers configured to connect to.\";\n\n/* Raw mode messages */\n\"ik6-dl\" = \"⍅ Server traffic will be output to this window until it is closed by control clicking (right clicking) it. ⍆\";\n\n/* Hidden command responses messages */\n\"yem-td\" = \"⍅ Command responses which are normally hidden will be output to this window until it is closed by control clicking (right clicking) it. ⍆\";\n\n/* Log file session headers */\n\"qrg-ua\" = \"------------- Begin Session -------------\";\n\"d5d-uy\" = \"------------- End Session -------------\";\n\n/* Ban list */\n\"c04-d0-1\" = \"Ban in %1$@: %2$@ set by %3$@ on %4$@\";\n\"c04-d0-2\" = \"Ban in %1$@: %2$@\";\n\n/* Invite exception list */\n\"py2-qh-1\" = \"Invite Exception in %1$@: %2$@ set by %3$@ on %4$@\";\n\"py2-qh-2\" = \"Invite Exception in %1$@: %2$@\";\n\n/* Ban exception list */\n\"ov2-ci-1\" = \"Ban exception in %1$@: %2$@ set by %3$@ on %4$@\";\n\"ov2-ci-2\" = \"Ban exception in %1$@: %2$@\";\n\n/* Quiet list */\n\"u5z-az-1\" = \"Quiet in %1$@: %2$@ set by %3$@ on %4$@\";\n\"u5z-az-2\" = \"Quiet in %1$@: %2$@\";\n\n/* Cipher suite information */\n\"uyz-4r\" = \"\\002%1$@\\002 with the cipher suite: \\002%2$@\\002\";\n\"xwj-xy\" = \"\\002%1$@\\002 with the cipher suite: \\002%2$@\\002 \\0034\\002(deprecated)\\002\\003\";\n\n/* XPC errors */\n\"vdy-jk\" = \"Connection service closed unexpectedly\";\n\n/* Large messages warning */\n\"u4c-7i\" = \"The message that you are sending is very large which means it will be split up into multiple messages. Sending too many messages at once is often considered disruptive and may result in a ban.\";\n\"lql-8i\" = \"Are you sure you want to send this message?\";\n\n/* /away/ command */\n\"41y-p2\" = \"You have exceeded the maximum away message length for %1$@ which is %2$ld characters. The end of your away message may have been cut off.\";\n\n/* /defaults/ command */\n\"1dz-jb\" = \"Invalid Syntax. Type “/defaults help” for more information.\";\n\n\"bkk-lo\" = \"The \\002defaults\\002 command can be used to toggle very specific, rarely used features.\n\nUsage:\n\t“/defaults enable <token>” — Enables the feature defined by \\002<token>\\002\n\t“/defaults disable <token>” — Disables the feature defined by \\002<token>\\002\n\t“/defaults features” — View list of supported features\n\nSurround \\002<token>\\002 with double quotes (\\\") if it contains a space.\";\n\n\"pc4-67\" = \"Cannot enable the feature “%@” because it is not supported\";\n\"d7y-pv\" = \"Cannot disable the feature “%@” because it is not supported\";\n\n\"5ke-18\" = \"Enabled Feature: %@\";\n\"0gn-cb\" = \"Disabled Feature: %@\";\n\n/* /ignore/ command */\n\"ret-20\" = \"Added ignore that matches \\002%1$@\\002 with pattern: %2$@\";\n\"jzg-g8\" = \"Removed ignore that matches \\002%1$@\\002 with pattern: %2$@\";\n\"wu0-jp\" = \"No ignores could be found that matches \\002%@\\002\";\n\"5ix-zn\" = \"An ignore already exists that matches \\002%@\\002. To modify this ignore, open the \\002Address Book\\002 using the keyboard shortcut \\002Control 3\\002.\";\n\"vrx-1f\" = \"Cannot remove ignore for \\002%@\\002 because Textual isn't sure which to remove. More than one ignore exists that matches this user. To remove a specific ignore, open the \\002Address Book\\002 using the keyboard shortcut \\002Control 3\\002.\";\n\n/* /kick/ command */\n\"59a-ir\" = \"You have exceeded the maximum kick message length for %1$@ which is %2$ld characters. The end of your kick message may have been cut off.\";\n\n/* /lagcheck/ command */\n\"5bf-jp\" = \"Received lag check reply from %1$@. Time elapsed: %2$1.0f milliseconds. (Rating: %3$@)\";\n\"qoh-kt\" = \"Waiting for response from lag check…\";\n\n\"58g-m9\" = \"Yeah, okay…\";\n\"0jp-93\" = \"Are you plugged into the server?\";\n\"yym-8y\" = \"Pretty good\";\n\"mic-qe\" = \"Not bad\";\n\"mqg-wi\" = \"Okay\";\n\"ut8-7s\" = \"Needs work\";\n\"8fo-ss\" = \"Slow\";\n\"4oc-p2\" = \"Very slow\";\n\n/* /mode/ command */\n\"dwi-d1\" = \"The mode \\002+%@\\002 is not supported on this server\";\n\n/* /monitor/ command errors */\n\"khw-4y\" = \"Please use the \\002Address Book\\002 to add or remove tracked users. Open the \\002Address Book\\002 using the keyboard shortcut \\002Control 3\\002.\";\n\n/* /msg/ command errors */\n\"54l-h7\" = \"Cannot send operator message because the mode \\002+o\\002 is not supported by this server.\";\n\n/* /mute/ command */\n\"sdn-yr\" = \"Sound is already muted\";\n\"190-f2\" = \"Sound is no longer muted\";\n\"5rf-mj\" = \"Sound is not muted\";\n\"u48-aa\" = \"Sound has been muted\";\n\n/* /myversion/ command */\n\"pqj-1y\" = \"I am using %@\";\n\"ccb-ur\" = \"%1$@ %2$@ (Build %3$@)%4$@%5$@\";\n\"b8p-44\" = \" as classic binary on an %@ Mac.\";\n\n/* /timer/ command */\n\"jj9-94\" = \"Invalid Syntax. Type “/timer help” for more information.\";\n\"327-pv\" = \"Timer interval must be a whole number that is grater than zero (0). Type “/timer help” for more information.\";\n\"eud-kc\" = \"Timer repeat count must be a whole number that is grater than or equal to zero (0). Type “/timer help” for more information.\";\n\"p6l-o4\" = \"Timer identifier is not properly formatted. Type “/timer list“ for a list of timers.\";\n\"vzu-xh\" = \"Timer with identifier “%@“ does not exist. Type “/timer list“ for a list of timers.\";\n\"uiz-32\" = \"Timer with identifier “%@“ can't be stopped\";\n\"ax6-n9\" = \"Timer with identifier “%@“ is already stopped\";\n\"hs0-up\" = \"Timer with identifier “%@“ stopped\";\n\"dgp-d4\" = \"Timer with identifier “%@“ can't be restarted. Add a new timer.\";\n\"qb7-mi\" = \"Timer with identifier “%@“ restarted\";\n\"p7s-is\" = \"Timer with identifier “%@“ removed\";\n\"808-bs\" = \"All timers removed\";\n\"jef-tp\" = \"Timer with identifier “%@“ added\"; // unused\n\"pqk-5k\" = \"There are no timers\";\n\"q1m-1e\" = \"There are %ld timers:\";\n\"6ts-oi\" = \"There is %ld timer:\";\n\n\"4n6-2x\" = \"\\002ID:\\002 %1$@ • \\002Status:\\002 %2$@ • \\002Interval:\\002 %3$@ • \\002Next Fire:\\002 %4$@ • \\002Command:\\002 “%5$@“\";\n\"uw0-v2\" = \"\\002ID:\\002 %1$@ • \\002Status:\\002 %2$@ • \\002Interval:\\002 %3$@ • \\002Next Fire:\\002 %4$@ • \\002Repeat:\\002 Yes • \\002Repeat Limit:\\002 %5$@ • \\002Iteration:\\002 %6$ld • \\002Command:\\002 “%7$@“\";\n\"bhz-9e\" = \"Active\";\n\"ww4-sn\" = \"Stopped\";\n\"o26-ae\" = \"No Limit\";\n\n\"xkq-rt\" = \"The timer command can be used to perform a command after a specific amount of time and optionally repeat it.\n\nTo learn more, type:\n\t“/timer help <topic>“\n\nAvailable topics: ADD, REMOVE, LIST, STOP, RESTART\";\n\n\"6r0-il\" = \"“/timer <seconds> <repeat> <command>“\n\n\\002<seconds>\\002 is the interval of the timer.\nThe interval must be a \\002whole number that is greater than zero (0)\\002.\n\n\\002<repeat>\\002 is the repeat count for the timer.\n• To perform the timer only once, use one (1) as the repeat count.\n• To repeat the timer until manually stopped, use zero (0) as the repeat count.\n• To repeat the timer X number of times, use that number as the repeat count.\n\n\\002<command>\\002 is the command to perform when the timer fires.\n\\002Example:\\002 “msg #textual-testing Hey everyone!”\n\\002Scope:\\002 The channel or query that is selected when a timer is added is used as the target for commands that do not take a channel name as an argument.\n\n\\002Example #1:\\002 “/timer 10 1 <command>” — perform command one time, after ten seconds.\n\\002Example #2:\\002 “/timer 10 20 <command>” — perform command twenty times, once every ten seconds.\n\\002Example #3:\\002 “/timer 10 0 <command>” — perform command every ten seconds until the heat death of the universe.\";\n\n\"x1n-ve\" = \"“/timer list“\n\nList timers\";\n\n\"bx2-n1\" = \"“/timer stop <identifier>“\n\nStop the timer assigned to \\002<identifier>\\002.\n\nThe identifier for a timer can be found using “/timer list”\";\n\n\"r27-tv\" = \"“/timer restart <identifier>“\n\nRestart the timer assigned to \\002<identifier>\\002.\n\nThe identifier for a timer can be found using “/timer list”\n\nWhen restarting a timer, the iteration count is reset\nwhich means a timer that is setup to repeat X number\nof times will start over from the beginning.\";\n\n\"i2d-x5\" = \"“/timer remove <identifier>“\n\nRemove the timer assigned to \\002<identifier>\\002.\n\nTo remove all timers, pass “all” as \\002<identifier>\\002.\n\nThe identifier for a timer can be found using “/timer list”\";\n\n\"aox-zz\" = \"---------------------------------------\";\n\n/* /setcolor/ command */\n\"026-qv\" = \"This command cannot be used unless the checkbox labeled “Disable nickname colors” is unchecked in the \\002Style\\002 section of \\002Preferences\\002.\";\n\"8dy-6f\" = \"Cannot set color for “%@“ because that does not appear to be a valid nickname.\";\n\n/* /tage/ command */\n\"v9x-18\" = \"\\002Time Since First Commit:\\002 %@\";\n\n/* /topic/ command errors */\n\"1oo-3b\" = \"You have exceeded the maximum topic length for %1$@ which is %2$ld characters. The end of your topic may have been cut off.\";\n\n/* /weights/ command */\n\"zud-u3\" = \"Nickname completion weights for %@:\";\n\"24r-8c\" = \"\\002%1$@\\002: Sent: %2$.2f, Receive: %3$.2f, \\002Total: %4$.2f\\002\";\n\"dje-41\" = \"No weights\";\n\n/* Address type migration warning */\n\"w05-ph\" = \"\\0034\\002Please take notice:\\002\\003 The preference labeled “Prefer IPv4”, which you had enabled, no longer exists. \\002IPv6 has been disabled for this connection\\002 to offer you similar behavior. See the \\002Network Socket\\002 section of \\002Server Properties\\002 to change which protocols are enabled (IPv4 and/or IPv6).\";\n\n/* Common command errors */\n\"atq-93\" = \"Invalid syntax: “%@“\";\n\"pxa-ox\" = \"Cannot find channel named “%@“\";\n\"1fc-vl\" = \"Cannot find query named “%@“\";\n\"zef-q9\" = \"One or more arguments are not properly formatted for this command.\";\n\"g01-qn\" = \"This command can only be used with a channel.\";\n\"m6o-z1\" = \"This command can only be used with a query.\";\n\"sxf-qx\" = \"This command cannot be used within this window.\";\n\"z2r-sd\" = \"Messages cannot be sent to this window.\";\n\n/* Miscellaneous messages related to IRC events */\n\"u51-nn\" = \"%1$@%2$@\"; // RPL_ISUPPORT configuration data\n\"xog-in\" = \"Be back later\";\n\"bg3-h2\" = \"\\002-CTCP-\\002 %1$@ from %2$@ was ignored\";\n\"jer-ju\" = \"CLIENTINFO DCC FINGER PING TIME USERINFO VERSION\";\n\"en6-mw\" = \"Stop fingering me pervert!\";\n\"5wa-lb\" = \"There are no capabilities that are enabled\";\n\"7p9-rs\" = \"The following capabilities are currently enabled: %@\";\n\"obp-ww\" = \"Mode is \\002%@\\002\";\n\"7nm-7v\" = \"Topic is \\002%@\\002\";\n\"y7s-3e\" = \"Set by \\002%1$@\\002 on %2$@\";\n\"8tq-g6\" = \"Website is \\002%@\\002\";\n\"zzj-2h\" = \"Attempting to rejoin channel in three seconds\";\n\"qq2-66\" = \"\\002%1$@\\002 changed the topic to \\002%2$@\\002\";\n\"4vt-ow\" = \"Connection to host established\";\n\"l21-p7\" = \"Connection to host at [%@] established\";\n\"ex4-f8\" = \"Connection secured using %@\";\n\"drg-b7\" = \"Disconnected for Sleep Mode\";\n\"wcl-po\" = \"Disconnected for server redirect\";\n\"zro-bg\" = \"Disconnected from server because of an untrusted certificate\";\n\"isx-fi\" = \"Disconnected from server because the Internet is not reachable\";\n\"9b4-10\" = \"Disconnected\";\n\"bps-la\" = \"%.0f minutes have elapsed since last response from this connection. Disconnecting due to timeout.\";\n\"gzo-54\" = \"%.0f minutes have elapsed since last response from this connection. It's possible the connection is timing out.\";\n\"3yo-gw\" = \"Message(%1$d): %2$@\";\n\"o77-ls\" = \"Connecting to [%1$@] on port %2$hu\";\n\"p7h-un\" = \"Connecting using SOCKS4 proxy [%1$@] on port %2$hu\";\n\"ni5-cy\" = \"Connecting using SOCKS5 proxy [%1$@] on port %2$hu\";\n\"oby-av\" = \"Connecting using HTTP proxy [%1$@] on port %2$hu\";\n\"xxb-y2\" = \"Reconnecting…\";\n\"ky3-36\" = \"Retrying…\";\n\"v5d-ix\" = \"\\002%1$@\\002 sets mode \\002%2$@\\002\";\n\"vy7-pk\" = \"\\002-%1$@ CTCP-\\002 %2$@ (%3$1.5f sec)\";\n\"dri-l7\" = \"\\002-%1$@ CTCP-\\002 %2$@ %3$@\";\n\"6o8-eu\" = \"\\002-CTCP-\\002 %1$@ from %2$@\";\n\"tok-st\" = \"%1$@ (%2$@)\";\n\"8hg-7k\" = \"%@ IRC Network\";\n\"fxw-5s\" = \"%1$@ is now known as \\002%2$@\\002\";\n\"rr6-yo\" = \"You're now known as \\002%@\\002\";\n\"53b-dm\" = \"\\002%1$@\\002 (%2$@@%3$@) left IRC\";\n\"8bk-mx\" = \"\\002%1$@\\002 left the query by disconnecting from IRC\";\n\"q0q-ch\" = \"\\002%1$@\\002 joined the query by connecting to IRC\";\n\"ipj-34\" = \"%@, your user modes are \\002%@\\002\";\n\"wk4-rv\" = \"Inviting %1$@ to join %2$@\";\n\"qw4-t3\" = \"%1$@!%2$@@%3$@ invited you to join %4$@\";\n\"c1h-fq\" = \"%1$@ is away (%2$@)\";\n\"6bh-br\" = \"You are now an IRC Operator on %@\";\n\"ziu-p9\" = \"\\002%1$@\\002 (%2$@@%3$@) joined the channel\";\n\"9aj-bd\" = \"\\002%1$@\\002 kicked \\002%2$@\\002 from the channel (%3$@)\";\n\"nkr-kf\" = \"\\002%1$@\\002 (%2$@@%3$@) left the channel\";\n\"ozy-6i\" = \"%1$@ (%2$@)\";\n\"onk-l5\" = \"%1$@ is in %2$@\";\n\"h19-n2\" = \"%1$@ is connected on %2$@ (%3$@)\";\n\"plg-lr\" = \"%1$@ has userhost %2$@@%3$@ and real name “%4$@”\";\n\"6hn-o6\" = \"%1$@ signed on at %2$@ and has been idle for %3$@\";\n\"cdu-ed\" = \"%1$@ was connected to %2$@ on %3$@\";\n\"32c-87\" = \"%1$@ had userhost %2$@@%3$@ and real name “%4$@”\";\n\"11i-ev\" = \"You cannot send private messages to %@. Anything that you send to them will be ignored until you are added to their list of recognized users.\";\n\"3yj-in\" = \"%1$@ (%2$@) tried to send you a private message, but it was ignored due to \\002umode +g\\002. Perform “/accept %1$@” to allow this user to communicate with you.\";\n\"5i4-qq\" = \"Reconnecting to proxy to rebuild internal state…\"; // irssi proxy\n\"5h5-sl\" = \"Server closed read stream\";\n\"r5h-fj\" = \"Joining channels has been delayed because because you haven't identified. Perform “/autojoin” to join channels without identifying.\";\n\"3oa-mv\" = \"%1$@ is connected from %2$@ (%3$@)\";\n\"x69-rz\" = \"%1$@ was connected from %2$@ (%3$@)\";\n\"js3-9v\" = \"Cannot use nickname “%@“ — Trying another…\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/Notifications.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Notification spoken text */\n/* Address Book spoken text uses the actual notification message for that\n notification type. It is not defined here */\n\n/* Channel messages */\n/* Channel messages are broken up into multiple components so that they\n can be reassembled based on user preference. */\n\"tao-i2\" = \"Channel Message\";\n\"kk4-68\" = \"Channel Notice\";\n\"qld-sa\" = \"Highlight\";\n\"ke8-17\" = \" in %@\";\n\"6nw-ec\" = \" in Private Message\";\n\"qy9-86\" = \" by %@\";\n\"a7i-pu\" = \" from %@\";\n\"g9t-bt\" = \", \"; // separator\n\n/* Other spoken text */\n\"l5i-at\" = \"Invited to %1$@ by %2$@\";\n\"5yu-bf\" = \"Kicked from %1$@ by %2$@\";\n\"rvb-9l\" = \"New Private Message from %1$@, %2$@\";\n\"2bu-ep\" = \"Private Message from %1$@, %2$@\";\n\"6jl-vh\" = \"Private Notice from %1$@, %2$@\";\n\"z4p-yr\" = \"Connected to %@\";\n\"fd0-f8\" = \"Disconnected from %@\";\n\"5e4-vg\" = \"File transfer to %@ completed\";\n\"4cd-p3\" = \"File transfer from %@ completed\";\n\"f0u-32\" = \"File transfer to %@ failed\";\n\"mak-bj\" = \"File transfer from %@ failed\";\n\"at0-vi\" = \"Received file transfer request from %@\";\n\"bwu-ps\" = \"%1$@ joined %2$@\";\n\"vhl-5u\" = \"%1$@ joined\"; // join without channel name (unused)\n\"4aq-hz\" = \"%1$@ parted %2$@\";\n\"nsn-du\" = \"%1$@ parted\"; // part without channel name (unused)\n\"sqf-4y\" = \"%1$@ disconnected\"; // disconnect\n\n/* Notification bubble titles */\n\"niq-32\" = \"Address Book Notification\";\n\"ep5-de\" = \"Channel Message: %@\";\n\"chi-km\" = \"Channel Notice: %@\";\n\"mo1-vn\" = \"Connected: %@\";\n\"7xe-ig\" = \"Disconnected: %@\";\n\"qka-f3\" = \"Highlight: %@\";\n\"g4s-cq\" = \"Invited: %@\";\n\"u30-ia\" = \"Kicked: %@\";\n\"ltn-hf\" = \"New Private Message\";\n\"69i-dy\" = \"Private Message\";\n\"7hn-dg\" = \"Private Notice\";\n\"l5y-sx\" = \"Successful File Transfer: %@\";\n\"hc9-7n\" = \"Successful File Transfer: %@\";\n\"het-vh\" = \"File Transfer Failed: %@\";\n\"hm4-ze\" = \"File Transfer Failed: %@\";\n\"nqz-7v\" = \"File Transfer Request: %@\";\n\"keq-ts\" = \"User Joined: %@\";\n\"im4-p0\" = \"User Parted: %@\";\n\"20x-32\" = \"User Disconnected: %@\";\n\n/* Notification bubble descriptions.\n These are only notifications that require localization. Many notifications\n just send the raw message received so they are not localized here */\n\"88k-kl\" = \"Connection successful\";\n\"bif-2c\" = \"Disconnection successful\";\n\"xl5-dn\" = \"%1$@ invited you to join %2$@\";\n\"fkt-p3\" = \"%1$@ kicked you from %2$@ with reason: %3$@\";\n\"fhn-dd\" = \"%1$@ (%2$qi bytes)\";\n\"oqh-pn\" = \"%1$@ (%2$qi bytes)\";\n\"9r4-cq\" = \"%@\";\n\"cqq-ci\" = \"%@\";\n\"wik-wq\" = \"%1$@ (%2$qi bytes)\";\n\"97r-0l\" = \"User with nickname “%1$@” is available\";\n\"rif-9r\" = \"User with nickname “%1$@” is no longer available\";\n\"xk2-1l\" = \"User with nickname “%1$@” is now available\";\n\"yas-us\" = \"%1$@ joined %2$@\";\n\"bu2-9m\" = \"%1$@ parted %2$@\";\n\"3ur-i8\" = \"%1$@ parted %2$@ with reason: %3$@\";\n\"7ao-n8\" = \"%1$@ disconnected\";\n\"ssw-m6\" = \"%1$@ disconnected with reason: %2$@\";\n\n/* Notification bubble reply button placeholders */\n\"3t4-kl\" = \"Reply\";\n\"bhn-uo\" = \"Send Message\";\n\"do4-2e\" = \"Enter message to reply to this private message\";\n\n/* Notification type titles */\n\"kx3-xk\" = \"Address Book Notification\";\n\"qnz-k4\" = \"Channel Message\";\n\"vuq-jp\" = \"Channel Notice\";\n\"4lr-ej\" = \"Connected\";\n\"wjv-yb\" = \"Disconnected\";\n\"cs4-x9\" = \"Highlight (Mention)\";\n\"eiu-8q\" = \"Channel Invitation\";\n\"2nk-lg\" = \"Kicked from Channel\";\n\"5yi-gu\" = \"Private Message (new)\";\n\"00b-nx\" = \"Private Message\";\n\"nhz-io\" = \"Private Notice\";\n\"0x2-3h\" = \"Successful File Transfer (Sending)\";\n\"qle-7v\" = \"Successful File Transfer (Receiving)\";\n\"sc0-1n\" = \"Failed File Transfer (Sending)\";\n\"we9-1b\" = \"Failed File Transfer (Receiving)\";\n\"st5-0n\" = \"File Transfer Request\";\n\"25q-af\" = \"User Joined Channel\";\n\"k3s-by\" = \"User Parted Channel\";\n\"0fo-bt\" = \"User Disconnected\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/OffTheRecord.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n **********************************************************************\\* */\n\n\"l49-9y\" = \"Off-the-Record Messaging: Private conversation started with an UNRECOGNIZED user. <a href='#' onclick='appPrivate.encryptionAuthenticateUser(); return false;'>Perform authentication</a>.\";\n\"r3w-fj\" = \"Off-the-Record Messaging: Private conversation started with a recognized user.\";\n\n\"rj0-ys\" = \"Off-the-Record Messaging: %@ was successful in confirming their identity.\";\n\"ufr-mh\" = \"Off-the-Record Messaging: %@ FAILED to confirm their identity.\";\n\n\"m1z-eb\" = \"Off-the-Record Messaging: Private conversation has ended.\";\n\n\"f59-3b\" = \"Off-the-Record Messaging: Refreshing the private conversation…\";\n\"aii-2q\" = \"Off-the-Record Messaging: Starting a private conversation…\";\n\n\"jww-e0\" = \"Off-the-Record Messaging: Our policy requires encryption but we are trying to send an unencrypted message. The message visible on your screen will be sent once a private conversation has started.\";\n\"jvt-fi\" = \"Off-the-Record Messaging: An error occurred while encrypting a message. The message was not sent.\";\n\"c5o-2l\" = \"Off-the-Record Messaging: Message has not been sent because the other user has closed the conversation.\";\n\"uhy-85\" = \"Off-the-Record Messaging: A private conversation could not be started.\";\n\"bl0-5i\" = \"Off-the-Record Messaging: Our original message has been sent back to us.\";\n\"c49-q0\" = \"Off-the-Record Messaging: The previous message was resent.\";\n\"6v9-w3\" = \"Off-the-Record Messaging: Received an encrypted message but cannot read it because a private conversation has not been started.\";\n\"9if-xp\" = \"Off-the-Record Messaging: Cannot read the message received.\";\n\"auo-n0\" = \"Off-the-Record Messaging: The message received contains malformed data.\";\n\"nl1-nf\" = \"Off-the-Record Messaging: Received a heartbeat\";\n\"iwt-9f\" = \"Off-the-Record Messaging: Sent a heartbeat\";\n\"2zx-p6\" = \"Off-the-Record Messaging: Received a generic error from the Off-the-Record Messaging library.\";\n\"1lf-f0\" = \"Off-the-Record Messaging: Received an unencrypted message.\";\n\"4by-8j\" = \"Off-the-Record Messaging: The message received was sent in a format that is not recognized.\";\n\"c7t-vi\" = \"Off-the-Record Messaging: Received and discarded a message intended for another instance.\";\n\n\"jrv-gq\" = \"Off-the-Record Messaging: Cannot authenticate user because a private conversation is not active.\";\n\"g9p-8r\" = \"Off-the-Record Messaging: Cannot end private conversation because there is not one that's active.\";\n\n\"8hr-8l\" = \"Requesting an off-the-record private conversation. However, you do not have a plugin to support that. See http://otr.cypherpunks.ca/ for more information.\";\n\n\"anu-ky\" = \"Not Encrypted\";\n\"w34-mg\" = \"Encrypted & Unverified\";\n\"l9n-p9\" = \"Encrypted & Verified\";\n\n\"67n-6j\" = \"Off-the-Record Messaging: The fingerprint for %1$@ is “%2$@” — <a href='#' onclick='appPrivate.encryptionAuthenticateUser(); return false;'>Perform authentication</a>\";\n\n\"mnw-qt\" = \"Are you sure you want to transfer the file named “%@“?\";\n\"nuo-8s\" = \"This file will be sent without encryption.\";\n\"ng0-5q\" = \"Transfer File\";\n\n\"gcg-tv\" = \"Are you sure you want to transfer the file named “%1$@“ to %2$@?\";\n\"7he-76\" = \"This file will be sent without encryption.\";\n\"0v0-ix\" = \"Transfer File\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/Prompts.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"mvh-ms\" = \"Yes\";\n\"99q-gg\" = \"No\";\n\"zjw-bd\" = \"Continue\";\n\"qso-2g\" = \"Cancel\";\n\"c7s-dq\" = \"OK\";\n\"xne-79\" = \"Select\";\n\"ce6-o1\" = \"Choose\";\n\"aqw-q1\" = \"Close\";\n\"qpv-go\" = \"Accept\";\n\"0sy-uc\" = \"Deny\";\n\"u09-hg\" = \"Trust\";\n\"tlp-8e\" = \"Delete\";\n\"71s-kb\" = \"Open\";\n\"ece-dd\" = \"Remind Me Later\";\n\n\"68u-z9\" = \"Do not show this message again\";\n\n\"6vj-2p\" = \"Are you sure you want to quit Textual?\";\n\"77u-vp\" = \"Quitting will disconnect you from any server that you are connected to until you restart Textual.\";\n\"1bf-k0\" = \"Quit\";\n\n\"7gr-e4\" = \"Set User vHost\";\n\"2mx-jf\" = \"Please enter desired vHost (e.g. “apple.vhost”)\";\n\n\"akr-eh\" = \"Enter some text to search for\";\n\"d2w-4o\" = \"The keyboard shortcut ⌘G can be used to continue to the next search result. ⌘⇧G can be used to return to the previous search result.\";\n\"q5h-xx\" = \"Search\";\n\n\"i8o-7z\" = \"Do you want to delete the selection?\";\n\"516-ms\" = \"There is no undo and all data related to this channel, except for logs, will be erased.\";\n\n\"0kz-wd\" = \"Do you want to delete the selection?\";\n\"etl-ss\" = \"There is no undo and all data related to this server, except for logs, will be erased.\";\n\n\"3l6-3z\" = \"You have clicked a link that will connect you to “%1$@“ and join the channel %2$@\";\n\"mx1-qz\" = \"The connection named “%1$@“ is already configured to connect to this server address.\n\nDo you want to add this channel to that connection or would you rather create a new connection?\";\n\"sl5-rf\" = \"Use Existing Connection\";\n\"xca-5h\" = \"Create New Connection\";\n\n\"pnc-ew\" = \"You have clicked a link that will connect you to “%1$@“ and join the channels: %2$@\";\n\"a9z-9f\" = \"The connection named “%1$@“ is already configured to connect to this server address.\n\nDo you want to add these channels to that connection or would you rather create a new connection?\";\n\"0hh-sl\" = \"Use Existing Connection\";\n\"sv9-8s\" = \"Create New Connection\";\n\n\"82q-zi\" = \"Are you sure you wish to enable inline media?\";\n\"vcq-sz\" = \"Inline media does not use the proxy you may have configured for connecting to IRC. Your IP address will be leaked without configuring a system-wide proxy. If you wish to configure a proxy before continuing, click the “Open System Settings” button.\";\n\"xkj-nw\" = \"Turn On\";\n\"x3e-ur\" = \"Open System Settings\";\n\n\"9mb-o5\" = \"An update is available for these addons: %@\";\n\"x4w-is\" = \"Would you like to open the “Textual Extras” installer to perform an update?\";\n\"ioq-nf\" = \"Open Installer\";\n\n\"ins-op\" = \"An update is required for these addons: %@\";\n\"34o-pk\" = \"These addons will not be available for use until they are updated.\n\nWould you like to open the “Textual Extras” installer to perform an update?\";\n\"hd0-bf\" = \"Remind Me Next Launch\";\n\"467-5l\" = \"Open Installer\";\n\"h78-9e\" = \"View Files\";\n\n\"af6-45\" = \"The version of Textual that you are using is no longer compatible with these addons: %@\";\n\"45a-df\" = \"Please contact the developer of each addon to receive information on updating.\n\nIf you are the developer of one of these addons: In the Info.plist file of your project, set the value of the property “MinimumTextualVersion” to “%@“, then rebuild to check for any errors.\";\n\"324-5d\" = \"Remind Me Next Launch\";\n\"0ik-o9\" = \"View Files\";\n\n\"o9p-4n\" = \"The “Textual Extras” package must be installed to perform the command “%@”\";\n\"bpb-vv\" = \"Would you like to open the installer?\";\n\"6lr-02\" = \"Open Installer\";\n\n\"2ul-cl\" = \"You have clicked on a link that will open the application “%@”\";\n\"5oq-vv\" = \"Are you sure you want to open “%@” with this application?\";\n\n\"hcb-3i\" = \"Preferences may become corrupted if you have more than one copy of Textual open\";\n\"kx4-q8\" = \"Are you sure you want to continue?\";\n\n\"py0-cr\" = \"The style named “%@” is not designed to work with this version of Textual\";\n\"76t-pn\" = \"Some features will not work correctly with this style selected.\";\n\"2a3-5s\" = \"Choose Different Style\";\n\n\"ezn-rm\" = \"The style named “%@” wants to enable dark mode but styles are no longer allowed to change that preference\";\n\"193-6o\" = \"Do you want to keep Textual's light appearance or switch to dark mode?\";\n\"hf0-w3\" = \"Keep It Light\";\n\"hv0-79\" = \"Paint It Black\";\n\n\"fjw-hj\" = \"The style named “%@” has been modified in such a way that it can no longer be used\";\n\"3wd-gj\" = \"This usually occurs when one or more critical files have been moved or deleted.\";\n\"c4z-2b\" = \"Choose Different Style\";\n\n\"1fm-up\" = \"This action will save a copy of your configuration to a location of your choice\";\n\"syp-al\" = \"Please note that the following items cannot be exported: custom addons, file transfer download location, log location, and passwords.\";\n\"vun-f0\" = \"Save File\";\n\n\"itb-3x\" = \"This action will overwrite your configuration with the contents of a file you choose\";\n\"jsh-1a\" = \"Please note that the following items cannot be imported: custom addons, file transfer download location, log location, and passwords.\";\n\"502-6h\" = \"Choose File\";\n\n\"6hx-ni\" = \"Save\";\n\"0bj-ic\" = \"To install this script, save it inside the folder:\n[home folder] \\U279C Library \\U279C Application Scripts \\U279C %@\n\nCreate this folder if it does not exist.\";\n\n\"m2r-gv\" = \"A script cannot be saved here\";\n\"ztu-nv\" = \"\";\n\n\"4ua-v5\" = \"The script named “%@” has been successfully installed\";\n\"3ze-xh\" = \"Type “/%@” into the main input text field to perform this script.\";\n\n\"xek-0t\" = \"The extension named “%@” has been successfully installed\";\n\"k69-q0\" = \"Restart Textual to load this extension.\";\n\n\"xfl-8e\" = \"Are you sure you want to open the file named “%@” with Textual?\";\n\"6tj-yp\" = \"\";\n\n\"k55-19\" = \"No logs were found\";\n\"f05-hu\" = \"\";\n\n\"b7o-v4\" = \"Textual is unable to access the folder that's configured for your log location because the resource is 'stale'\";\n\"atn-1c\" = \"Navigate to Preferences \\U279C Advanced \\U279C Log Location to repair this preference\";\n\n\"h99-3q\" = \"The process responsible for managing scrollback is not working correctly. Please report this problem to support@codeux.com\";\n\"nlz-um\" = \"Last known error message: %@\";\n\n\"d22-76\" = \"A query named “%@“ already exists. Do you want to delete this query?\";\n\"61s-jc\" = \"There is no undo and all data related to this query, except for logs, will be erased.\";\n\n\"bi7-ah\" = \"Logging has been disabled because there is not enough space on your Mac\";\n\"v9e-jy\" = \"Logging will resume when there is free space available.\";\n\n\"m8b-58\" = \"Textual can’t verify the identity of the server “%@”\";\n\"85z-qw\" = \"The certificate for this server is invalid. You might be connecting to a server that is pretending to be “%@”, which could put your confidential information at risk. Would you like to connect to the server anyway?\";\n\n\"sfx-xx\" = \"Textual is using an encrypted connection to “%@“\";\n\"ihy-mz\" = \"Encryption with a digital certificate keeps information private as it’s sent to or from the server “%1$@“\";\n\"iun-45\" = \"Encryption with a digital certificate keeps information private as it’s sent to or from the server “%1$@“\n\nInformation encrypted using: %2$@\";\n\n\"2jq-t5\" = \"%1$@ with the cipher suite: %2$@\";\n\"8ou-pu\" = \"%1$@ with the cipher suite: %2$@ (deprecated)\";\n\n\"ujw-64\" = \"The “Inspect Element” feature of WebKit2 cannot be accessed on this version of macOS.\";\n\"kig-m1\" = \"Disable WebKit2 or upgrade to a newer version of macOS.\";\n\n\"ios-na\" = \"Textual has copied the following content to a new location your Mac:\";\n\"qy4-5o\" = \"Caches, custom addons, custom styles, encryption keys, preferences, and scrollback history.\n\nWould you like to clear up disk space by removing this content from the old location?\";\n\"q3t-45\" = \"I would like to remove the old content\";\n\"d90-au\" = \"Learn More\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCAboutDialog.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"zjd-al\" = \"Version %@\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCAddressBookSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"csu-bv\" = \"Please enter a properly formatted ignore mask.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelBanListSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"rhc-ke\" = \"Bans in %@\";\n\"gbi-wn\" = \"Ban Exceptions in %@\";\n\"ylc-6e\" = \"Invite Exceptions in %@\";\n\"g4r-t6\" = \"Quiets in %@\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelInviteSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"c8p-sb\" = \"%ld users\";\n\"0lg-er\" = \"Invite %@ to:\";\n\"7i1-ds\" = \"%1$@ and %2$@\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelModifyModesSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"7m9-39\" = \"You have exceeded the secret key length defined by %1$@ which is %2$ld characters\";\n\"lir-ra\" = \"If you continue typing, the end of your secret key may be cut off.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelModifyTopicSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"27l-qx\" = \"You have exceeded the maximum topic length defined by %1$@ which is %2$ld characters\";\n\"zm4-cr\" = \"If you continue typing, the end of your topic may be cut off.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelPropertiesSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"zf2-r7\" = \"You have exceeded the secret key length defined by %1$@ which is %2$ld characters\";\n\"op4-gg\" = \"If you continue typing, the end of your secret key may be cut off.\";\n\n\"1nd-7x\" = \"Please enter a properly formatted channel name.\";\n\n\"mvl-r5\" = \"This channel's configuration has changed. Do you want to reload the Channel Properties dialog?\";\n\"qby-hi\" = \"You will loose unsaved changes if you click “Yes”\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCChannelSpotlightController.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"jpw-cj\" = \"%@\";\n\"z68-5q\" = \" on %@\";\n\n\"43s-x4\" = \"%@ unread message\";\n\"vzj-30\" = \"%@ unread messages\";\n\"0lz-oh\" = \"%@ highlight\";\n\"c4u-21\" = \"%@ highlights\";\n\"et7-c5\" = \"%1$@, %2$@\";\n\n\"tyv-p6\" = \"No Results\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCFileTransferDialog.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"nvm-nd\" = \"%1$@ of %2$@ (%3$@/s) sent to %4$@\";\n\"u17-ql\" = \"%1$@ of %2$@ (%3$@/s) sent to %4$@ — %5$@ remaining\";\n\n\"w3h-p8\" = \"Transfer to %@ is stopped. Control click to start.\";\n\"j1z-88\" = \"Transfer to %@: Attempting to map listening port\";\n\"onl-av\" = \"Transfer to %@: Determining local IP address\";\n\"pcv-kg\" = \"Transfer to %@ is initializing\";\n\"ca5-2v\" = \"Transfer to %@ is ready. Waiting for them to accept.\";\n\"rx7-xy\" = \"Transfer to %@ is complete\";\n\"cku-24\" = \"Transfer to %@ is ready. Waiting for them to accept.\";\n\n\"7dk-lp\" = \"%1$@ of %2$@ (%3$@/s) received from %4$@\";\n\"9xn-7j\" = \"%1$@ of %2$@ (%3$@/s) received from %4$@ — %5$@ remaining\";\n\n\"jvh-u7\" = \"Transfer from %@ is stopped. Control click to start.\";\n\"495-90\" = \"Transfer from %@: Attempting to map listening port\";\n\"6t1-mb\" = \"Transfer from %@: Determining local IP address\";\n\"gxq-zu\" = \"Transfer from %@: Waiting for response to resume transfer\";\n\"42z-mg\" = \"Transfer from %@ is initializing\";\n\"pip-z6\" = \"Transfer from %@ is ready. Control click to start.\";\n\"6gu-za\" = \"Transfer from %@ is complete. Control click to open in Finder.\";\n\n\"7nf-fr\" = \"Connecting to %@\";\n\n\"fn8-sx\" = \"Transfer with %@ failed. Could not establish connection\";\n\"vxc-sd\" = \"Transfer with %@ failed. There is no open port\";\n\"nab-dx\" = \"Transfer with %@ failed. Could not read source file\";\n\"47s-1s\" = \"Transfer with %@ failed. Unknown source IP address\";\n\"coa-ii\" = \"Transfer with %@ failed. Connection was disconnected\";\n\"0ov-tr\" = \"Transfer with %@ failed. Proposed resume position is bad\";\n\"12p-0v\" = \"Transfer with %@ failed. You are not connected to IRC\";\n\"79f-s0\" = \"Transfer with %@ failed. No space left on device\";\n\"05g-c8\" = \"Transfer with %@ failed. File handler threw an exception\";\n\"s79-3a\" = \"Transfer with %@ failed: %@\";\n\n\"dcm-w7\" = \"Select the folder in which this file will be saved\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCLicenseUpgradeEligibilitySheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"wmk-xg\" = \"A problem was encountered when checking the upgrade eligibility for the license key “%@”\";\n\"8hb-y3\" = \"%@\\n\\nTry again in a few minutes then contact support if the problem persists.\";\n\"dn3-4r\" = \"Contact Support\";\n\n\"awy-4i\" = \"Service returned a non-zero response code: %ld\";\n\"z70-6s\" = \"Service returned an empty status context.\";\n\"gc5-ko\" = \"Service returned an malformed status context.\";\n\"5s6-sb\" = \"Service returned an unusual eligibility: %lu\";\n\"9uu-go\" = \"Request cannot be completed at this time because it was rate limited.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCPreferencesController.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"70s-c6\" = \"No Log Location Selected\";\n\"721-ie\" = \"No Location Selected\";\n\n\"5jv-aw\" = \"Are you opening this style because you are interested in modifying it?\";\n\"ojj-ap\" = \"It’s possible to modify the appearance of this style without editing its source files.\n\nClick “Edit Style” to add your own style sheet rules. This feature can also be found in the Developers section of Preferences.\";\n\"aib-iy\" = \"Edit Style\";\n\"dj8-1t\" = \"Create Copy\";\n\"6ws-av\" = \"View Files\";\n\n\"uc0-z7\" = \"Preferred Selection\";\n\"q4o-2f\" = \"The style named “%1$@” has chosen to override the following preferences with ones that it prefers for the best viewing experience:\\n\\n%2$@\";\n\n\"77t-de\" = \"• Nickname Format\";\n\"ddh-hr\" = \"• Timestamp Format\";\n\"we8-i8\" = \"• Channel View Font\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCPreferencesUserStyleSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2019 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"q4s-3m\" = \"/*\n\n!!! WARNING: THIS IS DESIGNED FOR ADVANCED USERS. !!!\n\nStyles are written in HTML which means custom rules should be\nwritten in CSS: https://developer.mozilla.org/en-US/docs/Web/CSS\n\n- Example: \n\n#topicBar {\n\tdisplay: none;\n}\n\nTextual does not perform sanitation in any form on your rules\nwhich means you could possibly abuse this feature by escaping\nfrom the style element and inserting JavaScript or other code.\n\n*/\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCServerChannelListDialog.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"7qf-r0\" = \"Channel List for “%@”\";\n\"ct4-wh\" = \"Channel List — %@ Public Channels\"; // %@ = channel count.\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCServerEndpointListSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"iis-gr\" = \"The value you entered is not a properly formatted server address\";\n\"k0c-3u\" = \"\";\n\n\"qeb-ip\" = \"The value you entered is not a properly formatted server port\";\n\"ox2-od\" = \"Enter a whole number between 1 and 65,535.\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TDCServerPropertiesSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Server properties Address Book entry types */\n\"f7o-x4\" = \"User Ignore\";\n\"b0g-0x\" = \"User Tracking\";\n\n/* Server specific highlight entry things */\n\"61f-6b\" = \"All Channels\";\n\"qcc-b4\" = \"Exclude\";\n\"tet-dk\" = \"Match\";\n\n/* Server properties navigation menu */\n\"lww-pc\" = \"Server Properties\";\n\"v27-8w\" = \"Vendor Specific\";\n\"8uw-tz\" = \"Advanced\";\n\"8zc-6y\" = \"Address Book\";\n\"5oz-07\" = \"Channel List\";\n\"hip-13\" = \"Connect Commands\";\n\"8ug-ka\" = \"Encoding\";\n\"ehx-4d\" = \"General\";\n\"8ik-qo\" = \"Identity\";\n\"jtx-hn\" = \"Highlights\";\n\"j34-yr\" = \"Messages\";\n\"fsj-7f\" = \"ZNC Bouncer\";\n\"ce7-kc\" = \"Client Certificate\";\n\"fcr-w8\" = \"Flood Control\";\n\"ffy-xt\" = \"Network Socket\";\n\"t52-7a\" = \"Proxy Server\";\n\"36n-u9\" = \"Redundancy\";\n\n/* Error localizations */\n\"8iw-q8\" = \"Please enter a properly formatted username.\";\n\"agy-bp\" = \"Please enter a properly formatted real name.\";\n\"tlo-b6\" = \"Please enter a properly formatted proxy address.\";\n\"wlz-tb\" = \"Please enter a list of properly formatted nicknames.\n\nFailed on nickname: “%@“\n\nList of nicknames should be space separated.\nFor example: “Guest1 Guest2 Guest3“\";\n\n/* Custom client-side certificate selection */\n\"6xz-ec\" = \"No Certificate Selected\";\n\n\"6wq-i4\" = \"Choose An Identity\";\n\"mi4-fd\" = \"Select a certificate to send when you connect securely.\";\n\n\"pmk-os\" = \"No Certificates Available\";\n\"489-hG\" = \"There are no certificates in the keychain configured for identity purposes.\n\nCertificates must meet the following criteria:\n\t• Certificate is configured as type: “SSL Client”\n\t• Certificate has matching private key\";\n\"3ju-lo\" = \"Learn to Create a Certificate\";\n\n/* Cipher suites */\n\"yko-5g\" = \"The “%@” includes the following cipher suites:\";\n\"k50-8n\" = \"%@\\n\\nThese cipher suites are ordered by preference with the most preferred at the top.\";\n\n/* Enabling wait for NickServ without a password */\n\"94r-eq\" = \"The preference you have enabled will not work correctly because you do not have a password set\";\n\"26u-j8\" = \"Enter your NickServ password into the field labeled “Personal Password”\";\n\n/* Cloud changes */\n\"bzh-il\" = \"This connection's configuration has changed. Do you want to reload the Server Properties dialog?\";\n\"oz4-kb\" = \"You will loose unsaved changes if you click “Yes”\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TLOLicenseManager.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"nhh-ts\" = \"A problem was encountered while communicating with the web server located at codeux.com\";\n\"1cv-0v\" = \"Try again in a few minutes then contact support if the problem persists.\";\n\"bqw-cv\" = \"Contact Support\";\n\n\"13u-4p\" = \"codeux.com has denied your request because too many requests have been received in a short period of time\";\n\"fvx-90\" = \"Access to license information for Textual is rate limited to prevent misuse or abuse. Please try again in a few minutes.\";\n\n\"u8h-qv\" = \"The license key “%@“ cannot be activated because it is blacklisted\";\n\"w1n-n0\" = \"Contact support for more information.\";\n\"vgp-j6\" = \"Contact Support\";\n\n\"ocm-03\" = \"The following error was returned while processing request:\";\n\"dio-y9\" = \"Improperly formatted e-mail address or missing\";\n\n\"fg6-gf\" = \"The following error was returned while processing request:\";\n\"wc7-mn\" = \"Unknown or improperly formatted license key\";\n\n\"m4q-ul\" = \"Successfully queued e-mail for %@\";\n\"fxj-s6\" = \"An e-mail which contains your license key will be delivered to %@ within the next few minutes.\";\n\n\"jbs-64\" = \"Thank you for your purchase of Textual!\";\n\"k39-7l\" = \"All limitations have been lifted.\";\n\n\"pg1-a9\" = \"Are you sure you want to deactivate this copy of Textual?\";\n\"z87-wb\" = \"All limitations that apply to the trial version of Textual will immediately take effect once deactivated.\";\n\n\"vft-qo\" = \"Select a copy of Textual downloaded from the Mac App Store to receive a license key. You can download a new copy at any time in the Purchases section of your Mac App Store account.\";\n\n\"b6l-ka\" = \"The application “%@“ cannot be used to request a license key\";\n\"sdj-xd\" = \"This application is not Textual 5 or a newer version, or was not downloaded from the Mac App Store.\";\n\n\"vxq-oa\" = \"Successfully migrated Mac App Store purchase\";\n\"yxk-ej\" = \"An e-mail which contains your license key will be delivered to %@ within the next few minutes.\";\n\n\"enb-hw\" = \"Cannot migrate Mac App Store purchase because it has already been migrated\";\n\"36y-49\" = \"Click the “Recover Lost License” button if you have lost your license key.\";\n\n\"ztd-5y\" = \"The following error was returned while processing request:\";\n\"bu4-zk\" = \"Improperly formatted e-mail address or is missing\";\n\n\"r87-jw\" = \"The following error was returned while processing request:\";\n\"6zh-jr\" = \"Unable to locate an order that is linked to the e-mail address “%@“\";\n\n\"o66-ox\" = \"The license key “%@“ has exceeded its daily activation limit\";\n\"6aa-ow\" = \"This license key cannot be activated more than %ld times within a twenty-four (24) hour period. Please try again at a later time.\";\n\n\"wdl-3f\" = \"Your trial of Textual will expire in %@\";\n\"kn7-ju\" = \"Your trial of Textual has expired.\";\n\n\"ccj-ag\" = \"Please purchase Textual to prevent disruption to your chat experience.\";\n\"b8b-sg\" = \"More Info\";\n\n\"f49-rk\" = \"The following error was returned while processing request:\";\n\"do9-8x\" = \"Improperly formatted name or is missing\";\n\n\"p9s-ak\" = \"The following error was returned while processing request:\";\n\"ujo-cd\" = \"Receipt did not pass validation because of the following error:\\n\\n“%@“\";\n\n\"0uc-io\" = \"The license key “%@“ cannot be activated because another operation is already in progress\";\n\"vnu-5e\" = \"\";\n\n\"bw3-sc\" = \"The license key “%@“ cannot be activated because it is already in use\";\n\"fxu-su\" = \"\";\n\n\"pmv-qp\" = \"The license key “%@“ cannot be activated because it requires an upgrade\";\n\"5bu-ov\" = \"\";\n\"53u-lt\" = \"Learn More\";\n\n\"t28-j9\" = \"Cannot migrate Mac App Store purchase because the appropriate in-app purchase is missing\";\n\"4n2-ps\" = \"The Standard Edition in-app purchase is required to perform migration.\";\n\n\"12h-3w\" = \"Are you sure you want to purchase a new license key?\";\n\"dpo-ln\" = \"You already own the license key “%@.”\";\n\"qrx-aq\" = \"Upgrade Existing License Key\";\n\"zp8-8q\" = \"Purchase New License Key\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TVCMainWindow.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"tjj-z2\" = \"No Privileges\";\n\"ya1-sk\" = \"Voice\";\n\"0nn-te\" = \"Half-op\";\n\"0kn-s5\" = \"Operator\";\n\"som-zo\" = \"Super Admin\";\n\"p1z-sc\" = \"Channel Owner\";\n\"i8t-vb\" = \"Server Staff Member (IRC Operator)\";\n\"jkr-ed\" = \"User is away\";\n\"gi6-wf\" = \"User is not away\";\n\n\"d85-9n\" = \"Information Not Available\";\n\n\"8r3-ih\" = \"Send message…\";\n\n\"jqk-ha\" = \" — \";\n\"cyg-g9\" = \" (%@)\";\n\"v6i-zb\" = \" (%@ users)\";\n\"19v-bc\" = \"%1$@%2$@ on %3$@\";\n\"q42-an\" = \"Disconnected — \";\n\"xqd-h9\" = \"Disconnecting… — \";\n\"8eu-c7\" = \"Connecting… — \";\n\"wcb-y8\" = \"Logging on… — \";\n\"s23-zd\" = \"Reconnecting… — \";\n\"3yn-wd\" = \"Waiting to reconnect… — \";\n\"nxz-l9\" = \" (away)\";\n\"6wz-pd\" = \"%1$@ (%2$@)\";\n\n\"iph-a9\" = \"Loading configuration…\";\n\"5g1-i9\" = \"Importing preferences…\";\n\n\"4yo-mk\" = \"Current Session\";\n\n\"vi3-23\" = \"(No Topic)\";\n"
  },
  {
    "path": "Sources/App/Resources/Language Files/en.lproj/TVCNotificationConfigurationView.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"vje-9n\" = \"No Sound\";\n\"0rs-8l\" = \"Default Sound\";\n"
  },
  {
    "path": "Sources/App/Resources/License Manager/RemoteLicenseSystemPublicKey.pub",
    "content": "-----BEGIN RSA PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7ZYeINFUwe5zOpGqIKUD\nohdMprjucrmhnCMJndVTJLlHDdttKdfXF8ar39EGkh/WeEDL6i/tLaMYzXEkRWzJ\na/ZKY0j6L4MFfAn3Div+HtAAKKp4Ag4dCJALsfaldhz0wapEttifs+H7cDqX1sbC\nlQQzFJNOufdLf1bTJqXnnnt/dB6D7xK1Poe/T1meTjWbJISpujm6bib3n8GyOTbB\ndQMBd8RiGD6t9Scm6feoESVAVJviCMS+/IHWtVp0EenStqzFgy/zl4R9Op5ypoYY\nUo8Ul6Q/pS/OpAH/plJ/8duAbvuTy5fWo7MNbgHV7DfYLk2FrXKgyUgjEjOfyfpF\noSpuWbV52nPeYf3lgyIgqVif6eF/LEoIqMk1nDUrspWAkg2FHqTgik5nKo1fuezq\nLT2BkdV+nSee7ZjmWcSQD3Lb/D826Zb5EJcpvlK4dw2QX4VtQ4dHeGRmnA04/IDd\nqAAJ0fwzVGItehwuhbtPYFFdEHbMpqqTRTKu9BvRfc3zd79b2VXIIjQykPVafc6o\nAnUiXZStO9vvstXjwnG4pKzCKdy3IRKgn4gNp91wHwOlY6mgRoEEHb5q1jtj0ZiR\nLr7oKr4UK6a3/KxmVRKcIIhHQZ16iKWTwOp3kx/OX9jNMF13tr4fgUAAuuPnowIB\nCBA1ua7CrIfxIbUM7PscG2sCAwEAAQ==\n-----END RSA PUBLIC KEY-----\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Application Properties/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>LSApplicationCategoryType</key>\n\t<string>public.app-category.social-networking</string>\n\t<key>LSRequiresNativeExecution</key>\n\t<false/>\n\t<key>CFBundleSignature</key>\n\t<string>TXTL</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Textual IRC Client</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleVersion</key>\n\t<string>7.2.6</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>7.2.6</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2010 - 2023 Codeux Software, LLC. All rights reserved.</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIconFile</key>\n\t<string>applicationIcon.icns</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>NSMainNibFile</key>\n\t<string>TXCMainMenu</string>\n\t<key>LSMinimumSystemVersion</key>\n\t<string>11.0</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TXApplication</string>\n\t<key>NSContactsUsageDescription</key>\n\t<string>Textual accesses contacts to automatically populate certain forms with your name and/or e-mail address. Access to this information is not required.</string>\n\t<key>NSAppleScriptEnabled</key>\n\t<true/>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n\t<key>CFBundleDocumentTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>scpt</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>Textual IRC Client Script</string>\n\t\t\t<key>CFBundleTypeOSTypes</key>\n\t\t\t<array>\n\t\t\t\t<string>****</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>TPCResourceManagerDocumentTypeImporter</string>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeExtensions</key>\n\t\t\t<array>\n\t\t\t\t<string>bundle</string>\n\t\t\t</array>\n\t\t\t<key>CFBundleTypeName</key>\n\t\t\t<string>Textual IRC Client Extension</string>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Editor</string>\n\t\t\t<key>LSHandlerRank</key>\n\t\t\t<string>Alternate</string>\n\t\t\t<key>LSTypeIsPackage</key>\n\t\t\t<integer>1</integer>\n\t\t\t<key>NSDocumentClass</key>\n\t\t\t<string>TPCResourceManagerDocumentTypeImporter</string>\n\t\t</dict>\n\t</array>\n\t<key>CFBundleURLTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>CFBundleTypeRole</key>\n\t\t\t<string>Viewer</string>\n\t\t\t<key>CFBundleURLIconFile</key>\n\t\t\t<string>application</string>\n\t\t\t<key>CFBundleURLName</key>\n\t\t\t<string>Internet Relay Chat</string>\n\t\t\t<key>CFBundleURLSchemes</key>\n\t\t\t<array>\n\t\t\t\t<string>irc</string>\n\t\t\t\t<string>ircs</string>\n\t\t\t\t<string>textual</string>\n\t\t\t</array>\n\t\t</dict>\n\t</array>\n\t<key>SUAllowsAutomaticUpdates</key>\n\t<true/>\n\t<key>SUBundleName</key>\n\t<string>Textual</string>\n\t<key>SUEnableDownloaderService</key>\n\t<false/>\n\t<key>SUEnableInstallerLauncherService</key>\n\t<true/>\n\t<key>SUEnableSystemProfiling</key>\n\t<false/>\n\t<key>SUFeedURL</key>\n\t<string>https://updates.textualapp.com/sparkle/feeds/v7/feed-one-merged.xml</string>\n\t<key>SUScheduledCheckInterval</key>\n\t<string>345600</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/IRCCommandIndexLocalData.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Reserved Information</key>\n\t<dict>\n\t\t<key>Next Index Value</key>\n\t\t<real>5119</real>\n\t</dict>\n\t<key>adchat</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5001</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>ame</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5002</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>amsg</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5003</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>aquote</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5095</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;input&gt;</string>\n\t</dict>\n\t<key>araw</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5096</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;input&gt;</string>\n\t</dict>\n\t<key>autojoin</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5101</real>\n\t</dict>\n\t<key>away</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5004</integer>\n\t\t<key>arguments</key>\n\t\t<string>[comment]</string>\n\t</dict>\n\t<key>back</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5105</integer>\n\t</dict>\n\t<key>ban</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5005</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>cap</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5006</integer>\n\t</dict>\n\t<key>caps</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5007</integer>\n\t</dict>\n\t<key>chatops</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5009</integer>\n\t</dict>\n\t<key>clear</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5010</integer>\n\t</dict>\n\t<key>clearall</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5011</integer>\n\t</dict>\n\t<key>close</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5012</integer>\n\t\t<key>arguments</key>\n\t\t<string>[target]</string>\n\t</dict>\n\t<key>conn</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5013</integer>\n\t\t<key>arguments</key>\n\t\t<string>[server]</string>\n\t</dict>\n\t<key>ctcp</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5014</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt; &lt;command&gt; [extra]</string>\n\t</dict>\n\t<key>ctcpreply</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5015</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt; &lt;command&gt; [extra]</string>\n\t</dict>\n\t<key>cycle</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5016</integer>\n\t</dict>\n\t<key>dcc</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5017</integer>\n\t</dict>\n\t<key>debug</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5018</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>defaults</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5092</integer>\n\t\t<key>New item</key>\n\t\t<string>&lt;enable | disable&gt; [-a] &lt;feature&gt;</string>\n\t</dict>\n\t<key>dehalfop</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5019</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>deop</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5020</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>devoice</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5021</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>echo</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5022</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>getscripts</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5098</integer>\n\t</dict>\n\t<key>gline</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5023</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;+ | -&gt;&lt;hostmask | nickname&gt; [duration] [comment]</string>\n\t</dict>\n\t<key>globops</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5024</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>goto</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5099</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;needle&gt;</string>\n\t</dict>\n\t<key>gzline</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5025</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;+ | -&gt;&lt;hostmask | nickname&gt; [duration] [comment]</string>\n\t</dict>\n\t<key>halfop</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5026</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>hop</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5027</integer>\n\t</dict>\n\t<key>ignore</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5029</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>invite</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5030</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt; [channel]</string>\n\t</dict>\n\t<key>ison</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5100</real>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>j</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5031</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel[,channel]]&gt; [key[,key]]</string>\n\t</dict>\n\t<key>join</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5032</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel[,channel]]&gt; [key[,key]]</string>\n\t</dict>\n\t<key>join_random</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<true/>\n\t\t<key>indexValue</key>\n\t\t<real>5109</real>\n\t\t<key>arguments</key>\n\t\t<string>[count]</string>\n\t</dict>\n\t<key>kb</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5083</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt; [comment]</string>\n\t</dict>\n\t<key>kick</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5033</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt; [comment]</string>\n\t</dict>\n\t<key>kickban</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5034</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt; [comment]</string>\n\t</dict>\n\t<key>kill</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5035</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt; [comment]</string>\n\t</dict>\n\t<key>lagcheck</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5084</integer>\n\t</dict>\n\t<key>leave</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5036</integer>\n\t\t<key>arguments</key>\n\t\t<string>[comment]</string>\n\t</dict>\n\t<key>list</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5037</integer>\n\t</dict>\n\t<key>locops</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5039</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>m</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5040</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target&gt; [flags] [arguments]</string>\n\t</dict>\n\t<key>me</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5041</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>mode</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5042</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target&gt; [flags] [arguments]</string>\n\t</dict>\n\t<key>monitor</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5106</real>\n\t</dict>\n\t<key>msg</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5043</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target[,target]]&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>mute</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5044</integer>\n\t</dict>\n\t<key>mylag</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5045</integer>\n\t</dict>\n\t<key>myversion</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5046</integer>\n\t</dict>\n\t<key>nachat</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5047</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>names</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5094</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt;</string>\n\t</dict>\n\t<key>nick</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5048</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>notice</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5050</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target[,target]]&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>notifybubble</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5112</real>\n\t\t<key>arguments</key>\n\t\t<string>[target] &lt;message&gt;</string>\n\t</dict>\n\t<key>notifysound</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5113</real>\n\t\t<key>arguments</key>\n\t\t<string>&lt;sound&gt;</string>\n\t</dict>\n\t<key>notifyspeak</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5114</real>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>omsg</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5051</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>onotice</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5052</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>op</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5053</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>part</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5054</integer>\n\t\t<key>arguments</key>\n\t\t<string>[comment]</string>\n\t</dict>\n\t<key>pass</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5055</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;password&gt;</string>\n\t</dict>\n\t<key>query</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5056</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>quit</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5057</integer>\n\t\t<key>arguments</key>\n\t\t<string>[comment]</string>\n\t</dict>\n\t<key>quiet</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5107</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>quote</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5058</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;input&gt;</string>\n\t</dict>\n\t<key>raw</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5059</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;input&gt;</string>\n\t</dict>\n\t<key>recv</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<true/>\n\t\t<key>indexValue</key>\n\t\t<integer>5087</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;input&gt;</string>\n\t</dict>\n\t<key>rejoin</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5060</integer>\n\t</dict>\n\t<key>remove</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5061</integer>\n\t\t<key>arguments</key>\n\t\t<string>[target]</string>\n\t</dict>\n\t<key>server</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5062</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;address&gt; [[+] port] [password]</string>\n\t</dict>\n\t<key>setcolor</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5103</real>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>setqueryname</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<real>5117</real>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>shun</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5063</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;+ | -&gt;&lt;hostmask | nickname&gt; [duration] [comment]</string>\n\t</dict>\n\t<key>sme</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5064</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target[,target]]&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>smsg</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5065</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target[,target]]&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>sslcontext</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5066</integer>\n\t</dict>\n\t<key>t</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5067</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt; [topic]</string>\n\t</dict>\n\t<key>tage</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<true/>\n\t\t<key>indexValue</key>\n\t\t<integer>5093</integer>\n\t</dict>\n\t<key>tempshun</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5068</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;+ | -&gt;&lt;hostmask | nickname&gt; [comment]</string>\n\t</dict>\n\t<key>timer</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5069</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;seconds&gt; &lt;repeat&gt; &lt;command&gt;</string>\n\t</dict>\n\t<key>topic</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5070</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt; [topic]</string>\n\t</dict>\n\t<key>ume</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5089</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>umode</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5071</integer>\n\t\t<key>arguments</key>\n\t\t<string>[flags] [arguments]</string>\n\t</dict>\n\t<key>umsg</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5088</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>unban</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5072</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>unignore</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5073</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>unmute</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5075</integer>\n\t</dict>\n\t<key>unotice</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5090</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;target&gt; &lt;message&gt;</string>\n\t</dict>\n\t<key>unquiet</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5108</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>voice</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5076</integer>\n\t\t<key>arguments</key>\n\t\t<string>[channel] &lt;nickname&gt;</string>\n\t</dict>\n\t<key>wallops</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5077</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;message&gt;</string>\n\t</dict>\n\t<key>watch</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5097</integer>\n\t</dict>\n\t<key>weights</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5118</integer>\n\t</dict>\n\t<key>who</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5079</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;channel&gt;</string>\n\t</dict>\n\t<key>whois</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5080</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>whowas</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5081</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;nickname&gt;</string>\n\t</dict>\n\t<key>zline</key>\n\t<dict>\n\t\t<key>developerModeOnly</key>\n\t\t<false/>\n\t\t<key>indexValue</key>\n\t\t<integer>5082</integer>\n\t\t<key>arguments</key>\n\t\t<string>&lt;+ | -&gt;&lt;hostmask | nickname&gt; [duration] [comment]</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/IRCCommandIndexRemoteData.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Reserved Information</key>\n\t<dict>\n\t\t<key>Next Index Value</key>\n\t\t<real>1058</real>\n\t</dict>\n\t<key>adchat</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1003</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>away</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1050</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>authenticate</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1005</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>batch</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<real>1054</real>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>cap</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1004</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>certinfo</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<real>1055</real>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>chatops</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1006</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>chghost</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<real>1057</real>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>error</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1016</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>gline</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1047</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>2</integer>\n\t</dict>\n\t<key>globops</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1017</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>gzline</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1048</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>2</integer>\n\t</dict>\n\t<key>invite</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1018</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>ison</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1019</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>join</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1020</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>kick</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1021</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>2</integer>\n\t</dict>\n\t<key>kill</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1022</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>list</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1023</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>locops</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1024</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>mode</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1026</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>monitor</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<real>1056</real>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>nachat</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1027</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>names</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1028</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>nick</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1029</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>notice</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1030</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>part</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1031</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>pass</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1032</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>-1</integer>\n\t</dict>\n\t<key>ping</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1033</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>pong</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1034</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>privmsg</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1035</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>quit</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1036</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>shun</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1045</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>2</integer>\n\t</dict>\n\t<key>tempshun</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1046</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>topic</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1039</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>1</integer>\n\t</dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1037</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>3</integer>\n\t</dict>\n\t<key>wallops</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1038</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>0</integer>\n\t</dict>\n\t<key>watch</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1053</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>who</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1040</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>whois</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1042</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>whowas</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1041</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>999</integer>\n\t</dict>\n\t<key>zline</key>\n\t<dict>\n\t\t<key>indexValue</key>\n\t\t<integer>1049</integer>\n\t\t<key>outgoingColonIndex</key>\n\t\t<integer>2</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/IRCNetworks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>AccessIRC</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.accessirc.net</string>\n\t\t<key>serverPort</key>\n\t\t<real>6697</real>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>AlphaChat</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.alphachat.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Azzurra</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.azzurra.chat</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>DALnet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.dal.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6667</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<false/>\n\t</dict>\n\t<key>EFnet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.efnet.info</string>\n\t\t<key>serverPort</key>\n\t\t<real>6667</real>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<false/>\n\t</dict>\n\t<key>EsperNet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.esper.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Ewnix</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.ewnix.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Fuel Rats</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.fuelrats.com</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>GameSurge</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.gamesurge.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6667</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<false/>\n\t</dict>\n\t<key>GeeksIRC</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.geeksirc.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>GeekShed</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.geekshed.net</string>\n\t\t<key>serverPort</key>\n\t\t<real>6697</real>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>German-Elite</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.german-elite.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Global Gamers</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.globalgamers.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>IRCHighWay</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.irchighway.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Interlinked</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.interlinked.me</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>IdleChat</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.idlechat.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Libera Chat</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.libera.chat</string>\n\t\t<key>serverPort</key>\n\t\t<real>6697</real>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>LizardIRC</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.lizardirc.org</string>\n\t\t<key>serverPort</key>\n\t\t<real>6697</real>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Mibbit</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.mibbit.com</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>MindForge</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.mindforge.org</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Mozor</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.mozor.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>NixtrixIRC</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.nixtrixirc.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>OFTC</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.oftc.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>PonyChat</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.ponychat.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>QuakeNet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.quakenet.org</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6667</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<false/>\n\t</dict>\n\t<key>Rizon</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.rizon.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Snoonet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.snoonet.org</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Snyde</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.snyde.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>StormBit</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.stormbit.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>TWiT</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.twit.tv</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Thinkstack</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.thinstack.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>TinyCrab</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.tinycrab.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>Undernet</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.undernet.org</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6667</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<false/>\n\t</dict>\n\t<key>freenode</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>chat.freenode.net</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n\t<key>hackint</key>\n\t<dict>\n\t\t<key>serverAddress</key>\n\t\t<string>irc.hackint.org</string>\n\t\t<key>serverPort</key>\n\t\t<integer>6697</integer>\n\t\t<key>prefersSecuredConnection</key>\n\t\t<true/>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/KeysExcludedFromContainer.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemesAny</key>\n\t<integer>0</integer>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemesDefault</key>\n\t<integer>0</integer>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemes</key>\n\t<integer>0</integer>\n\t<key>NSWindow Frame -&gt; Internal (v3) -&gt; </key>\n\t<integer>1</integer>\n\t<key>SUEnableAutomaticChecks</key>\n\t<integer>0</integer>\n\t<key>SUHasLaunchedBefore</key>\n\t<integer>0</integer>\n\t<key>SULastCheckTime</key>\n\t<integer>0</integer>\n\t<key>SUScheduledCheckInterval</key>\n\t<integer>0</integer>\n\t<key>SUSendProfileInfo</key>\n\t<integer>0</integer>\n\t<key>SUUpdateGroupIdentifier</key>\n\t<integer>0</integer>\n\t<key>TLOLicenseManagerAuthorizationCode</key>\n\t<integer>0</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/KeysExcludedFromExport.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TXRunCount</key>\n\t<integer>0</integer>\n\t<key>TXRunTime</key>\n\t<integer>0</integer>\n\t<key>TextField</key>\n\t<integer>1</integer>\n\t<key>Window -&gt; Main Window </key>\n\t<integer>1</integer>\n\t<key>THOPluginManager -&gt; Extras Installer Last Check for Update Payload</key>\n\t<integer>0</integer>\n\t<key>Text Input Prompt Suppression -&gt; </key>\n\t<integer>1</integer>\n\t<key>Textual 7 Upgrade -&gt; </key>\n\t<integer>1</integer>\n\t<key>TPCPreferences -&gt; Migration -&gt; </key>\n\t<integer>1</integer>\n\t<key>NSWindow Frame -&gt; Internal (v3) -&gt; </key>\n\t<integer>1</integer>\n\t<key>SUEnableAutomaticChecks</key>\n\t<integer>0</integer>\n\t<key>SUHasLaunchedBefore</key>\n\t<integer>0</integer>\n\t<key>SULastCheckTime</key>\n\t<integer>0</integer>\n\t<key>SUScheduledCheckInterval</key>\n\t<integer>0</integer>\n\t<key>SUSendProfileInfo</key>\n\t<integer>0</integer>\n\t<key>SUUpdateGroupIdentifier</key>\n\t<integer>0</integer>\n\t<key>Internal Theme Settings Key-value Store -&gt; </key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Font Name -&gt; Did Not Exist During Last Sync</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Name -&gt; Did Not Exist During Last Sync</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Channel Font Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Nickname Format Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Timestamp Format Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Download Folder Bookmark</key>\n\t<integer>0</integer>\n\t<key>LogTranscriptDestinationSecurityBookmark_5</key>\n\t<integer>0</integer>\n\t<key>TLOLicenseManagerAuthorizationCode</key>\n\t<integer>0</integer>\n\t<key>TVCLogControllerHistoricLogFileSavePath_v3</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Migrated Resources</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Installation Migrated</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; User Acknowledged</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; User Prefers Pruning Files</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; All Extensions Pruned</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Imported Keys</key>\n\t<integer>0</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/KeysExcludedFromMigrate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>NSWindowAutosaveFrameMovesToActiveDisplay</key>\n\t<integer>0</integer>\n\t<key>WebKitDeveloperExtras</key>\n\t<integer>0</integer>\n\t<key>__uniquePageGroupID-1.WebKit2ScrollAnimatorEnabled</key>\n\t<integer>0</integer>\n\t<key>__uniquePageGroupID-1.WebKit2ShouldRespectImageOrientation</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; Migrated Resources</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; Installation Migrated</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; User Acknowledged</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; User Prefers Pruning Files</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; All Extensions Pruned</key>\n\t<integer>0</integer>\n\t<key>TPCResourceManagerMigrate -&gt; Imported Keys</key>\n\t<integer>0</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/PreferenceKeyMasterList.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<integer>0</integer>\n\t<key>ApplicationCTCPVersionMasquerade</key>\n\t<integer>0</integer>\n\t<key>ApplyCommandToAllConnections -&gt; amsg</key>\n\t<integer>0</integer>\n\t<key>ApplyCommandToAllConnections -&gt; away</key>\n\t<integer>0</integer>\n\t<key>ApplyCommandToAllConnections -&gt; clearall</key>\n\t<integer>0</integer>\n\t<key>ApplyCommandToAllConnections -&gt; nick</key>\n\t<integer>0</integer>\n\t<key>AutojoinChannelOnInvite</key>\n\t<integer>0</integer>\n\t<key>AutojoinDelayBetweenChannelJoins</key>\n\t<integer>0</integer>\n\t<key>AutojoinDelayAfterIdentification</key>\n\t<integer>0</integer>\n\t<key>AutojoinMaximumChannelJoinCount</key>\n\t<integer>0</integer>\n\t<key>AutomaticallyAddScrollbackMarker</key>\n\t<integer>0</integer>\n\t<key>AutomaticallyDisconnectForSleepMode</key>\n\t<integer>0</integer>\n\t<key>AutomaticallyDetectHighlightSpam</key>\n\t<integer>0</integer>\n\t<key>AutomaticallyFilterUnicodeTextSpam</key>\n\t<integer>0</integer>\n\t<key>AutomaticallyReloadCustomThemesWhenTheyChange</key>\n\t<integer>0</integer>\n\t<key>Blowfish Encryption Extension -&gt; Enable Service</key>\n\t<integer>0</integer>\n\t<key>ChannelNavigationIsServerSpecific</key>\n\t<integer>0</integer>\n\t<key>ChannelOperatorDefaultLocalization -&gt; Kick Reason</key>\n\t<integer>0</integer>\n\t<key>ChannelViewArrangement</key>\n\t<integer>0</integer>\n\t<key>CommandReturnSendsMessageAsAction</key>\n\t<integer>0</integer>\n\t<key>ConfirmApplicationQuit</key>\n\t<integer>0</integer>\n\t<key>ControlEnterSendsMessage</key>\n\t<integer>0</integer>\n\t<key>ConversationTrackingIncludesUserModeSymbol</key>\n\t<integer>0</integer>\n\t<key>CopyTextSelectionOnMouseUp</key>\n\t<integer>0</integer>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemesAny</key>\n\t<integer>0</integer>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemesDefault</key>\n\t<integer>0</integer>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemes</key>\n\t<integer>0</integer>\n\t<key>DefaultBanCommandHostmaskFormat</key>\n\t<integer>0</integer>\n\t<key>DefaultIdentity -&gt; AwayNickname</key>\n\t<integer>0</integer>\n\t<key>DefaultIdentity -&gt; Nickname</key>\n\t<integer>0</integer>\n\t<key>DefaultIdentity -&gt; Realname</key>\n\t<integer>0</integer>\n\t<key>DefaultIdentity -&gt; Username</key>\n\t<integer>0</integer>\n\t<key>DestinationOfNonserverNotices</key>\n\t<integer>0</integer>\n\t<key>DisableMainWindowSegmentedController</key>\n\t<integer>0</integer>\n\t<key>DisableRemoteNicknameColorHashing</key>\n\t<integer>0</integer>\n\t<key>DisableSidebarTranslucency</key>\n\t<integer>0</integer>\n\t<key>DisplayDockBadges</key>\n\t<integer>0</integer>\n\t<key>DisplayEventInLogView -&gt; Date Changes</key>\n\t<integer>0</integer>\n\t<key>DisplayEventInLogView -&gt; Inline Media</key>\n\t<integer>0</integer>\n\t<key>DisplayEventInLogView -&gt; Join, Part, Quit</key>\n\t<integer>0</integer>\n\t<key>DisplayPublicMessageCountInDockBadge</key>\n\t<integer>0</integer>\n\t<key>DisplayServerMessageOfTheDayOnConnect</key>\n\t<integer>0</integer>\n\t<key>DisplayUserListNoModeSymbol</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Download Folder Bookmark</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer IP Address Detection Method</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer IP Address Detection Prefers 3rd-party Sources</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Port Range End</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Port Range Start</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Request Reply Action</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; File Transfer Requests Use Reverse DCC</key>\n\t<integer>0</integer>\n\t<key>File Transfers -&gt; Idle System Sleep Prevented During File Transfer</key>\n\t<integer>0</integer>\n\t<key>FocusSelectionOnMessageCommandExecution</key>\n\t<integer>0</integer>\n\t<key>Highlight List -&gt; Excluded Matches</key>\n\t<integer>0</integer>\n\t<key>Highlight List -&gt; Primary Matches</key>\n\t<integer>0</integer>\n\t<key>IRCopDefaultLocalizaiton -&gt; G:Line Reason</key>\n\t<integer>0</integer>\n\t<key>IRCopDefaultLocalizaiton -&gt; Kill Reason</key>\n\t<integer>0</integer>\n\t<key>IRCopDefaultLocalizaiton -&gt; Shun Reason</key>\n\t<integer>0</integer>\n\t<key>InlineMediaCheckEverything</key>\n\t<integer>0</integer>\n\t<key>InlineMediaLimitToBasics</key>\n\t<integer>0</integer>\n\t<key>InlineMediaLimitBasicsToFiles</key>\n\t<integer>0</integer>\n\t<key>InlineMediaLimitInsecureContent</key>\n\t<integer>0</integer>\n\t<key>InlineMediaLimitNaughtyContent</key>\n\t<integer>0</integer>\n\t<key>InlineMediaLimitUnsafeContent</key>\n\t<integer>0</integer>\n\t<key>InlineMediaMaximumFilesize</key>\n\t<integer>0</integer>\n\t<key>InlineMediaMaximumHeight</key>\n\t<integer>0</integer>\n\t<key>InlineMediaScalingWidth</key>\n\t<integer>0</integer>\n\t<key>Internal Theme Settings Key-value Store -&gt; </key>\n\t<integer>1</integer>\n\t<key>InvertSidebarColors</key>\n\t<integer>0</integer>\n\t<key>IRC -&gt; Enable echo-message Capability</key>\n\t<integer>0</integer>\n\t<key>Keyboard -&gt; Command+W Key Action</key>\n\t<integer>0</integer>\n\t<key>Keyboard -&gt; Tab Key Action</key>\n\t<integer>0</integer>\n\t<key>Keyboard -&gt; Tab Key Completion Suffix</key>\n\t<integer>0</integer>\n\t<key>LogHighlights</key>\n\t<integer>0</integer>\n\t<key>LogTranscript</key>\n\t<integer>0</integer>\n\t<key>LogTranscriptDestinationSecurityBookmark_5</key>\n\t<integer>0</integer>\n\t<key>MemberListSortFavorsServerStaff</key>\n\t<integer>0</integer>\n\t<key>MemberListUpdatesUserInfoPopoverOnScroll</key>\n\t<integer>0</integer>\n\t<key>Main Input Text Field -&gt; Font Size</key>\n\t<integer>0</integer>\n\t<key>Main Input Text Field -&gt; Focus When Changing Views</key>\n\t<integer>0</integer>\n\t<key>MainWindowTransparencyLevel</key>\n\t<integer>0</integer>\n\t<key>NicknameHighlightMatchingType</key>\n\t<integer>0</integer>\n\t<key>Nickname Color Style Overrides (v2)</key>\n\t<integer>0</integer>\n\t<key>New item</key>\n\t<integer>0</integer>\n\t<key>NotificationType -&gt; </key>\n\t<integer>1</integer>\n\t<key>Notification Sound Is Muted</key>\n\t<integer>0</integer>\n\t<key>NSWindow Frame -&gt; Internal (v3) -&gt; </key>\n\t<integer>1</integer>\n\t<key>PostNotificationsWhileInFocus</key>\n\t<integer>0</integer>\n\t<key>PreferModernCiphers</key>\n\t<integer>0</integer>\n\t<key>PreferModernSockets</key>\n\t<integer>0</integer>\n\t<key>Private Extension Store -&gt; Caffeine Extension -&gt; Prevent Sleep</key>\n\t<integer>0</integer>\n\t<key>Private Extension Store -&gt; Blowfish Encryption Extension -&gt; Encryption Mode of Operation -&gt; </key>\n\t<integer>1</integer>\n\t<key>Off-the-Record Messaging -&gt; Automatically Enable Service</key>\n\t<integer>0</integer>\n\t<key>Off-the-Record Messaging -&gt; Enable Encryption</key>\n\t<integer>0</integer>\n\t<key>Off-the-Record Messaging -&gt; Require Encryption</key>\n\t<integer>0</integer>\n\t<key>OnlySpeakNotificationsForSelection</key>\n\t<integer>0</integer>\n\t<key>OpenClickedLinksInBackgroundBrowser</key>\n\t<integer>0</integer>\n\t<key>Optimizations -&gt; Load History Lazily</key>\n\t<integer>0</integer>\n\t<key>ReceiveBetaUpdates</key>\n\t<integer>0</integer>\n\t<key>RejoinChannelOnLocalKick</key>\n\t<integer>0</integer>\n\t<key>ReloadScrollbackOnLaunch</key>\n\t<integer>0</integer>\n\t<key>RightToLeftTextFormatting</key>\n\t<integer>0</integer>\n\t<key>RemoveIRCTextFormatting</key>\n\t<integer>0</integer>\n\t<key>ReplyUnignoredExternalCTCPRequests</key>\n\t<integer>0</integer>\n\t<key>SaveInputHistoryPerSelection</key>\n\t<integer>0</integer>\n\t<key>ServerListDoubleClickConnectServer</key>\n\t<integer>0</integer>\n\t<key>ServerListDoubleClickDisconnectServer</key>\n\t<integer>0</integer>\n\t<key>ServerListDoubleClickJoinChannel</key>\n\t<integer>0</integer>\n\t<key>ServerListDoubleClickLeaveChannel</key>\n\t<integer>0</integer>\n\t<key>ServerListRetainsQueriesBetweenRestarts</key>\n\t<integer>0</integer>\n\t<key>Server List Unread Message Count Badge Colors -&gt; Highlight</key>\n\t<integer>0</integer>\n\t<key>Server Properties Window Sheet -&gt; Include Advanced Encodings</key>\n\t<integer>0</integer>\n\t<key>SetAwayOnScreenSleep</key>\n\t<integer>0</integer>\n\t<key>ScrollbackMaximumSavedLineCount</key>\n\t<integer>0</integer>\n\t<key>ScrollbackMaximumVisibleLineCount</key>\n\t<integer>0</integer>\n\t<key>SwipeMinimumLength</key>\n\t<integer>0</integer>\n\t<key>Smiley Converter Extension -&gt; Enable Service</key>\n\t<integer>0</integer>\n\t<key>Smiley Converter Extension -&gt; Enable Extra Emoticons</key>\n\t<integer>0</integer>\n\t<key>SUEnableAutomaticChecks</key>\n\t<integer>0</integer>\n\t<key>SUHasLaunchedBefore</key>\n\t<integer>0</integer>\n\t<key>SULastCheckTime</key>\n\t<integer>0</integer>\n\t<key>SUScheduledCheckInterval</key>\n\t<integer>0</integer>\n\t<key>SUSendProfileInfo</key>\n\t<integer>0</integer>\n\t<key>SUUpdateGroupIdentifier</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; CPU Model</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; GPU Model</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; Disk Information</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; Memory Information</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; OS Version</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; Screen Resolution</key>\n\t<integer>0</integer>\n\t<key>System Profiler Extension -&gt; Feature Disabled -&gt; System Uptime</key>\n\t<integer>0</integer>\n\t<key>Tab Completion -&gt; Completion Suffix Cut Forward Until Space</key>\n\t<integer>0</integer>\n\t<key>Tab Completion -&gt; Do Not Use Whitespace for Missing Completion Suffix</key>\n\t<integer>0</integer>\n\t<key>Text Input Prompt Suppression -&gt; </key>\n\t<integer>1</integer>\n\t<key>TextFieldAutomaticGrammarCheck</key>\n\t<integer>0</integer>\n\t<key>TextFieldAutomaticSpellCheck</key>\n\t<integer>0</integer>\n\t<key>TextFieldAutomaticSpellCorrection</key>\n\t<integer>0</integer>\n\t<key>TextFieldSmartCopyPaste</key>\n\t<integer>0</integer>\n\t<key>TextFieldSmartDashes</key>\n\t<integer>0</integer>\n\t<key>TextFieldDataDetectors</key>\n\t<integer>0</integer>\n\t<key>TextFieldSmartLinks</key>\n\t<integer>0</integer>\n\t<key>TextFieldSmartQuotes</key>\n\t<integer>0</integer>\n\t<key>TextFieldTextReplacement</key>\n\t<integer>0</integer>\n\t<key>TextualDeveloperEnvironment</key>\n\t<integer>0</integer>\n\t<key>Textual 7 Upgrade -&gt; Tv7 -&gt; Remind Me Later</key>\n\t<integer>0</integer>\n\t<key>Textual 7 Upgrade -&gt; Tv7 -&gt; Last Dialog Presentation (LMD)</key>\n\t<integer>0</integer>\n\t<key>Textual 7 Upgrade -&gt; Tv7 -&gt; Eligible License Key</key>\n\t<integer>0</integer>\n\t<key>Textual 7 Upgrade -&gt; Tv7 -&gt; Eligibility</key>\n\t<integer>0</integer>\n\t<key>Textual Chat Filter Extension -&gt; Filters</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Channel Font Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Font Name</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Font Name -&gt; Did Not Exist During Last Sync</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Font Size</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Name</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Name -&gt; Did Not Exist During Last Sync</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Nickname Format</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Nickname Format Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Timestamp Format</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; Timestamp Format Preference Enabled</key>\n\t<integer>0</integer>\n\t<key>Theme -&gt; User Style Sheet Rules</key>\n\t<integer>0</integer>\n\t<key>TrackNicknameHighlightsOfLocalUser</key>\n\t<integer>0</integer>\n\t<key>TrackUserAwayStatusMaximumChannelSize</key>\n\t<integer>0</integer>\n\t<key>TPCPreferencesDictionaryVersion</key>\n\t<integer>0</integer>\n\t<key>TPCPreferences -&gt; Migration -&gt; Appearance (7011)</key>\n\t<integer>0</integer>\n\t<key>TPCPreferences -&gt; Migration -&gt; Sparkle (601)</key>\n\t<integer>0</integer>\n\t<key>TPCPreferences -&gt; Migration -&gt; Nickname Color Style Overrides</key>\n\t<integer>0</integer>\n\t<key>TPCPreferences -&gt; Migration -&gt; World Controller Migrated (600)</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Migrated Resources</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Installation Migrated</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; User Acknowledged</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; User Prefers Pruning Files</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; All Extensions Pruned</key>\n\t<integer>0</integer>\n\t<key>Sandbox Migration -&gt; Imported Keys</key>\n\t<integer>0</integer>\n\t<key>TLOLicenseManagerAuthorizationCode</key>\n\t<integer>0</integer>\n\t<key>THOPluginManager -&gt; Extras Installer Last Check for Update Payload</key>\n\t<integer>0</integer>\n\t<key>TVCLogControllerHistoricLogFileSavePath_v3</key>\n\t<integer>0</integer>\n\t<key>TXRunCount</key>\n\t<integer>0</integer>\n\t<key>TXRunTime</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +a</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +h</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +o</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +q</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +v</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; +y</key>\n\t<integer>0</integer>\n\t<key>User List Mode Badge Colors -&gt; no mode</key>\n\t<integer>0</integer>\n\t<key>UserListDoubleClickAction</key>\n\t<integer>0</integer>\n\t<key>UsesWebKit2WhenAvailable</key>\n\t<integer>0</integer>\n\t<key>WebViewDoNotUsesCustomScrollers</key>\n\t<integer>0</integer>\n\t<key>WebViewPreviewLinks</key>\n\t<integer>0</integer>\n\t<key>WebViewProcessPoolSizeIsLimited</key>\n\t<integer>0</integer>\n\t<key>Wiki-style Link Parser Extension -&gt; Service Enabled</key>\n\t<integer>0</integer>\n\t<key>Wiki-style Link Parser Extension -&gt; Link Prefixes</key>\n\t<integer>0</integer>\n\t<key>Window -&gt; Main Window Is Fullscreen&apos;d</key>\n\t<integer>0</integer>\n\t<key>Window -&gt; Main Window -&gt; Member List is Visible</key>\n\t<integer>0</integer>\n\t<key>Window -&gt; Main Window -&gt; Server List is Visible</key>\n\t<integer>0</integer>\n\t<key>Window -&gt; Main Window -&gt; Server List Selection</key>\n\t<integer>0</integer>\n\t<key>Window -&gt; Main Window -&gt; Split Channel View Saved Frames</key>\n\t<integer>0</integer>\n\t<key>World Controller Client Configurations</key>\n\t<integer>0</integer>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/RegisteredUserDefaults.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.adiumX.AutoHyperlinks.permittedSchemesDefault</key>\n\t<array>\n\t\t<string>feed</string>\n\t\t<string>ftp</string>\n\t\t<string>gopher</string>\n\t\t<string>irc</string>\n\t\t<string>ircs</string>\n\t\t<string>itms</string>\n\t\t<string>sftp</string>\n\t\t<string>ssh</string>\n\t\t<string>telnet</string>\n\t\t<string>textual</string>\n\t\t<string>webcal</string>\n\t\t<string>x-man-page</string>\n\t</array>\n\t<key>NSWindowAutosaveFrameMovesToActiveDisplay</key>\n\t<false/>\n\t<key>WebKitDeveloperExtras</key>\n\t<true/>\n\t<key>__uniquePageGroupID-1.WebKit2ScrollAnimatorEnabled</key>\n\t<false/>\n\t<key>__uniquePageGroupID-1.WebKit2ShouldRespectImageOrientation</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/Preferences/RegisteredUserDefaultsInContainer.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<integer>0</integer>\n\t<key>ApplyCommandToAllConnections -&gt; amsg</key>\n\t<false/>\n\t<key>ApplyCommandToAllConnections -&gt; away</key>\n\t<false/>\n\t<key>ApplyCommandToAllConnections -&gt; clearall</key>\n\t<true/>\n\t<key>ApplyCommandToAllConnections -&gt; nick</key>\n\t<false/>\n\t<key>AutojoinChannelOnInvite</key>\n\t<false/>\n\t<key>AutojoinDelayBetweenChannelJoins</key>\n\t<real>2.2</real>\n\t<key>AutojoinDelayAfterIdentification</key>\n\t<real>0</real>\n\t<key>AutojoinMaximumChannelJoinCount</key>\n\t<integer>2</integer>\n\t<key>AutomaticallyAddScrollbackMarker</key>\n\t<true/>\n\t<key>AutomaticallyDisconnectForSleepMode</key>\n\t<true/>\n\t<key>AutomaticallyDetectHighlightSpam</key>\n\t<true/>\n\t<key>AutomaticallyFilterUnicodeTextSpam</key>\n\t<false/>\n\t<key>AutomaticallyReloadCustomThemesWhenTheyChange</key>\n\t<false/>\n\t<key>ChannelNavigationIsServerSpecific</key>\n\t<true/>\n\t<key>ChannelOperatorDefaultLocalization -&gt; Kick Reason</key>\n\t<string>Your behavior is not conducive to the desired environment.</string>\n\t<key>ChannelViewArrangement</key>\n\t<integer>0</integer>\n\t<key>CommandReturnSendsMessageAsAction</key>\n\t<true/>\n\t<key>ConfirmApplicationQuit</key>\n\t<true/>\n\t<key>ControlEnterSendsMessage</key>\n\t<false/>\n\t<key>ConversationTrackingIncludesUserModeSymbol</key>\n\t<false/>\n\t<key>CopyTextSelectionOnMouseUp</key>\n\t<false/>\n\t<key>DefaultBanCommandHostmaskFormat</key>\n\t<integer>1</integer>\n\t<key>DefaultIdentity -&gt; AwayNickname</key>\n\t<string></string>\n\t<key>DefaultIdentity -&gt; Nickname</key>\n\t<string>Guest</string>\n\t<key>DefaultIdentity -&gt; Realname</key>\n\t<string>Textual User</string>\n\t<key>DefaultIdentity -&gt; Username</key>\n\t<string>textual</string>\n\t<key>DestinationOfNonserverNotices</key>\n\t<integer>0</integer>\n\t<key>DisableMainWindowSegmentedController</key>\n\t<false/>\n\t<key>DisableRemoteNicknameColorHashing</key>\n\t<false/>\n\t<key>DisableSidebarTranslucency</key>\n\t<false/>\n\t<key>DisplayDockBadges</key>\n\t<true/>\n\t<key>DisplayEventInLogView -&gt; Date Changes</key>\n\t<true/>\n\t<key>DisplayEventInLogView -&gt; Inline Media</key>\n\t<false/>\n\t<key>DisplayEventInLogView -&gt; Join, Part, Quit</key>\n\t<true/>\n\t<key>DisplayPublicMessageCountInDockBadge</key>\n\t<false/>\n\t<key>DisplayServerMessageOfTheDayOnConnect</key>\n\t<true/>\n\t<key>DisplayUserListNoModeSymbol</key>\n\t<true/>\n\t<key>File Transfers -&gt; File Transfer IP Address Detection Method</key>\n\t<integer>1</integer>\n\t<key>File Transfers -&gt; File Transfer IP Address Detection Prefers 3rd-party Sources</key>\n\t<false/>\n\t<key>File Transfers -&gt; File Transfer Port Range End</key>\n\t<integer>1130</integer>\n\t<key>File Transfers -&gt; File Transfer Port Range Start</key>\n\t<integer>1115</integer>\n\t<key>File Transfers -&gt; File Transfer Request Reply Action</key>\n\t<integer>2</integer>\n\t<key>File Transfers -&gt; File Transfer Requests Use Reverse DCC</key>\n\t<false/>\n\t<key>File Transfers -&gt; Idle System Sleep Prevented During File Transfer</key>\n\t<true/>\n\t<key>FocusSelectionOnMessageCommandExecution</key>\n\t<true/>\n\t<key>IRCopDefaultLocalizaiton -&gt; G:Line Reason</key>\n\t<string>35d Your behavior is not conducive to the desired environment.</string>\n\t<key>IRCopDefaultLocalizaiton -&gt; Kill Reason</key>\n\t<string>Your behavior is not conducive to the desired environment.</string>\n\t<key>IRCopDefaultLocalizaiton -&gt; Shun Reason</key>\n\t<string>1d Shunned.</string>\n\t<key>InlineMediaCheckEverything</key>\n\t<false/>\n\t<key>InlineMediaLimitToBasics</key>\n\t<false/>\n\t<key>InlineMediaLimitBasicsToFiles</key>\n\t<false/>\n\t<key>InlineMediaLimitInsecureContent</key>\n\t<false/>\n\t<key>InlineMediaLimitNaughtyContent</key>\n\t<true/>\n\t<key>InlineMediaLimitUnsafeContent</key>\n\t<true/>\n\t<key>InlineMediaMaximumFilesize</key>\n\t<integer>2</integer>\n\t<key>InlineMediaMaximumHeight</key>\n\t<integer>0</integer>\n\t<key>InlineMediaScalingWidth</key>\n\t<integer>300</integer>\n\t<key>IRC -&gt; Enable echo-message Capability</key>\n\t<false/>\n\t<key>Keyboard -&gt; Command+W Key Action</key>\n\t<integer>0</integer>\n\t<key>Keyboard -&gt; Tab Key Action</key>\n\t<integer>0</integer>\n\t<key>LogHighlights</key>\n\t<true/>\n\t<key>LogTranscript</key>\n\t<false/>\n\t<key>MemberListSortFavorsServerStaff</key>\n\t<false/>\n\t<key>MemberListUpdatesUserInfoPopoverOnScroll</key>\n\t<true/>\n\t<key>Main Input Text Field -&gt; Font Size</key>\n\t<integer>1</integer>\n\t<key>Main Input Text Field -&gt; Focus When Changing Views</key>\n\t<true/>\n\t<key>MainWindowTransparencyLevel</key>\n\t<real>1</real>\n\t<key>NicknameHighlightMatchingType</key>\n\t<integer>1</integer>\n\t<key>NotificationType -&gt; Address Book Match -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Failed File Transfer (Receiving) -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Failed File Transfer (Receiving) -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Failed File Transfer (Sending) -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Failed File Transfer (Sending) -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; File Transfer Request -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; File Transfer Request -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; File Transfer Request -&gt; Sound</key>\n\t<string>Blow</string>\n\t<key>NotificationType -&gt; Highlight -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Highlight -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Highlight -&gt; Sound</key>\n\t<string>Glass</string>\n\t<key>NotificationType -&gt; Private Message (New) -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Private Message (New) -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Private Message (New) -&gt; Sound</key>\n\t<string>Submarine</string>\n\t<key>NotificationType -&gt; Private Message -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Private Message -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Private Message -&gt; Sound</key>\n\t<string>Submarine</string>\n\t<key>NotificationType -&gt; Public Message -&gt; Speak Channel Name</key>\n\t<true/>\n\t<key>NotificationType -&gt; Public Message -&gt; Speak Nickname</key>\n\t<true/>\n\t<key>NotificationType -&gt; Successful File Transfer (Receiving) -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Successful File Transfer (Receiving) -&gt; Enabled</key>\n\t<true/>\n\t<key>NotificationType -&gt; Successful File Transfer (Sending) -&gt; Bounce Dock Icon</key>\n\t<true/>\n\t<key>NotificationType -&gt; Successful File Transfer (Sending) -&gt; Enabled</key>\n\t<true/>\n\t<key>PostNotificationsWhileInFocus</key>\n\t<true/>\n\t<key>PreferModernCiphers</key>\n\t<false/>\n\t<key>PreferModernSockets</key>\n\t<true/>\n\t<key>Off-the-Record Messaging -&gt; Automatically Enable Service</key>\n\t<false/>\n\t<key>Off-the-Record Messaging -&gt; Enable Encryption</key>\n\t<true/>\n\t<key>Off-the-Record Messaging -&gt; Require Encryption</key>\n\t<false/>\n\t<key>OnlySpeakNotificationsForSelection</key>\n\t<true/>\n\t<key>OpenClickedLinksInBackgroundBrowser</key>\n\t<false/>\n\t<key>Optimizations -&gt; Load History Lazily</key>\n\t<true/>\n\t<key>ReceiveBetaUpdates</key>\n\t<false/>\n\t<key>RejoinChannelOnLocalKick</key>\n\t<false/>\n\t<key>ReloadScrollbackOnLaunch</key>\n\t<true/>\n\t<key>RightToLeftTextFormatting</key>\n\t<false/>\n\t<key>RemoveIRCTextFormatting</key>\n\t<false/>\n\t<key>ReplyUnignoredExternalCTCPRequests</key>\n\t<true/>\n\t<key>SaveInputHistoryPerSelection</key>\n\t<false/>\n\t<key>ServerListDoubleClickConnectServer</key>\n\t<false/>\n\t<key>ServerListDoubleClickDisconnectServer</key>\n\t<false/>\n\t<key>ServerListDoubleClickJoinChannel</key>\n\t<false/>\n\t<key>ServerListDoubleClickLeaveChannel</key>\n\t<false/>\n\t<key>ServerListRetainsQueriesBetweenRestarts</key>\n\t<false/>\n\t<key>SetAwayOnScreenSleep</key>\n\t<false/>\n\t<key>ScrollbackMaximumSavedLineCount</key>\n\t<real>15000</real>\n\t<key>ScrollbackMaximumVisibleLineCount</key>\n\t<integer>0</integer>\n\t<key>SwipeMinimumLength</key>\n\t<integer>30</integer>\n\t<key>Tab Completion -&gt; Completion Suffix Cut Forward Until Space</key>\n\t<false/>\n\t<key>Tab Completion -&gt; Do Not Use Whitespace for Missing Completion Suffix</key>\n\t<false/>\n\t<key>TextFieldAutomaticGrammarCheck</key>\n\t<true/>\n\t<key>TextFieldAutomaticSpellCheck</key>\n\t<true/>\n\t<key>TextFieldAutomaticSpellCorrection</key>\n\t<false/>\n\t<key>TextFieldSmartCopyPaste</key>\n\t<true/>\n\t<key>TextFieldSmartDashes</key>\n\t<false/>\n\t<key>TextFieldDataDetectors</key>\n\t<false/>\n\t<key>TextFieldSmartLinks</key>\n\t<false/>\n\t<key>TextFieldSmartQuotes</key>\n\t<false/>\n\t<key>TextFieldTextReplacement</key>\n\t<true/>\n\t<key>TextualDeveloperEnvironment</key>\n\t<false/>\n\t<key>Theme -&gt; Font Name</key>\n\t<string>Lucida Grande</string>\n\t<key>Theme -&gt; Font Size</key>\n\t<real>12</real>\n\t<key>Theme -&gt; Name</key>\n\t<string>resource:Simplified</string>\n\t<key>Theme -&gt; Nickname Format</key>\n\t<string>&lt;%@%n&gt;</string>\n\t<key>Theme -&gt; Timestamp Format</key>\n\t<string>[%H:%M:%S]</string>\n\t<key>TrackNicknameHighlightsOfLocalUser</key>\n\t<true/>\n\t<key>TrackUserAwayStatusMaximumChannelSize</key>\n\t<integer>300</integer>\n\t<key>User List Mode Badge Colors -&gt; +a</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmg5HtHD8Ag/ypsT4Bhg==</data>\n\t<key>User List Mode Badge Colors -&gt; +h</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmgwIrhz2DI9v5PoNQjZc9AYY=</data>\n\t<key>User List Mode Badge Colors -&gt; +o</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmg0a2sz6DqMZLPoNt5xs/AYY=</data>\n\t<key>User List Mode Badge Colors -&gt; +q</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmgyPbOT8AAAGG</data>\n\t<key>User List Mode Badge Colors -&gt; +v</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmg6jGSz6Dj8L1PoNt5xs/AYY=</data>\n\t<key>User List Mode Badge Colors -&gt; +y</key>\n\t<data>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU0NvbG9yAISECE5TT2JqZWN0AIWEAWMBhARmZmZmg8HKIT+DH4WrPoOLbGc+AYY=</data>\n\t<key>UserListDoubleClickAction</key>\n\t<integer>200</integer>\n\t<key>UsesWebKit2WhenAvailable</key>\n\t<true/>\n\t<key>WebViewDoNotUsesCustomScrollers</key>\n\t<false/>\n\t<key>WebViewPreviewLinks</key>\n\t<false/>\n\t<key>WebViewProcessPoolSizeIsLimited</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/StaticStore.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TPCThemeController Remapped Themes</key>\n\t<dict>\n\t\t<key>resource:Simplified Light</key>\n\t\t<string>resource:Simplified</string>\n\t\t<key>resource:Simplified Dark</key>\n\t\t<string>resource:Simplified</string>\n\t\t<key>resource:Tomorrow Night (Eighties)</key>\n\t\t<string>resource:Tomorrow</string>\n\t</dict>\n\t<key>IRCClient List of NickServ Successfully Identified Tokens</key>\n\t<array>\n\t\t<string>now recognized</string>\n\t\t<string>automatically identified</string>\n\t\t<string>already identified</string>\n\t\t<string>successfully identified</string>\n\t\t<string>you are already logged in</string>\n\t\t<string>you are now identified</string>\n\t\t<string>password accepted</string>\n\t</array>\n\t<key>IRCClient List of NickServ Needs Identification Tokens</key>\n\t<array>\n\t\t<string>nickname is owned</string>\n\t\t<string>nickname is registered</string>\n\t\t<string>owned by someone else</string>\n\t\t<string>nick belongs to another user</string>\n\t\t<string>if you do not change your nickname</string>\n\t\t<string>authentication required</string>\n\t\t<string>authenticate yourself</string>\n\t\t<string>identify yourself</string>\n\t\t<string>type /msg NickServ IDENTIFY password</string>\n\t</array>\n\t<key>IRCClient List of Nicknames that Encryption Forbids</key>\n\t<dict>\n\t\t<key>UnderNet</key>\n\t\t<array>\n\t\t\t<string>c</string>\n\t\t\t<string>w</string>\n\t\t\t<string>x</string>\n\t\t\t<string>x@channels.undernet.org</string>\n\t\t</array>\n\t\t<key>-default-</key>\n\t\t<array>\n\t\t\t<string>authserv</string>\n\t\t\t<string>botserv</string>\n\t\t\t<string>chanserv</string>\n\t\t\t<string>hostserv</string>\n\t\t\t<string>memoserv</string>\n\t\t\t<string>nickserv</string>\n\t\t\t<string>operserv</string>\n\t\t\t<string>rootserv</string>\n\t\t\t<string>statserv</string>\n\t\t\t<string>userserv</string>\n\t\t</array>\n\t</dict>\n\t<key>THOPluginManager List of Forbidden Commands</key>\n\t<array>\n\t\t<string>connect</string>\n\t\t<string>die</string>\n\t\t<string>error</string>\n\t\t<string>info</string>\n\t\t<string>kill</string>\n\t\t<string>links</string>\n\t\t<string>lusers</string>\n\t\t<string>motd</string>\n\t\t<string>names</string>\n\t\t<string>oper</string>\n\t\t<string>pass</string>\n\t\t<string>ping</string>\n\t\t<string>pong</string>\n\t\t<string>rehash</string>\n\t\t<string>restart</string>\n\t\t<string>server</string>\n\t\t<string>service</string>\n\t\t<string>servlist</string>\n\t\t<string>squery</string>\n\t\t<string>squit</string>\n\t\t<string>stats</string>\n\t\t<string>time</string>\n\t\t<string>trace</string>\n\t\t<string>userhost</string>\n\t\t<string>users</string>\n\t\t<string>version</string>\n\t\t<string>whowas</string>\n\t</array>\n\t<key>THOPluginManager List of Forbidden Extensions</key>\n\t<array>\n\t\t<string>com.codeux.app-extensions.textual-Caffeine</string>\n\t</array>\n\t<key>THOPluginManager List of Reserved Commands</key>\n\t<array>\n\t\t<string>apps</string>\n\t\t<string>banhammer</string>\n\t\t<string>delkey</string>\n\t\t<string>ffuu</string>\n\t\t<string>flip</string>\n\t\t<string>hermes</string>\n\t\t<string>key</string>\n\t\t<string>keyx</string>\n\t\t<string>music</string>\n\t\t<string>np</string>\n\t\t<string>o_p</string>\n\t\t<string>page</string>\n\t\t<string>qt</string>\n\t\t<string>radium</string>\n\t\t<string>setkey</string>\n\t\t<string>setkeymode</string>\n\t\t<string>shell</string>\n\t\t<string>slap</string>\n\t\t<string>spotify</string>\n\t\t<string>vlc</string>\n\t</array>\n\t<key>THOPluginManager Extras Installer Latest Extension Versions</key>\n\t<dict>\n\t\t<key>com.codeux.app-extensions.textual-BlowfishEncryption</key>\n\t\t<string>1.0.18</string>\n\t\t<key>com.codeux.app-extensions.textual-WikiStyleLinkParser</key>\n\t\t<string>1.0.9</string>\n\t</dict>\n\t<key>Spelling Ignores</key>\n\t<array>\n\t\t<string>deop</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Property Lists/TemplateLineTypes.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>action</key>\n\t<string>newMessagePostedWithSender</string>\n\t<key>ctcp</key>\n\t<string>newMessagePostedWithSender</string>\n\t<key>dcc-file-transfer</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>debug</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>invite</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>join</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>kick</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>kill</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>mode</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>nick</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>notice</key>\n\t<string>newMessagePostedWithSender</string>\n\t<key>off-the-record-encryption-status</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>part</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>privmsg</key>\n\t<string>newMessagePostedWithSender</string>\n\t<key>quit</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>topic</key>\n\t<string>newMessagePostedWithoutSender</string>\n\t<key>website</key>\n\t<string>newMessagePostedWithoutSender</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Bundled Scripts/Installing Custom Scripts.txt",
    "content": "\nCustom scripts can be installed in the folder:\n\n\"~/Library/Application Scripts/com.codeux.apps.textual/\"\n\nThis folder might not exist. If it does not, create it. Textual does\nnot have write permission to this location so it cannot create it on\nits own. Scripts installed within this folder benefit from the ability\nto be ran outside of the OS X sandbox giving them unrestricted access\nto the system as a whole.\n\nOnly OS X Mountain Lion or later can read scripts from this folder.\nThis is an unfortunate design flaw of the OS X sandbox that Textual\ncannot circumvent. \n\nFor more information, read the knowledge base:\n\nhttps://help.codeux.com/textual/Writing-Scripts.kb\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Create-Installers",
    "content": "\nset -e\n\nexport BUILD_PATH=\"/private/tmp/Textual-${RANDOM}\"\n\nexport BUILD_PATH_SCRIPTS_STANDALONE=\"${BUILD_PATH}/Library/Application Scripts/com.codeux.apps.textual\"\nexport BUILD_PATH_EXTENSIONS_STANDALONE=\"${BUILD_PATH}/Library/Group Containers/8482Q6EPL6.com.codeux.apps.textual/Library/Application Support/Textual/Extensions\"\n\nexport CURRENT_DIRECTORY=$(cd `dirname $0` && pwd)\n\nexport SOURCE_FILES_SCRIPTS=\"${CURRENT_DIRECTORY}/Installation Files/Scripts\"\nexport SOURCE_FILES_EXTENSIONS=\"${CURRENT_DIRECTORY}/Installation Files/Extensions\"\n\nexport PACKAGES_DESTINATION=\"${CURRENT_DIRECTORY}/Packages\"\n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Scripts-Package\" \"AudioVideo\" \"hermes,music,np,qt,radium,spotify,vlc\"\n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Scripts-Package\" \"Fun\" \"banhammer,ffuu,o_o,slap\"\n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Scripts-Package\" \"Utilities\" \"apps,flip,page,reverse,shell\"\n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Extension-Package\" \"BlowfishEncryption\"\n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Extension-Package\" \"WikiStyleLinkParser\" \n\necho \"**************************\"\n\n\"${CURRENT_DIRECTORY}/Installer Helpers/Build-Final-Package\"\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installer Helpers/Build-Extension-Package",
    "content": "\necho \"Extension - ${1} - Start\";\n\ncodesign -f -s \"Developer ID Application: Codeux Software, LLC (8482Q6EPL6)\" \"${SOURCE_FILES_EXTENSIONS}/${1}.bundle\"\n\n# *****************************************************\n# STANDALONE \n# *****************************************************\n\nmkdir -p \"${BUILD_PATH_EXTENSIONS_STANDALONE}\"\n\ncp -Rp \"${SOURCE_FILES_EXTENSIONS}/${1}.bundle\" \"${BUILD_PATH_EXTENSIONS_STANDALONE}\"\n\npkgbuild \\\n--root \"${BUILD_PATH}\" \\\n--ownership recommended \\\n--sign \"Developer ID Installer: Codeux Software, LLC (8482Q6EPL6)\" \\\n--quiet \\\n--identifier \"com.codeux.app-extensions.textual-extension-installer-${1}\" \\\n--version \"1.0\" \\\n\"${PACKAGES_DESTINATION}/STANDALONE/Extension-${1}.pkg\"\n\nrm -fr \"${BUILD_PATH}\"\n\n# *****************************************************\n\necho \"Extension - ${1} - End\";\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installer Helpers/Build-Final-Package",
    "content": "\necho \"Build Finale Package - Start\"\n\n# *****************************************************\n# STANDALONE \n# *****************************************************\n\nproductbuild \\\n--distribution distribution.plist \\\n--resources \"./Installer Resources\" \\\n--package-path \"${PACKAGES_DESTINATION}/STANDALONE/\" \\\n--sign \"Developer ID Installer: Codeux Software, LLC (8482Q6EPL6)\" \\\n--identifier \"com.codeux.app-extensions.textual-extras-installer\" \\\n--version \"1.0\" \\\n--quiet \\\n\"${PACKAGES_DESTINATION}/Textual-Extras.pkg\"\n\nrm -f \"${PACKAGES_DESTINATION}/STANDALONE/*.pkg\"\n\necho \"Build Finale Package - End\"\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installer Helpers/Build-Scripts-Package",
    "content": "\necho \"${1} - Start\";\n\n# *****************************************************\n# STANDALONE \n# *****************************************************\n\nmkdir -p \"${BUILD_PATH_SCRIPTS_STANDALONE}\"\n\nfor i in $(echo $2 | sed \"s/,/ /g\")\ndo\n\techo \"Copying ${i}\"\n \n\tcp \"${SOURCE_FILES_SCRIPTS}/${3}${i}.scpt\" \"${BUILD_PATH_SCRIPTS_STANDALONE}\"\ndone\n\npkgbuild \\\n--root \"${BUILD_PATH}\" \\\n--ownership recommended \\\n--sign \"Developer ID Installer: Codeux Software, LLC (8482Q6EPL6)\" \\\n--quiet \\\n--identifier \"com.codeux.app-extensions.textual-scripts-installer-${1}\" \\\n--version \"1.0\" \\\n\"${PACKAGES_DESTINATION}/STANDALONE/Scripts-${1}.pkg\"\n\nrm -fr \"${BUILD_PATH}\"\n\n# *****************************************************\n\necho \"${1} - End\";\n"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/Installer Resources/en.lproj/Welcome.rtf",
    "content": "{\\rtf1\\ansi\\ansicpg1252\\cocoartf2571\n\\cocoatextscaling0\\cocoaplatform0{\\fonttbl\\f0\\fnil\\fcharset0 HelveticaNeue;\\f1\\fnil\\fcharset0 HelveticaNeue-Bold;}\n{\\colortbl;\\red255\\green255\\blue255;\\red252\\green41\\blue19;}\n{\\*\\expandedcolortbl;;\\cssrgb\\c100000\\c25745\\c7993;}\n\\margl1440\\margr1440\\vieww13040\\viewh11540\\viewkind0\n\\pard\\tx720\\tx1440\\tx2160\\tx2880\\tx3600\\tx4320\\tx5040\\tx5760\\tx6480\\tx7200\\tx7920\\tx8640\\pardirnatural\\partightenfactor0\n\n\\f0\\fs26 \\cf0 Click \\'93Continue\\'94 to view a list of addons that can be installed. \\\n\\\nWhen the next screen appears, expand the various categories,\\\nthen click each item to view its description. \\\n\\\nEnable the checkbox next to the items that you are interested in \\\nthen click \\'93Install\\'94 to complete installation.\\\n\\\n\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\'97\\\n\\\n\n\\f1\\b \\cf2 The macOS Installer may bug out at times and install files \\\nat the incorrect location.\n\\f0\\b0 \\cf0 \\\n\\\n\n\\f1\\b If you perform an installation and find what you selected \\\nwas not installed, then try following these steps:\n\\f0\\b0 \\\n\\\n1. When presented with the button \\'93Change Install Location\\'85\\'94\\\n    after the selection screen, click it.\\\n2. In the window that appears, click \\'93Install for me only.\\'94\\\n3. Continue installation.}"
  },
  {
    "path": "Sources/App/Resources/Scripting/Script Files/Textual Extras Installer/distribution.plist",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<installer-gui-script minSpecVersion=\"2\">\n    <title>DISTRIBUTION_TITLE</title>\n   \n    <background file=\"installerBackground.png\" scaling=\"proportional\" alignment=\"bottomleft\"/>\n    \n    <welcome file=\"Welcome.rtf\"/>\n    \n    <options customize=\"always\" require-scripts=\"false\" hostArchitectures=\"arm64,x86_64\"/>\n   \n    <volume-check>\n        <allowed-os-versions>\n            <os-version min=\"11.0\"/>\n        </allowed-os-versions>\n    </volume-check>\n\n    <choices-outline>\n        <line choice=\"installer_choice_1\">\n            <line choice=\"installer_choice_1_1\"/>\n            <line choice=\"installer_choice_1_2\"/>\n            <line choice=\"installer_choice_1_3\"/>\n        </line>\n        <line choice=\"installer_choice_2\">\n            <line choice=\"installer_choice_2_1\"/>\n            <line choice=\"installer_choice_2_2\"/>\n        </line>\n    </choices-outline>\n   \n    <choice id=\"installer_choice_1_1\" start_selected=\"false\" title=\"INSTALLER_CHOICE_1_1_TITLE\" description=\"INSTALLER_CHOICE_1_1_DESCRIPTION\">\n        <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-AudioVideo\"/>\n    </choice>\n    <choice id=\"installer_choice_1_2\" start_selected=\"false\" title=\"INSTALLER_CHOICE_1_2_TITLE\" description=\"INSTALLER_CHOICE_1_2_DESCRIPTION\">\n        <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-Fun\"/>\n    </choice>\n    <choice id=\"installer_choice_1_3\" start_selected=\"false\" title=\"INSTALLER_CHOICE_1_3_TITLE\" description=\"INSTALLER_CHOICE_1_3_DESCRIPTION\">\n        <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-Utilities\"/>\n    </choice>\n    <choice id=\"installer_choice_1\" title=\"INSTALLER_CHOICE_1_TITLE\" description=\"INSTALLER_CHOICE_1_DESCRIPTION\"/>\n    \n    <choice id=\"installer_choice_2_1\" start_selected=\"false\" title=\"INSTALLER_CHOICE_2_1_TITLE\" description=\"INSTALLER_CHOICE_2_1_DESCRIPTION\">\n        <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-BlowfishEncryption\"/>\n    </choice>\n    <choice id=\"installer_choice_2_2\" start_selected=\"false\" title=\"INSTALLER_CHOICE_2_2_TITLE\" description=\"INSTALLER_CHOICE_2_2_DESCRIPTION\">\n        <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-WikiStyleLinkParser\"/>\n    </choice>\n    <choice id=\"installer_choice_2\" title=\"INSTALLER_CHOICE_2_TITLE\" description=\"INSTALLER_CHOICE_2_DESCRIPTION\"/>\n  \n    <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-AudioVideo\" version=\"1.4\">#Scripts-AudioVideo.pkg</pkg-ref>\n    <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-Fun\" version=\"1.3\">#Scripts-Fun.pkg</pkg-ref>\n    <pkg-ref id=\"com.codeux.app-extensions.textual-scripts-installer-Utilities\" version=\"1.3\">#Scripts-Utilities.pkg</pkg-ref>\n    <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-BlowfishEncryption\" version=\"1.0.18\">#Extension-BlowfishEncryption.pkg</pkg-ref>\n    <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-WikiStyleLinkParser\" version=\"1.0.9\">#Extension-WikiStyleLinkParser.pkg</pkg-ref>\n\n    <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-BlowfishEncryption\">\n        <must-close>\n\t        <app id=\"com.codeux.apps.textual\"/>\n\t        <app id=\"com.codeux.apps.textual-mas\"/>\n        </must-close>\n    </pkg-ref>\n    <pkg-ref id=\"com.codeux.app-extensions.textual-extension-installer-WikiStyleLinkParser\">\n        <must-close>\n\t        <app id=\"com.codeux.apps.textual\"/>\n\t        <app id=\"com.codeux.apps.textual-mas\"/>\n        </must-close>\n    </pkg-ref>\n\n    <domains enable_localSystem=\"false\" enable_currentUserHome=\"true\" enable_anywhere=\"false\"/>\n</installer-gui-script>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconLight.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/copyright.txt",
    "content": "Copyright © 2010, 2011, 2012 Alex Sørlie."
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #fff;\n\theight: 100%;\n \tz-index: 100;\n\tfont-size: 9px;\n\toverflow: hidden;\n\tbackground-color: #000;\n\tfont-family: \"Lucida Grande\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 2.0em); /* height minus topic */\n}\n\ndiv.line {\n \tmargin-top: -1px;\n\tclear: both;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #181818;\n\tborder: 1px solid #333333;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Time */\n\nbody[dir=\"ltr\"] .time {\n\tcolor: #ffffff;\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tcolor: #ffffff;\n\twhite-space: nowrap;\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* Encryption Lock */\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* Links */\n\na {\n\tcolor: #0080FF;\n\tborder-color: #0080FF;\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #40A0FF;\n\tborder-color: #40A0FF;\n}\n\n/* Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tcolor: #fff;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tposition: fixed;\n\tbackground: #000;\n\tpadding: 2px 0.5em 3px;\n\tborder-bottom: 1px solid #1f1f1f;\n\t-webkit-box-shadow: 0 1px 5px #777;\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n\t<https://github.com/hbang/Simplified-Light-Modifications> */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n#topicBar a {\n\tcolor: #0080FF;\n\tborder-color: #0080FF;\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\n#topicBar a:hover {\n\tcolor: #40A0FF;\n\tborder-color: #40A0FF;\n}\n\n/* Remember Line */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #444;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #5a5a5a;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #606060;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #d8d8d8;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #f00;\n  \tz-index: 191;\n\tbackground: #400;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #811;\n\tborder-bottom: 1px solid #811;\n}\n\ndiv.line[data-line-type=\"notice\"] .sender {\n\tcolor: #f00;\n\tfont-weight: 700;\n}\n\n/* Selected User Messages */\n\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #aaa;\n}\n\ndiv.line.selectedUser[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .time {\n\tcolor: #fff;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n\n  \tz-index: 190;\n  \tposition: relative;\n\tborder-top: 1px solid #CC7A03 !important;\n\tborder-bottom: 1px solid #CC7A03 !important;\n  \tbackground-color: rgba(244, 151, 75, 0.25) !important;\n}\n\n/* PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"false\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n  \tz-index: 191;\n  \tposition: relative;\n\tfont-weight: normal;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #06c793;\n\tborder-bottom: 1px solid #06c793;\n  \tbackground-color: rgba(18, 93, 53, 0.6) !important;\n}\n\ndiv[data-line-type=\"privmsg\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .message {\n\tcolor: #fff;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\tfont-weight: 700;\n\twhite-space: pre-wrap;\n}\n\n/* ACTION */\n\ndiv.line[data-line-type=\"action\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv[data-line-type=\"action\"] .message {\n\tcolor: #00ff9c;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .sender,\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .message {\n\tcolor: #00ff9c;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-left: 0.4em; */\n}\n\n/* DEBUG/INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #777;\n  \tz-index: 190;\n\tbackground: #222;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #444;\n\tborder-bottom: 1px solid #444;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] .message {\n\tcolor: #ff0000;\n\tfont-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tborder: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tborder-bottom: none;\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tborder-top: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"website\"],\ndiv.line[data-line-type=\"topic\"] {\n \tpadding: 3px 5px 3px 5px;\n\tcolor: #666;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message {\n  \tcolor: #b589ff;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message:before {\n\tcontent: \"✕\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message {\n  \tcolor: #ff3d3d;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message {\n  \tcolor: #ffae01;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message {\n  \tcolor: #ffee7a;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0090ff;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message {\n  \tcolor: #0090ff;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"mode\"] .message:before {\n\tcontent: \"❖\";\n  \tcolor: #b4a355;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"mode\"] .message {\n  \tcolor: #9c9c9c;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"topic\"] .message:before {\n\tcontent: \"✦\";\n  \tcolor: #00a2ff;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"topic\"] .message {\n  \tcolor: #00ffa2;\n  \tmargin-right: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message {\n  \tcolor: #b589ff;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message:before {\n\tcontent: \"✕\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message {\n  \tcolor: #ff3d3d;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message {\n  \tcolor: #ffae01;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message {\n  \tcolor: #ffee7a;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0090ff;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message {\n  \tcolor: #0090ff;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"mode\"] .message:before {\n\tcontent: \"❖\";\n  \tcolor: #b4a355;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"mode\"] .message {\n  \tcolor: #9c9c9c;\n  \tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"topic\"] .message:before {\n\tcontent: \"✦\";\n  \tcolor: #00a2ff;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"topic\"] .message {\n  \tcolor: #00ffa2;\n  \tmargin-left: 0.4em;\n}\n\n/* Nickname Colors */\n\n.inlineSender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender[data-member-type=\"myself\"] {\n\tcolor: #B8DFFF;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/inlineMedia.css",
    "content": "\n/* Images */\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 12px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/scripts.js",
    "content": "/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.95);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Astria/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n\t<key>Underlying Window Color</key>\n\t<string>#000000</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/LICENSE.txt",
    "content": "Copyright (c) 2013-2015, April King, Alex Sørlie Glomsaas, Tobias Pollmann\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice, this\n  list of conditions and the following disclaimer in the documentation and/or\n  other materials provided with the distribution.\n\n* Neither the name of the {organization} nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{activeStyleAbsolutePath}}/Resources/lockIconResource.svg\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/design.css",
    "content": "\n/* Inline media */\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n  margin: 0;\n  padding: 0;\n  font-size: 100%;\n  word-break: break-word;\n}\n\nbody {\n  color: #f2f2f2;\n  z-index: 100;\n  font-size: 12px;\n  background-color: #1d1d1d;\n  font-family: \"Helvetica Neue\";\n  font-weight: 200;\n  overflow-y: auto;\n}\n\np {\n  overflow: visible !important;\n}\n\nbody .line {\n  clear: both;\n}\n\n#body {\n  left: 0;\n  right: 0;\n  bottom: 0;\n  position: absolute;\n  width: 100%;\n  z-index: 100;\n  max-height: 99.99%;\n  opacity: 0; /* Set by JavaScript */\n  -webkit-transition: opacity 0.8s linear;\n}\n\n#body {\n  max-height: 100%;\n}\n\nbody[dir=rtl] .senderContainer {\n  display: inline-block;\n}\n\n/* Hide some internal stuff. */\n#timestampWidth {\n  display: none;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n  width: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n  height: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n  background: #393939;\n  box-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n  background-color: #7c7c7c;\n  border: 4px solid transparent;\n  border-left: 5px solid transparent;\n  border-radius: 20px;\n  background-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n  background-color: #b0b0b0;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n  position: fixed;\n  margin: auto;\n  top: 0; left: 0; right: 0; bottom: 0;\n  width: 210px;\n  height: 35px;\n  line-height: 35px;\n  text-align: center;\n  font-size: 18px;\n  background: #363636;\n  padding: 5px;\n  padding-left: 10px;\n  opacity: 1; /* Set by JavaScript */\n  -webkit-transition: opacity 0.8s linear;\n}\n\n#loadingScreen progress {\n  margin-top: 5px;\n}\n\n/* Time */\nbody[dir=ltr] .time {\n  font-size: .91em !important;\n  white-space: nowrap;\n  float: right;\n  color: #999;\n  -webkit-user-select: none;\n  /*  font-weight: bold; */\n  margin-right: 10px;\n  padding-left: 25px;\n  line-height: 22px;\n  font-style: normal;\n  text-align: right;\n}\n\n/* Encryption Lock */\n.encryptionLock {\n}\n\n.encryptionLock img {\n  z-index: 100;\n  position:absolute;\n  top:0;\n  left: 5px;\n  bottom:0;\n  margin:auto;\n  height: 12px;\n  width: auto;\n}\n\n/* Links */\n\na {\n  color: #ccc;\n  border-color: #ccc;\n  text-decoration: none;\n  border-bottom: dotted 1px;\n\n}\n\na:hover {\n  color: #64a5ff;\n  border-color: #64a5ff;\n}\n\n/* Topic Bar */\n#topicBar {\n  top: 0;\n  left: 0;\n  right: 0;\n  padding-bottom: 5px;\n  opacity: 0; /* Set by JavaScript */\n  z-index: 400;\n  color: #dddddd;\n  overflow: hidden;\n  position: fixed;\n  padding: 7px 0.5em 7px;\n  box-shadow: 0 1px 5px #777;\n  border-bottom: 1px solid #404040;\n  -webkit-transition: opacity 0.8s linear;\n  text-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n  background: rgba(60, 60, 60, 0.91);\n}\n\n#topicBar a,\n#topicBar .channel {\n  color: #64a5ff;\n  border-color: #64a5ff;\n  text-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n}\n\n/* Hidden scrollback history bar */\n#scrolling_history {\n  z-index: 400;\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  height: auto;\n  box-shadow: 0 1px 5px #777;\n  border-top: 1px solid #404040;\n  text-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n  background: rgba(31, 51, 81, 0.95);\n  display: none;\n  overflow: hidden;\n}\n\n#scrolling_history .senderContainer {\n  background: rgba(31, 51, 81, .95);\n}\n\n/* Remember Line */\n#mark {\n  position: relative;\n  z-index: 295;\n  margin-top: -1px;\n  border-bottom: 1px solid;\n  border-color: #444;\n  -webkit-transition: 0.2s linear;\n}\n\nbody[dir=ltr] div[data-line-type=action] .sender:before {\n  margin-right: 0.6em;\n  font-weight: bold;\n  font-size: 80% !important;\n  content: \"●\";\n}\n\n/* Message buffer loading animation */\n.message_buffer_loading_indicator {\n  text-align: center;\n  height: 42px;\n}\n\n.message_buffer_loading_indicator span {\n  font-family: Optima !important;\n  font-size: 35px;\n  font-weight: 600;\n  letter-spacing: 5px;\n  line-height: 43px;\n  color: #5a5a5a;\n  -webkit-animation: ellipsis-period 1.5s infinite;\n  animation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n  -webkit-animation-delay: 0.0s;\n  animation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n  -webkit-animation-delay: 0.1s;\n  animation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n  -webkit-animation-delay: 0.2s;\n  animation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n  0% { opacity: 0.2; }\n  20% { opacity: 1.0; }\n  100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n.date_indicator ,\n.session_indicator {\n  display: flex;\n  display: -webkit-flex;\n  padding: .5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n  background: #444;\n  border: 0;\n  height: 1px;\n  margin-top: 0.6em;\n  flex: 1;\n  -webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n  font-style: oblique;\n  margin: 0 1em;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n  display: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\nbody div.line[data-line-type=ctcp],\nbody div.line[data-line-type=notice],\nbody div.line[data-line-type=wallops] {\n  z-index: 191;\n  position: relative;\n  border-bottom: none;\n  border-top: none;\n  border-left: none;\n  background-color: #1d2734;\n}\n\nbody div[data-line-type=ctcp] .senderContainer,\nbody div[data-line-type=notice] .senderContainer {\n  color: #f00;\n  font-weight: 700;\n  min-height:23px;\n  width: 134px;\n  padding-right:7px;\n  text-align:right;\n  display:inline-block;\n  overflow: auto;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  text-overflow: ellipsis;\n  background-color: #161616;\n}\n\nbody div[data-line-type=notice] .message {\n  color: #f2f2f2;\n}\n\n/* PRIVMSG */\nbody div.line[data-line-type=privmsg][data-highlight=false] {\n  padding: 0;\n  position: relative;\n  min-height: 23px;\n}\n\nbody div[data-line-type=privmsg] .senderContainer {\n  /*  font-weight: 700; */\n  min-height:23px;\n  width: 134px;\n  border-right: 1px solid rgb(64, 64, 64);\n  padding-right:7px;\n  background-color: #161616;\n  text-align:right;\n  display:inline-block;\n  overflow: hidden;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  text-overflow: ellipsis;\n}\n\nbody .senderContainer .swrapper {\n  font-size: 0px !important;\n  opacity: 0;\n}\n\nbody div[data-line-type=\"privmsg\"] .message {\n  color: #f2f2f2;\n}\n\nbody div[data-line-type=\"privmsg\"][data-encrypted=\"true\"] {\n  background: repeating-linear-gradient(-45deg, rgba(79, 79, 79, 0.1), rgba(79, 79, 79, 0.1) 20px, rgba(68, 89, 63, 0.3) 20px, rgba(68, 89, 63, 0.3) 40px) !important;\n}\n\nbody div[data-line-type=\"privmsg\"][data-encrypted=\"failed\"] {\n  background: repeating-linear-gradient(-45deg, rgba(45, 6, 6, 0.2), rgba(45, 6, 6, 0.2) 20px, rgba(104, 15, 15, 0.2) 20px, rgba(104, 15, 15, 0.2) 40px) !important;\n}\n\nbody div[data-line-type=\"privmsg\"][data-highlight=true][data-encrypted=\"true\"] {\n  background: repeating-linear-gradient(-45deg, #30473a, #30473a 20px, rgba(68, 89, 63, 0.3) 20px, rgba(68, 89, 63, 0.3) 40px) !important;\n}\n\nbody div[data-line-type=privmsg][data-line-type=myself] .message {\n  color: #f2f2f2;\n}\n\nbody div[data-line-type=privmsg] span.effect[data-foreground-color=1]:not([data-background-color]) {\n  color: #f2f2f2; /* make black text with no bg white for readability */\n}\n\n/* ACTION */\nbody div[data-line-type=action] .senderContainer {\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  width: 134px;\n  /*  font-weight: 700;*/\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  background-color: #1d1d1d;\n  height:22px;\n  padding-right: 7px;\n  text-align:right;\n  display:inline-block;\n  overflow: hidden;\n}\n\nbody div.line[data-line-type=action] .message {\n  padding-top: 1px;\n}\n\nbody div.line[data-line-type=action][data-highlight=true] .message {\n  color: #f2f2f2 !important;\n}\n\n/* DEBUG/INVITE */\nbody div.line[data-line-type=invite],\nbody div.line[data-line-type=debug],\nbody div.line[data-line-type=dcc-file-transfer],\nbody div.line[data-line-type=off-the-record-encryption-status] {\n  color: #f2f2f2;\n  z-index: 190;\n  background: #2f2f2f;\n  position: relative;\n  padding: 2px 0 2px 0;\n  border-top: 1px solid #393939;\n  border-bottom: 1px solid #393939;\n}\n\nbody div.line[data-line-type=ctcp] .message,\nbody div.line[data-line-type=invite] .message,\nbody div.line[data-line-type=debug] .message,\nbody div.line[data-line-type=dcc-file-transfer] .message,\nbody div.line[data-line-type=off-the-record-encryption-status] .message {\n  text-indent: 0;\n  padding-left: 145px !important;\n}\n\n/* off-the-record-encryption-status Message Event */\nbody div.line[data-line-type=off-the-record-encryption-status]  .message {\n  color: #ff0000;\n  font-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\nbody div.line[data-command=\"372\"],\nbody div.line[data-command=\"721\"] {\n  border: none;\n  padding-top: 3px;\n  padding-bottom: 3px;\n}\n\nbody div.line[data-command=\"375\"],\nbody div.line[data-command=\"720\"] { /* Start. */\n  border-bottom: none;\n  padding-top: 2px;\n  padding-bottom: 3px;\n}\n\nbody div.line[data-command=\"376\"],\nbody div.line[data-command=\"722\"] { /* End. */\n  border-top: none;\n  padding-top: 3px;\n  padding-bottom: 3px;\n}\n\nbody div.line[data-command=\"372\"] .message,\nbody div.line[data-command=\"375\"] .message,\nbody div.line[data-command=\"376\"] .message\nbody div.line[data-command=\"720\"] .message,\nbody div.line[data-command=\"721\"] .message,\nbody div.line[data-command=\"722\"] .message {\n  font-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\nbody span.message {\n  position: relative;\n  padding-left: 150px;\n  /* padding-right: 25px; */\n  display: table-cell;\n  min-height: 22px;\n  line-height: 22px;\n  overflow: visible !important;\n}\n\nbody div.event span.time {\n  color: #999;\n  line-height: 19px;\n  display: table-cell;\n}\n\nbody div.event span.message {\n  min-height: 19px;\n  line-height: 19px;\n  text-indent: -20px;\n  padding-left: 0;\n}\n\nbody div.line[data-line-type=join],\nbody div.line[data-line-type=part],\nbody div.line[data-line-type=quit],\nbody div.line[data-line-type=mode],\nbody div.line[data-line-type=nick],\nbody div.line[data-line-type=topic],\nbody div.line[data-line-type=kill],\nbody div.line[data-line-type=kick],\nbody div.line[data-line-type=website] {\n  font-size: 85%;\n  min-height: 19px;\n  padding-left: 145px;\n  color: #a5b6ce;\n  background: #1d1d1d;\n}\n\nbody div.line[data-line-type=topic] span.message {\n  text-indent: 0;\n}\n\nbody div.line[data-line-type=nick] {\n  color: #529567;\n}\nbody div.line[data-line-type=kill],\nbody div.line[data-line-type=kick] {\n  color: #ec5151;\n}\n\nbody[dir=ltr] div[data-line-type=join] .message:before {\n  content: \"→\";\n  color: #0c0;\n  margin-left:3px;\n  margin-right: 5px;\n}\n\nbody[dir=ltr] div[data-line-type=kick] .message:before,\nbody[dir=ltr] div[data-line-type=part] .message:before,\nbody[dir=ltr] div[data-line-type=quit] .message:before {\n  content: \"←\";\n  color: #e00;\n  margin-left:3px;\n  margin-right: 5px;\n}\n\nbody[dir=ltr] div[data-line-type=nick] .message:before {\n  content: \"\\2022\";\n  color: #37be34;\n  font-weight: 700;\n  margin-left: 8px;\n  margin-right: 5px;\n}\n\nbody[dir=ltr] div[data-line-type=mode] .message:before {\n  content: \"\\2022\";\n  color: #2cb6f6;\n  font-weight: 700;\n  margin-left: 8px;\n  margin-right: 5px;\n}\n\nbody[dir=rtl] div[data-line-type=join] .message:before {\n  content: \"→\";\n  color: #0c0;\n  margin-left:3px;\n  margin-right: 5px;\n}\n\nbody[dir=rtl] div[data-line-type=kick] .message:before,\nbody[dir=rtl] div[data-line-type=part] .message:before,\nbody[dir=rtl] div[data-line-type=quit] .message:before {\n  content: \"←\";\n  color: #e00;\n  margin-left:3px;\n  margin-right: 5px;\n}\n\n/* Nickname Colors */\nbody .sender[data-member-type=myself] {\n  color: #9A60FF;\n}\n\nbody .sender {\n  margin-right: -.25em;\n\n}\n\nbody .f {  /* fade out */\n  -webkit-transition: color .75s;\n  color: rgb(22, 22, 22) !important;\n}\n\n/* SELECTED USER MESSAGES */\n\n.senderContainer {\n  cursor: pointer;\n  overflow: hidden;\n  white-space: nowrap;\n}\n\nbody div.line[data-line-type=privmsg]:not(.selectedUser),\nbody div.line[data-line-type=action]:not(.selectedUser) {\n  transition-property: background-color;\n  transition-duration: 0.5s, 0.5s, 0.5s;\n}\n\nbody div.line[data-line-type=privmsg] .time:not(.selectedUser),\nbody div.line[data-line-type=action] .time:not(.selectedUser) {\n  transition: color 0.5s;\n}\n\nbody div.line.selectedUser[data-highlight=false] .time {\n  transition: color 0.5s ease-in;\n  color: #aaa;\n}\n\nbody div.line.selectedUser[data-highlight=false] {\n  transition-property: background-color;\n  transition-duration: 0.5s, 0.5s, 0.5s;\n  z-index: 190;\n  position: relative;\n  background-color: #2f3e53;\n}\n\nbody div.line[data-line-type=privmsg][data-highlight=true],\nbody div.line[data-line-type=action][data-highlight=true] {\n  z-index: 191;\n  position: relative;\n  font-weight: normal;\n  background-color: #30473a;\n}\n\n/* Shamelessly steal the background colors from Tomorrow Night */\n.effect[data-foreground-color='0'] {\n  color: #EAEAEA !important;\n}\n\n.effect[data-foreground-color='1'] {\n  color: #515151 !important;\n}\n\n.effect[data-foreground-color='2'] {\n  color: #6699CC !important;\n}\n\n.effect[data-foreground-color='3'] {\n  color: #99CC99 !important;\n}\n\n.effect[data-foreground-color='4'] {\n  color: #F2777A !important;\n}\n\n.effect[data-foreground-color='5'] {\n  color: #FF9DA4 !important;\n}\n\n.effect[data-foreground-color='6'] {\n  color: #CC99CC !important;\n}\n\n.effect[data-foreground-color='7'] {\n  color: #F99157 !important;\n}\n\n.effect[data-foreground-color='8'] {\n  color: #FFCC66 !important;\n}\n\n.effect[data-foreground-color='9'] {\n  color: #B9CA4A !important;\n}\n\n.effect[data-foreground-color='10'] {\n  color: #66CCCC !important;\n}\n\n.effect[data-foreground-color='11'] {\n  color: #99FFFF !important;\n}\n\n.effect[data-foreground-color='12'] {\n  color: #7AA6DA !important;\n}\n\n.effect[data-foreground-color='13'] {\n  color: #C397D8 !important;\n}\n\n.effect[data-foreground-color='14'] {\n  color: #999999 !important;\n}\n\n.effect[data-foreground-color='15'] {\n  color: #CCCCCC !important;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/inlineMedia.css",
    "content": "\n/* Images */\n\nbody a img {\n  border: 0;\n}\n\nbody video,\nbody img {\n  display: block;\n}\n\n.inlineImage,\n.inlineVideo {\n  position: relative;\n  display: table;\n  overflow: auto;\n  width: auto;\n  height: auto;\n}\n\n.inlineImage > a,\n.inlineVideo > a {\n  display: inline-block;\n  border: none;\n}\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n  display: inline-block;\n  float: left;\n  margin: 15px 15px 12px 10px;\n  min-width: 100px;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n  background: #000000;\n  cursor: pointer;\n  border-radius: 50%;\n  position: absolute;\n  box-sizing: border-box;\n  font-size: 20px !important;\n  font-family: \"Helvetica Neue\" !important;\n  font-weight: 100 !important;\n  text-align: center;\n  line-height: 17px;\n  color: #f2f2f2;\n  border: 2px solid #f2f2f2;\n  top: 5px;\n  right: 5px;\n  width: 25px;\n  height: 25px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/scripts.js",
    "content": "/* jslint browser: true */\n/* global app, Textual */\n\n/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\n/* Theme-wide preferences, as per milky's request */\nvar Equinox = {\n  fadeNicks: true,            // fade out nicknames when they appear multiple times in a row\n  fadeNicksFreq: 10,          // how frequently to display a nick if they have fadeNickCounts lines in a row\n  squashModes: true,          // if a duplicate mode gets posted to the channel, squash it\n  squashTopics: true          // if a duplicate topic gets posted to the channel, squash it\n};\n\n/* Set the default statuses for everything tracked in the roomState */\nvar mappedSelectedUsers = [];\nvar rs                  = { // room state\n  channelJoined: false,\n  enableHistoryView: false,  // this doesn't get enabled until the history has finished loading\n  mode: {\n    mode: undefined\n  },\n  nick: {\n    count: 1,\n    delete: false,\n    id: undefined,\n    nick: undefined\n  },\n  nickname: null,\n  topic: {\n    delete: false,\n    topic: undefined\n  }\n};\n\n/* State tracking for client information */\nEquinox.refreshLocalNicknameCache = function()\n{\n  'use strict';\n  app.localUserNickname(\n    function(returnValue) {\n      rs.nickname = returnValue;   \n    }\n  );\n};\n\nEquinox.refreshChannelJoinedCache = function()\n{\n  'use strict';\n  app.channelIsJoined(\n    function(returnValue) {\n      rs.channelJoined = returnValue;    \n    }  \n  );\n};\n\n/* Nickname colors */\nvar NickColorGenerator = (function () {\n  'use strict';\n\n  function NickColorGenerator(message) {\n    var i, inlineNicks, nick;\n\n    // Start alternative nick colouring procedure\n    var selectNick = message.querySelector('.sender');\n\n    inlineNicks = message.querySelectorAll('.inlineSender');\n\n    this.generateColorFromNickname(selectNick.dataset.nickname,\n      function(nickcolor) {\n        selectNick.style.color = nickcolor;\n\n        if (message.dataset.lineType === 'action') {\n          message.querySelector('.message').style.color = nickcolor;\n        }\n      }\n    );\n\n    var self = this;\n    for (i = 0; i < inlineNicks.length; i++) {\n      nick = inlineNicks[i].textContent;\n      if (inlineNicks[i].dataset.mode.length > 0) {\n        nick = nick.replace(inlineNicks[i].dataset.mode, '');\n      }\n      var inlineNick = inlineNicks[i];\n      (function(inlineNickname) {\n        self.generateColorFromNickname(nick,\n          function(nickcolor) {\n            inlineNickname.style.color = nickcolor;\n          }\n        );\n      })(inlineNick);\n    }\n  }\n\n  NickColorGenerator.prototype.generateColorFromNickname = function (nick, callbackFunction) {\n    // First, sanitize the nicknames\n    nick = nick.toLowerCase();      // make them lowercase (so that April and april produce the same color)\n    nick = nick.replace(/[`_-]+$/, ''); // typically `, _, and - are used on the end of a nick\n    nick = nick.replace(/|.*$/, '');  // remove |<anything> from the end\n\n    // Generate the hashes\n    app.nicknameColorStyleHash(nick, 'HSL-dark',\n      function(hhash) {\n        var shash = hhash >>> 1;\n        var lhash = hhash >>> 2;\n\n        var h       = hhash % 360;\n        var s       = shash % 50 + 45;   // 50 - 95\n        var l       = lhash % 36 + 45;   // 45 - 81\n\n        // give the pinks a wee bit more lightness\n        if (h >= 280 && h < 335) {\n          l = lhash % 36 + 50; // 50 - 86\n        }\n\n        // Give the blues a smaller (but lighter) range\n        if (h >= 210 && h < 280) {\n          l = lhash % 25 + 65; // 65 - 90\n        }\n\n        // Give the reds a bit less saturation\n        if (h <= 25 || h >= 335) {\n          s = shash % 33 + 45; // 45 - 78\n        }\n\n        // Give the yellows and greens a bit less saturation as well\n        if (h >= 50 && h <= 150) {\n          s = shash % 50 + 40; // 40 - 90\n        }\n\n        var nickcolor = 'hsl(' + String(h) + ',' + String(s) + '%,' + String(l) + '%)';\n\n        callbackFunction(nickcolor);\n      }\n    );\n  };\n\n  return NickColorGenerator;\n})();\n\nfunction isMessageInViewport(elem) {\n  'use strict';\n\n  if (!elem.getBoundingClientRect) {\n    return true;\n  }\n\n  // Have to use Math.floor() because sometimes the getBoundingClientRect().bottom is a fraction of a pixel (!!!)\n  return (Math.floor(elem.getBoundingClientRect().bottom) - 1) <= Math.floor(document.documentElement.clientHeight);\n}\n\nfunction toggleHistoryIfScrolled() {\n  'use strict';\n\n  var line, lines;\n  var topic = document.getElementById('topicBar');\n\n  lines = document.getElementById('body').getElementsByClassName('line');\n  if (lines.length < 2) {\n    return;\n  }\n  line = lines[lines.length - 1];\n\n  if (isMessageInViewport(line) === false) {\n    // scrollback\n    rs.history.style.display = 'inline';\n    if (topic) { topic.style.visibility = 'hidden'; }\n  } else {\n    // at the bottom\n    rs.history.style.display = 'none';\n    if (topic) { topic.style.visibility = 'visible'; }\n  }\n}\n\n/* When you join a channel, delete all the old disconnected messages */\nTextual.handleEvent = function (event) {\n  'use strict';\n  var i, messages;\n  var messagesRemovedCount = 0;\n\n  switch(event) {\n    case \"channelJoined\": {\n      rs.channelJoined = true;\n      messages = document.querySelectorAll('div[data-command=\"-100\"]');\n      for (i = 0; i < messages.length; i++) {\n        if (messages[i].getElementsByClassName('message')[0].textContent.search('Disconnect') !== -1) {\n          messages[i].parentNode.removeChild(messages[i]);\n          messagesRemovedCount += 1;\n        }\n      }\n\n      if (messagesRemovedCount > 0) {\n        MessageBuffer.noteMessagesRemovedFromBuffer(messagesRemovedCount);\n      }\n      \n      break;\n    }\n    case \"channelParted\": {\n      rs.channelJoined = false;  \n      break;\n    }\n    case \"nicknameChanged\": {\n      Equinox.refreshLocalNicknameCache();\n      break;\n    }\n    /* It is important to have serverConnected as a state \n      because the nickname may change then, outside of the\n      NICK command (handled by \"nicknameChanged\").\n      For example, user can connect to ZNC which has\n      a different nickname than set locally. */\n    case \"serverConnected\": {\n      Equinox.refreshLocalNicknameCache();\n      break;\n    }\n    default: {\n      break;\n    }\n  } // switch()\n};\n\nTextual.messageAddedToView = function (line, fromBuffer) {\n  'use strict';\n  var message = document.getElementById('line-' + line);\n  var messageRemoved;\n  var clone, elem, getEmbeddedImages, i, mode, messageText, sender, topic;\n\n  // reset the message count and previous nick, when you rejoin a channel\n  if (message.dataset.lineType !== 'privmsg') {\n    rs.nick.count = 1;\n    rs.nick.nick = undefined;\n  }\n\n  // if it's a private message, colorize the nick and then track the state and fade away the nicks if needed\n  if (message.dataset.lineType === 'privmsg' || message.dataset.lineType === 'action') {\n    sender = message.getElementsByClassName('sender')[0];\n    if (sender.dataset.overrideColor !== 'true') {\n      new NickColorGenerator(message); // colorized the nick\n    }\n\n    // Delete (ie, make foreground and background color identical) the previous line's nick, if it was set to be deleted\n    if (rs.nick.delete === true) {\n      elem = document.getElementById(rs.nick.id).getElementsByClassName('sender')[0];\n      elem.className += ' f';\n    }\n\n    // Track the nicks that submit messages, so that we can space out everything\n    if ((rs.nick.nick === sender.textContent) && (rs.nick.count < Equinox.fadeNicksFreq)\n      && (message.dataset.lineType !== 'action') && (Equinox.fadeNicks === true)) {\n      rs.nick.delete = true;\n      rs.nick.count += 1;\n    } else {\n      rs.nick.nick = sender.textContent;\n      rs.nick.count  = 1;\n      rs.nick.delete = false;\n    }\n\n    // Track the previous message's id\n    rs.nick.id = message.getAttribute('id');\n\n    // Copy the message into the hidden history\n    clone = message.cloneNode(true);\n    clone.removeAttribute('id');\n\n    if (fromBuffer === false) {\n      rs.history.appendChild(clone);\n    }\n\n    // Colorize it as well\n    if (sender.dataset.overrideColor !== 'true') {\n      new NickColorGenerator(clone); // colorized the nick\n    }\n\n    // Remove old messages, if the history is longer than three messages\n    if (rs.history.childElementCount > 2) {\n      rs.history.removeChild(rs.history.childNodes[0]);\n\n      // Hide the first nick in the hidden history, if it's the same as the second\n      if ((rs.nick.count > 1) && (message.dataset.lineType !== 'action')) {\n        rs.history.getElementsByClassName('sender')[0].style.visibility = 'hidden';\n      }\n    }\n  }\n\n  /* Let's kill topics that appear where they had already been set before\n     This happens when you join a room (like a reconnect) that you had been in and seen the topic before */\n  if (Equinox.squashTopics === true && message.dataset.lineType === 'topic') {\n    topic = message.getElementsByClassName('message')[0].textContent.replace('Topic is ', '').replace(/\\s+/, '');\n\n    if (message.dataset.command === '332') { // an actual topic change\n      // hide the topic if it's the same topic again\n      if (topic === rs.topic.topic) {\n        message.parentNode.removeChild(message);\n        messageRemoved = true;\n        rs.topic.delete = true;\n      }\n\n      rs.topic.topic = topic;\n    }\n\n    if ((message.dataset.command === '333') && (rs.topic.delete === true)) {\n      message.parentNode.removeChild(message);\n      messageRemoved = true;\n      rs.topic.delete = false;\n    }\n  }\n\n  // much like we suppress duplicate topics, we want to suppress duplicate modes\n  if (Equinox.squashModes === true && message.dataset.lineType === 'mode') {\n    mode = message.getElementsByClassName('message')[0].textContent.replace(/\\s+/, '');\n\n    if (mode === rs.mode.mode) {\n      message.parentNode.removeChild(message);\n      messageRemoved = true;\n    } else {\n      rs.mode.mode = mode;\n    }\n  }\n\n  // hide messages about yourself joining\n  if ((message.dataset.lineType === 'join') || (message.dataset.lineType === 'part')) {\n    if (rs.nickname == message.getElementsByClassName('message')[0].getElementsByTagName('b')[0].textContent) {\n      message.parentNode.removeChild(message);\n      messageRemoved = true;\n    }\n  }\n\n  /* clear out all the old disconnect messages, if you're currently connected to the channel\n     note that normally Textual.handleEvent will catch this, but if you reload a theme, they will reappear */\n  if ((message.dataset.lineType === 'debug') && (message.dataset.command === '-100')) {\n    if (rs.channelJoined && message.getElementsByClassName('message')[0].textContent.search('Disconnect') !== -1) {\n      message.parentNode.removeChild(message);\n      messagesRemoved = true;\n    }\n  } \n\n  /* Textual's buffer keeps a record of number of messages that\n  appear in the buffer. The buffer counts anything with a line\n  number as a message. If we remove messages, we should let it\n  know so that it can correct any irregularities in its math. */\n  if (messageRemoved) {\n    MessageBuffer.noteMessageRemovedFromBuffer();\n    \n    return;\n  }\n\n  getEmbeddedImages = message.querySelectorAll('img');\n  if (getEmbeddedImages) {\n    for (i = 0; i < getEmbeddedImages.length; i++) {\n      getEmbeddedImages[i].onload = function (e) {\n        setTimeout(function () {\n          if (e.target.offsetHeight > (window.innerHeight - 150)) {\n            e.target.style.height = (window.innerHeight - 150);\n          }\n        }, 1000);\n      };\n    }\n  }\n\n  ConversationTracking.updateNicknameWithNewMessage(message);\n};\n\n/* This is called when a .sender is clicked */\nTextual.nicknameSingleClicked = function (e) {\n  ConversationTracking.nicknameSingleClickEventCallback(e);\n};\n\nTextual.viewBodyDidLoad = function () {\n  'use strict';\n  Textual.fadeOutLoadingScreen(1.00, 0.95);\n};\n\nTextual.viewFinishedLoadingHistory = function () {\n  'use strict';\n\n  // enable the history view, but only a bit after this gets called\n  setTimeout(function() {\n    rs.enableHistoryView = true;\n  }, 850);\n}\n\nTextual.viewInitiated = function () {\n  'use strict';\n\n  /* When the view is loaded, create a hidden history div which we display if there is scrollback */\n  var body = document.getElementById('body'), div = document.createElement('div');\n  div.id = 'scrolling_history';\n  document.getElementsByTagName('body')[0].appendChild(div);\n  rs.history = div;\n\n  /* setup the scrolling event to display the hidden history if the bottom element isn't in the viewport\n     also hide the topic bar when scrolling.  Note that we have to set a timer here so that the history\n     div doesn't appear in the viewport on normal inserts, which cause scroll effects */\n  window.addEventListener('scroll', function () {\n    // check to see if a bit of time has passed since we loaded the history\n    if (!rs.enableHistoryView) {\n      return;\n    }\n\n    rs.scrollTimer = setTimeout(toggleHistoryIfScrolled, 100);\n  });\n  \n  /* Cache client information so we do not have to wait\n     for callback functions to complete. */\n  Equinox.refreshChannelJoinedCache();\n  Equinox.refreshLocalNicknameCache();\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Equinox/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Force Invert Sidebars</key>\n\t<true/>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Nickname Format</key>\n\t<string>%@%n</string>\n\t<key>Post Textual.handleEvent() Notifications</key>\n\t<true/>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n\t<key>Underlying Window Color</key>\n\t<string>#232323</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/Resources/Documentation/changelog.txt",
    "content": "#Version Information, \"Sapientia\".\n\n2012-07-02 - Version 1.3\n\t* Topic bar:\n\t\t- Font size increased (13pt -> 15pt)\n\t\t- Gradient background added.\n\t* Override nickname style to %@%n\n\t* Support for inverted sidebars in 2.1.1\n\n2012-06-08 - Version 1.2\n\t* Updated for Textual 2.1, fixing bugs caused by the new version. \n\t* Brightened background colour, slightly.\n\n2011-04-10 - Version 1.1\n\t* Changed highlight colours.\n\n2011-04-09 - Version 1.0\n\t* First release."
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconLight.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/copyright.txt",
    "content": "\"Sapientia\" is a style by Noah \"Brisk\" Darville-Jennings (http://www.noahdj.ca/).\n\nThis style is based on the stripped down version of \nthe \"Simplified\" theme developed by \"Cowboy\" Ben Alman\n(http://benalman.com/). Copyright © 2010, 2011, 2012."
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure - Sapientia 1.3 */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #E8E7E3;\n\theight: 100%;\n \tz-index: 100;\n\tfont-size: 15pt;\n\toverflow: hidden;\n\tbackground-color: #242323;\n\tfont-family: \"HelveticaNeue\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 2.2em); /* height minus topic */\n}\n\ndiv.line {\n \tmargin-top: -1px;\n\tclear: both;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #181818;\n\tborder: 1px solid #333333;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Time */\n\nbody[dir=\"ltr\"] .time {\n\tcolor: #343434;\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tcolor: #343434;\n\twhite-space: nowrap;\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* Encryption Lock */\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* Links */\n\na {\n\tcolor: #FF7D40;\n\tborder-color: #FF7D40;\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #FF4500;\n\tborder-color: #FF4500;\n}\n\n/* Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tcolor: #a39888;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tline-height: 145%;\n\tposition: fixed;\n\tbackground: -webkit-linear-gradient(top, #494949 0%, #282828 100%);\n\tpadding: 2px 0.5em 3px;\n\tborder-bottom: 1px solid #544E45;\n\t-webkit-box-shadow: 0 1px 5px #000;\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n\t<https://github.com/hbang/Simplified-Light-Modifications> */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n#topicBar a {\n\tcolor: #FF7D40;\n\tborder-color: #FF7D40;\n}\n\n#topicBar a:hover {\n\tcolor: #FF4500;\n\tborder-color: #FF4500;\n}\n\n/* Remember Line */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #444;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #797979;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #444;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #919191;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #a00;\n  \tz-index: 191;\n\tbackground: #300;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #400;\n\tborder-bottom: 1px solid #400;\n}\n\ndiv.line[data-line-type=\"notice\"] .sender {\n\tcolor: #700;\n\tfont-weight: 700;\n}\n\n/* Selected User Messages */\n\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #aaa;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n\n  \tz-index: 190;\n  \tposition: relative;\n\tborder-top: 1px solid #5E5E5E !important;\n\tborder-bottom: 1px solid #5E5E5E !important;\n  \tbackground-color: rgba(105, 105, 105, 0.3) !important;\n}\n\n/* PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"false\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n  \tz-index: 191;\n  \tposition: relative;\n\tfont-weight: normal;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #994C00;\n\tborder-bottom: 1px solid #994C00;\n  \tbackground-color: #2d1e10 !important;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .message {\n\tcolor: #a9a9a9;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\tfont-weight: 700;\n\twhite-space: pre-wrap;\n}\n\n/* ACTION */\n\ndiv.line[data-line-type=\"action\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"action\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .sender,\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .message {\n\tcolor: #a9a9a9;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-left: 0.4em; */\n}\n\n/* DEBUG/INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #777;\n  \tz-index: 190;\n\tbackground: #222;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #444;\n\tborder-bottom: 1px solid #444;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"]  .message {\n\tcolor: #ff0000;\n\tfont-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tborder: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tborder-bottom: none;\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tborder-top: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n \tpadding: 3px 5px 3px 5px;\n\tcolor: #3D3D3D;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent: \"•\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent: \"•\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\n/* Nickname Colors */\n\n.inlineSender {\n\tfont-weight: 700;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/inlineMedia.css",
    "content": "\n/* Images */\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 12px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/scripts.js",
    "content": "/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.95);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sapientia/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Force Invert Sidebars</key>\n\t<true/>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Nickname Format</key>\n\t<string>%@%n:</string>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n\t<key>Underlying Window Color</key>\n\t<string>#242323</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Dark/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconLight.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Dark/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #fff;\n\theight: 100%;\n \tz-index: 100;\n\tfont-size: 12px;\n\toverflow: hidden;\n\tbackground-color: #000;\n\tfont-family: \"Lucida Grande\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 2.0em); /* height minus topic */\n}\n\ndiv.line {\n \tmargin-top: -1px;\n\tclear: both;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #181818;\n\tborder: 1px solid #333333;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Time */\n\nbody[dir=\"ltr\"] .time {\n\tcolor: #666;\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tcolor: #666;\n\twhite-space: nowrap;\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* Encryption Lock */\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* Links */\n\na {\n\tcolor: #0080FF;\n\tborder-color: #0080FF;\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #40A0FF;\n\tborder-color: #40A0FF;\n}\n\n/* Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\topacity: 0; /* Set by JavaScript */\n\tz-index: 400;\n\tcolor: #8E8E8E;\n\tposition: fixed;\n\tpadding: 2px 0.5em 3px;\n\tbox-shadow: 0 1px 5px #777;\n\tborder-bottom: 1px solid #404040;\n\ttext-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n\tbackground: -webkit-linear-gradient(top, #0F0F0F 0%, #262626 100%);\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n\t<https://github.com/hbang/Simplified-Light-Modifications> */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n#topicBar a,\n#topicBar span.channel {\n\tcolor: #8E8E8E;\n\tborder-color: #8E8E8E;\n\ttext-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n}\n\n/* Remember Line */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #444;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #5a5a5a;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #606060;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #d8d8d8;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #f00;\n  \tz-index: 191;\n\tbackground: #400;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #811;\n\tborder-bottom: 1px solid #811;\n}\n\ndiv.line[data-line-type=\"notice\"] .sender {\n\tcolor: #f00;\n\tfont-weight: 700;\n}\n\n/* Selected User Messages */\n\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #aaa;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n\n  \tz-index: 190;\n  \tposition: relative;\n\tborder-top: 1px solid #02577C !important;\n\tborder-bottom: 1px solid #02577C !important;\n  \tbackground-color: rgba(3, 134, 212, 0.25) !important;\n}\n\n/* PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"false\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n  \tz-index: 191;\n  \tposition: relative;\n\tfont-weight: normal;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #988C00;\n\tborder-bottom: 1px solid #988C00;\n  \tbackground-color: #362C00 !important;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .message {\n\tcolor: #fff;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\tfont-weight: 700;\n\twhite-space: pre-wrap;\n}\n\n/* ACTION */\n\ndiv.line[data-line-type=\"action\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"action\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .sender,\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .message {\n\tcolor: #B52CF6;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-left: 0.4em; */\n}\n\n/* DEBUG/INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #777;\n  \tz-index: 190;\n\tbackground: #222;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #444;\n\tborder-bottom: 1px solid #444;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] .message {\n\tcolor: #ff0000;\n\tfont-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tborder: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tborder-bottom: none;\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tborder-top: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n \tpadding: 3px 5px 3px 5px;\n\tcolor: #666;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\n/* Nickname Colors */\n\n.inlineSender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender[data-member-type=\"myself\"] {\n\tcolor: #B8DFFF;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Dark/inlineMedia.css",
    "content": "\n/* Images */\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 12px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Dark/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Underlying Window Color</key>\n\t<string>#000000</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Light/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconDark.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Light/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: light;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n  \tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #000;\n\theight: 100%;\n \tz-index: 100;\n\tfont-size: 12px;\n\toverflow: hidden;\n\tbackground-color: #fff;\n\tfont-family: \"Lucida Grande\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 2.0em); /* height minus topic */\n}\n\ndiv.line {\n \tmargin-top: -1px;\n\tclear: both;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #fbfbfb;\n\tbox-shadow: inset 1px 0px 0px 0px #e8e8e8;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #c1c1c1;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #7d7d7d;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #f3f3f3;\n\tborder: 1px solid #d7d7d7;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Time */\n\nbody[dir=\"ltr\"] .time {\n\tcolor: #aaa;\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tcolor: #aaa;\n\twhite-space: nowrap;\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* Encryption Lock */\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* Links */\n\na {\n\tcolor: #00e;\n\tborder-color: #00e;\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #0080FF;\n\tborder-color: #0080FF;\n}\n\n/* Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tcolor: #FFFFFF;\n\tposition: fixed;\n\tpadding: 2px 0.5em 3px;\n\tbox-shadow: 0 1px 5px #777;\n\tborder-bottom: 1px solid #61778F;\n\ttext-shadow: 1px 1px rgba(83, 86, 94, 0.7);\n\tbackground: -webkit-linear-gradient(top, #A2B0D0 0%, #7385AD 100%);\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n\t<https://github.com/hbang/Simplified-Light-Modifications> */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n#topicBar a,\n#topicBar span.channel {\n\tcolor: #FFFFFF;\n\tborder-color: #FFFFFF;\n\ttext-shadow: 1px 1px rgba(83, 86, 94, 0.7);\n}\n\n/* Remember Line */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #444;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #b6b6b6;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #dbdbdb;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #a6a6a6;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #f00;\n  \tz-index: 191;\n\tbackground: #fcc;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #f77;\n\tborder-bottom: 1px solid #f77;\n}\n\ndiv.line[data-line-type=\"notice\"] .sender {\n\tcolor: #f00;\n\tfont-weight: 700;\n}\n\n/* Selected User Messages */\n\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #000;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n\n  \tz-index: 190;\n  \tposition: relative;\n\tborder-top: 1px solid #FC5AF8 !important;\n\tborder-bottom: 1px solid #FC5AF8 !important;\n  \tbackground-color: rgba(246, 70, 255, 0.2) !important;\n}\n\n/* PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"false\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n  \tz-index: 191;\n  \tposition: relative;\n\tfont-weight: normal;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #F6E73F;\n\tborder-bottom: 1px solid #F6E73F;\n  \tbackground-color: #FAF4AF !important;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .message {\n\tcolor: #000;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .message {\n\tcolor: #000;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\tfont-weight: 700;\n\twhite-space: pre-wrap;\n}\n\n/* ACTION */\n\ndiv.line[data-line-type=\"action\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid transparent;\n\tborder-bottom: 1px solid transparent;\n\tbackground-color: none;\n}\n\ndiv.line[data-line-type=\"action\"] .message {\n\tcolor: #000;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .sender,\ndiv.line[data-line-type=\"action\"][data-member-type=\"myself\"] .message {\n\tcolor: #B52CF6;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-left: 0.4em; */\n}\n\n/* DEBUG/INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #777;\n  \tz-index: 190;\n\tbackground: #eee;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #ddd;\n\tborder-bottom: 1px solid #ddd;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"]  .message {\n\tcolor: #ff0000;\n\tfont-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tborder: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tborder-bottom: none;\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tborder-top: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n \tpadding: 3px 5px 3px 5px;\n\tcolor: #aaa;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\n/* Nickname Colors */\n\n.inlineSender {\n\tfont-weight: 700;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender[data-member-type=\"myself\"] {\n\tcolor: #ea0d68;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Light/inlineMedia.css",
    "content": "\n/* Images */\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 12px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/Varieties/Light/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>light</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000033</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-light</string>\n\t<key>Underlying Window Color</key>\n\t<string>#FFFFFF</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/copyright.txt",
    "content": "This style is a modified and stripped down version of \nthe \"Simplified\" theme developed by \"Cowboy\" Ben Alman\n(http://benalman.com/). Copyright © 2010, 2011, 2012."
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/scripts.js",
    "content": "/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.95);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Simplified/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/LICENSE.txt",
    "content": "Copyright (c) 2013 Ryan Grove (ryan@wonko.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the ‘Software’), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/Templates/newMessagePostedWithSender.mustache",
    "content": "\n<div \n\tclass=\"line {{lineClassAttribute}}\"\n\tid=\"line-{{lineNumber}}\"\n\n\tdata-command=\"{{command}}\"\n\n{{#isEncrypted}}\n\tdata-encrypted=\"true\"\n{{/isEncrypted}}\n\n\tdata-highlight=\"{{highlightAttribute}}\"\n\tdata-line-type=\"{{lineType}}\"\n\n{{^isRemoteMessage}}\n\tdata-member-type=\"{{nicknameType}}\"\n{{/isRemoteMessage}}\n\n\tdata-timestamp=\"{{timestamp}}\">\n\n{{#isEncrypted}}\n\t{{{encryptedMessageLockTemplate}}}\n{{/isEncrypted}}\n\n\t<span class=\"sender\"\n\t\tonclick=\"Textual.nicknameMaybeWasDoubleClicked(this)\"\n\t\toncontextmenu=\"Textual.openStandardNicknameContextualMenu()\"\n\t\tdata-member-type=\"{{nicknameType}}\"\n\t\tdata-nickname=\"{{nickname}}\"\n\n\t\t{{#nicknameColorHashingEnabled}}\n\t\t\t{{#nicknameColorStyleOverride}}\n\t\t\tdata-override-color=\"true\"\n\t\t\t{{/nicknameColorStyleOverride}}\n\n\t\t\t{{^ isEmpty(nicknameColorStyle) }}\n\t\t\tstyle=\"color: {{nicknameColorStyle}};\"\n\t\t\t{{/ isEmpty(nicknameColorStyle) }}\n\t\t{{/nicknameColorHashingEnabled}}>{{formattedNickname}}</span>\n\n\t<span class=\"message\">{{{formattedMessage}}}\n\n\t\t{{#inlineMediaEnabled}}\n\t\t\t<span class=\"inlineMediaContainer\"></span>\n\t\t{{/inlineMediaEnabled}}\n\t</span>\t\t\n\n\t<span class=\"time\"\n\n\t{{^ isEmpty(localizedTimestamp) }}\n\t\ttitle=\"{{localizedTimestamp}}\"\n\t{{/ isEmpty(localizedTimestamp) }}>{{formattedTimestamp}} </span>\n</div>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/Templates/newMessagePostedWithoutSender.mustache",
    "content": "\n<div\n\tdata-command=\"{{command}}\"\n\tdata-line-type=\"{{lineType}}\"\n\n{{^isRemoteMessage}}\n\tdata-member-type=\"{{nicknameType}}\"\n{{/isRemoteMessage}}\n\n\tdata-timestamp=\"{{timestamp}}\"\n\tclass=\"line {{lineClassAttribute}}\"\n\tid=\"line-{{lineNumber}}\">\n\n\t<span class=\"sender\"></span>\n\n\t<span class=\"message\">{{{formattedMessage}}}</span>\n\n\t<span class=\"time\"\n\n\t{{^ isEmpty(localizedTimestamp) }}\n\ttitle=\"{{localizedTimestamp}}\"\n\t{{/ isEmpty(localizedTimestamp) }}>{{formattedTimestamp}} </span>\n</div>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\nbody {\n\tbackground: #222;\n\tcolor: #cfcfcf;\n\tfont-family: 'Myriad Pro';\n\tfont-size: 16px;\n\tline-height: 1.4;\n\tmargin: 0;\n\toverflow: hidden;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\na {\n\tborder-bottom: dotted 1px #8cb3ff;\n\tcolor: #8cb3ff;\n\ttext-decoration: none;\n}\n\na:hover {\n\tborder: none;\n\tborder-bottom: solid 1px #8cb3ff;\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n.message,\n.sender,\n.time {\n\tpadding: 4px 8px 3px;\n}\n\n.message {\n\twidth: 100%;\n}\n\n.sender,\n.time {\n\tflex-shrink: 0;\n\tbackground: #333;\n}\n\n.sender {\n\tfont-weight: 600;\n\toverflow: hidden;\n\ttext-align: right;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\twidth: 10em;\n}\n\nbody[data-view-type=\"sender\"] .sender {\n\tdisplay: none;\n}\n\n.time {\n\tcolor: #888;\n\tfont-size: 0.8em;\n\tline-height: 1.8;\n\twhite-space: nowrap;\n}\n\ndiv.line {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tflex-flow: row;\n\t-webkit-flex-flow: row;\n}\n\ndiv.line[data-member-type=\"myself\"] .message {\n\tbackground: #2e2e2e;\n}\n\ndiv.line[data-line-type=\"action\"] .message,\ndiv.line[data-line-type=\"action\"] .sender {\n\tbackground: none;\n\tfont-style: italic;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tpadding-right: 2px;\n}\n\nbody[data-view-type=\"channel\"] .event .message {\n\tcolor: #666;\n}\n\n.event .message:before {\n\tcontent: '» ';\n}\n\nbody[data-view-type=\"server\"] .event .message {\n\tcolor: #999;\n\tfont-size: inherit;\n\tpadding-left: 1em;\n\tpadding-right: 2em;\n}\n\nbody[data-view-type=\"server\"] .event .message:before {\n\tcontent: '';\n}\n\n.event .sender {\n\tbackground: inherit;\n}\n\ndiv.line.text:hover,\nbody[data-view-type=\"server\"] .line:hover {\n\toutline: 1px solid #666;\n}\n\ndiv.line.text:hover .message,\ndiv.line.text:hover .sender,\ndiv.line.text:hover .time,\nbody[data-view-type=\"server\"] .line:hover .message,\nbody[data-view-type=\"server\"] .line:hover .time {\n\tbackground-color: #444;\n\tcolor: #fff;\n}\n\ndiv.line.text[data-highlight=\"true\"],\ndiv.line.text[data-highlight=\"true\"] .time {\n\tcolor: #fff;\n}\n\ndiv.line.text[data-highlight=\"true\"] {\n\tborder: 1px solid #284e84;\n\tborder-left: none;\n\tborder-right: none;\n\toutline: none;\n}\n\ndiv.line.text[data-highlight=\"true\"]:hover {\n\tborder-color: #3069ab;\n}\n\ndiv.line.text[data-highlight=\"true\"] + div.line.text[data-highlight=\"true\"] {\n\tborder-top: none;\n}\n\ndiv.line.text[data-highlight=\"true\"] .message,\ndiv.line.text[data-highlight=\"true\"] .sender,\ndiv.line.text[data-highlight=\"true\"] .time {\n\tbackground-color: #1b3458;\n}\n\ndiv.line.text[data-highlight=\"true\"]:hover .message,\ndiv.line.text[data-highlight=\"true\"]:hover .sender,\ndiv.line.text[data-highlight=\"true\"]:hover .time {\n\tbackground-color: #204571;\n}\n\n/* Selected User */\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #fff;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: color, border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s, 0.5s;\n\n\tcolor: #fff;\n\tborder: 1px solid #942f25;\n\tborder-left: none;\n\tborder-right: none;\n\toutline: none;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"]:hover {\n\tborder-color: #aa362b;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] + div.line.selectedUser[data-highlight=\"false\"] {\n\tborder-top: none;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .message,\ndiv.line.selectedUser[data-highlight=\"false\"] .sender,\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\tbackground-color: #521e17;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"]:hover .message,\ndiv.line.selectedUser[data-highlight=\"false\"]:hover .sender,\ndiv.line.selectedUser[data-highlight=\"false\"]:hover .time {\n\tbackground-color: #68271d;\n}\n\n/* Remember Line */\n#mark {\n\tborder-bottom: 1px dotted #9f9f9f;\n\tmargin: 1px 0;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Loading Screen */\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #181818;\n\tborder: 1px solid #333;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1;\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Topic Bar */\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tcolor: #efefef;\n\tposition: fixed;\n\tpadding: 4px 12px 2px;\n\tbox-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.8);\n\tborder-bottom: 1px solid #404040;\n\ttext-shadow: 1px 1px rgba(83, 86, 94, 0.7);\n\tbackground: #333;\n\tfont-weight: 600;\n\ttext-align: center;\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n}\n\n#topicBar a,\n#topicBar span.channel {\n\tcolor: #f5f5f5;\n\tborder-color: #f5f5f5;\n\ttext-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n}\n\n/* Scrolling */\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* Message buffer loading animation */\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #797979;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #444;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #919191;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* Nickname Colors */\ndata.line.text .sender[data-member-type=\"myself\"] { \n\tcolor: #ff8c00;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/inlineMedia.css",
    "content": "\n/* Images */\n\n.inlineImage,\n.inlineVideo,\n.inlineVideoService {\n\tmargin-top: 8px !important;\n\tmargin-bottom: 8px !important;\n}\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 15px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/scripts.js",
    "content": "\n// -- Sulaco -------------------------------------------------------------------\n\nvar Sulaco;\n\nSulaco = {\n\tcoalesceMessages: function (line) \n\t{\n\t\tvar previousLine = Sulaco.getPreviousLine(line);\n\t\tvar previousSender = Sulaco.getSenderNickname(previousLine);\n\n\t\tvar sender = Sulaco.getSenderNickname(line);\n\n\t\tif (sender === null || previousSender === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (sender === previousSender &&\n\t\t\tSulaco.getLineType(line) === 'privmsg' &&\n\t\t\tSulaco.getLineType(previousLine) === 'privmsg')\n\t\t{\n\t\t\tline.classList.add('coalesced');\n\n\t\t\tSulaco.getSenderElement(line).innerHTML = '';\n\t\t}\n\t},\n\n\tgetPreviousLine: function (line)\n\t{\n\t\tvar previousLine = line.previousElementSibling;\n\n\t\tif (previousLine &&\n\t\t\tpreviousLine.classList &&\n\t\t\tpreviousLine.classList.contains('line'))\n\t\t{\n\t\t\treturn previousLine;\n\t\t}\n\n\t\treturn null;\n\t},\n\n\tgetLineType: function (line)\n\t{\n\t\treturn ((line) ? line.dataset.lineType : null);\n\t},\n\n\tgetMessage: function (line)\n\t{\n\t\treturn ((line) ? line.querySelector('.message').textContent.trim() : null);\n\t},\n\n\tgetSenderElement: function (line)\n\t{\n\t\treturn ((line) ? line.querySelector('.sender') : null);\n\t},\n\n\tgetSenderNickname: function (line)\n\t{\n\t\tvar sender = Sulaco.getSenderElement(line);\n\n\t\treturn ((sender) ? sender.dataset.nickname : null);\n\t}\n};\n\n// -- Textual ------------------------------------------------------------------\n\n/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.90);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tSulaco.coalesceMessages(element);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Sulaco/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Nickname Format</key>\n\t<string>%@%n</string>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n\t<key>Underlying Window Color</key>\n\t<string>#222222</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Dark/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconLight.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Dark/design.css",
    "content": "/* Colors taken from the Tomorrow and base16 themes:\n * https://github.com/ChrisKempson/Tomorrow-Theme\n * https://github.com/chriskempson/base16\n */\n\n/* @group Inline media */\n\n@import \"inlineMedia.css\";\n\n/* @end */\n\n/* @group Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #CCCCCC; /* Tomorrow Night Eighties: Foreground */\n\theight: 100%;\n\tz-index: 100;\n\tfont-size: 12px;\n\toverflow: hidden;\n\tbackground-color: #2D2D2D; /* Tomorrow Night Eighties: Background */\n\tfont-family: \"EspressoMono-Regular\", \"Menlo\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 1.7em); /* height minus topic */\n}\n\ndiv.line {\n\tpadding: 2px 5px 2px 5px;\n\tclear: both;\n}\n\n.sender {\n\tcursor: pointer;\n\tfont-weight: 700;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* @end */\n\n/* @group Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* @end */\n\n/* @group Misc */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #393939; /* Tomorrow Night Eighties: Current Line */\n\tborder: 1px solid #373B41; /* Tomorrow: Selection */\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n\ttext-align: center;\n}\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* @end */\n\n/* @group Time */\n\n.time {\n\tcolor: #515151; /* Tomorrow Night Eighties: Selection */\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* @end */\n\n/* @group Links */\n\na {\n\tcolor: #6699CC; /* Tomorrow Night Eighties: Blue */\n\tborder-color: #6699CC; /* Tomorrow Night Eighties: Blue */\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #CC99CC; /* Tomorrow Night Eighties: Purple */\n\tborder-color: #CC99CC; /* Tomorrow Night Eighties: Purple */\n}\n\n/* @end */\n\n/* @group Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tcolor: #D1F1A9; /* Tomorrow Night Blue: Green */\n\tposition: fixed;\n\tpadding: 2px 0.5em 3px;\n\tbackground-color: rgba(113, 140, 00, 0.9); /* Tomorrow: Green 90% */\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n * https://github.com/hbang/Simplified-Light-Modifications\n */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n/* @end */\n\n/* @group Separating History */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #F2777A; /* Tomorrow Night Eighties: Red */\n\t-webkit-transition: 0.2s linear;\n}\n\n/* @end */\n\n/* @group Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #797979;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* @end */\n\n/* @group Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #444;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #919191;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* @end */\n\n/* @group NOTICE / CTCP / WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #FFCC66; /* Tomorrow Night Eighties: Yellow */\n\tz-index: 191;\n\tbackground-color: rgba(234, 183, 00, 0.2); /* Tomorrow: Yellow 20% */\n\tposition: relative;\n}\n\n/* @end */\n\n/* @group Selected User */\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition: background-color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition: background-color 0.5s;\n\tz-index: 190;\n\tposition: relative;\n\tbackground-color: rgba(245, 135, 31, 0.2) !important; /* Tomorrow: Orange 20% */\n}\n\n/* @end */\n\n/* @group PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n\tz-index: 191;\n\tposition: relative;\n\tfont-weight: normal;\n\tbackground-color: rgba(200, 40, 41, 0.2) !important; /* Tomorrow: Red 20% */\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\twhite-space: pre-wrap;\n}\n\n/* @end */\n\n/* @group ACTION */\n\ndiv.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"•\";\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tmargin-left: 0.4em;\n}\n\ndiv.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n}\n\n/* @end */\n\n/* @group DEBUG / INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #4D4D4C; /* Tomorrow: Foreground */\n\tz-index: 190;\n\tbackground: rgba(55, 59, 65, 0.2); /* Tomorrow Night: Selection 20% */\n\tposition: relative;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] .message {\n\tcolor: #F2777A;\n\tfont-weight: 700;\n}\n\n/* @end */\n\n/* @group Message of the Day (MOTD)\n *\n * 720, 721, 722 are used by ShadowIRCd for Oper MOTD.\n * 372, 375, 376 are normal MOTD shared by several IRCds.\n */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"EspressoMono-Regular\", \"Menlo\" !important;\n}\n\n/* @end */\n\n/* @group General Events */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n\tcolor: #424242; /* Tomorrow Night Bright: Selection */\n}\n\n/* Slightly more interesting events */\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"mode\"][data-command=\"mode\"] {\n\tcolor: #515151; /* Tomorrow Night Eighties: Selection */\n}\n\n/* @group Event Indicators */\n\ndiv.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n\tcolor: #99CC99; /* Tomorrow Night Eighties: Green */\n}\n\ndiv.line[data-line-type=\"kick\"] .message:before,\ndiv.line[data-line-type=\"part\"] .message:before,\ndiv.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n\tcolor: #F2777A; /* Tomorrow Night Eighties: Red */\n}\n\ndiv.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"◦\";\n\tcolor: #66CCCC; /* Tomorrow Night Eighties: Aqua */\n}\n\n/* @end */\n\n/* @end */\n\n/* @group Own Messages */\n\n.sender[data-member-type=\"myself\"] {\n\tcolor: #6699CC; /* Tomorrow Night Eighties: Blue */\n}\n\ndiv[data-member-type=\"myself\"] {\n\tbackground-color: rgba(66, 113, 174, 0.2); /* Tomorrow: Blue 20% */\n}\n\n/* @end */\n\n/* @group mIRC Color Codes */\n\n/* @group Foreground Colors */\n\n.effect[data-foreground-color=\"0\"] {\n\tcolor: #EAEAEA !important; /* Tomorrow Night Bright: Foreground */\n}\n\n.effect[data-foreground-color=\"1\"] {\n\tcolor: #515151 !important; /* Tomorrow Night Eighties: Selection */\n}\n\n.effect[data-foreground-color=\"2\"] {\n\tcolor: #6699CC !important; /* Tomorrow Night Eighties: Blue */\n}\n\n.effect[data-foreground-color=\"3\"] {\n\tcolor: #99CC99 !important; /* Tomorrow Night Eighties: Green */\n}\n\n.effect[data-foreground-color=\"4\"] {\n\tcolor: #F2777A !important; /* Tomorrow Night Eighties: Red */\n}\n\n.effect[data-foreground-color=\"5\"] {\n\tcolor: #FF9DA4 !important; /* Tomorrow Night Blue: Red */\n}\n\n.effect[data-foreground-color=\"6\"] {\n\tcolor: #CC99CC !important; /* Tomorrow Night Eighties: Purple */\n}\n\n.effect[data-foreground-color=\"7\"] {\n\tcolor: #F99157 !important; /* Tomorrow Night Eighties: Orange */\n}\n\n.effect[data-foreground-color=\"8\"] {\n\tcolor: #FFCC66 !important; /* Tomorrow Night Eighties: Yellow */\n}\n\n.effect[data-foreground-color=\"9\"] {\n\tcolor: #B9CA4A !important; /* Tomorrow Night Bright: Green */\n}\n\n.effect[data-foreground-color=\"10\"] {\n\tcolor: #66CCCC !important; /* Tomorrow Night Eighties: Aqua */\n}\n\n.effect[data-foreground-color=\"11\"] {\n\tcolor: #99FFFF !important; /* Tomorrow Night Blue: Aqua */\n}\n\n.effect[data-foreground-color=\"12\"] {\n\tcolor: #7AA6DA !important; /* Tomorrow Night Bright: Blue */\n}\n\n.effect[data-foreground-color=\"13\"] {\n\tcolor: #C397D8 !important; /* Tomorrow Night Bright: Purple */\n}\n\n.effect[data-foreground-color=\"14\"] {\n\tcolor: #999999 !important; /* Tomorrow Night Eighties: Comment */\n}\n\n.effect[data-foreground-color=\"15\"] {\n\tcolor: #CCCCCC !important; /* Tomorrow Night Eighties: Foreground */\n}\n\n/* @end */\n\n/* @group Background Colors */\n\n.effect[data-background-color=\"0\"] {\n\tbackground-color: #EAEAEA !important; /* Tomorrow Night Bright: Foreground */\n}\n\n.effect[data-background-color=\"1\"] {\n\tbackground-color: #515151 !important; /* Tomorrow Night Eighties: Selection */\n}\n\n.effect[data-background-color=\"2\"] {\n\tbackground-color: #6699CC !important; /* Tomorrow Night Eighties: Blue */\n}\n\n.effect[data-background-color=\"3\"] {\n\tbackground-color: #99CC99 !important; /* Tomorrow Night Eighties: Green */\n}\n\n.effect[data-background-color=\"4\"] {\n\tbackground-color: #F2777A !important; /* Tomorrow Night Eighties: Red */\n}\n\n.effect[data-background-color=\"5\"] {\n\tbackground-color: #FF9DA4 !important; /* Tomorrow Night Blue: Red */\n}\n\n.effect[data-background-color=\"6\"] {\n\tbackground-color: #CC99CC !important; /* Tomorrow Night Eighties: Purple */\n}\n\n.effect[data-background-color=\"7\"] {\n\tbackground-color: #F99157 !important; /* Tomorrow Night Eighties: Orange */\n}\n\n.effect[data-background-color=\"8\"] {\n\tbackground-color: #FFCC66 !important; /* Tomorrow Night Eighties: Yellow */\n}\n\n.effect[data-background-color=\"9\"] {\n\tbackground-color: #B9CA4A !important; /* Tomorrow Night Bright: Green */\n}\n\n.effect[data-background-color=\"10\"] {\n\tbackground-color: #66CCCC !important; /* Tomorrow Night Eighties: Aqua */\n}\n\n.effect[data-background-color=\"11\"] {\n\tbackground-color: #99FFFF !important; /* Tomorrow Night Blue: Aqua */\n}\n\n.effect[data-background-color=\"12\"] {\n\tbackground-color: #7AA6DA !important; /* Tomorrow Night Bright: Blue */\n}\n\n.effect[data-background-color=\"13\"] {\n\tbackground-color: #C397D8 !important; /* Tomorrow Night Bright: Purple */\n}\n\n.effect[data-background-color=\"14\"] {\n\tbackground-color: #999999 !important; /* Tomorrow Night Eighties: Comment */\n}\n\n.effect[data-background-color=\"15\"] {\n\tbackground-color: #CCCCCC !important; /* Tomorrow Night Eighties: Foreground */\n}\n\n/* @end */\n\n/* @end */\n\n/*\n\tvim: set foldmethod=marker:\n\tvim: set foldmarker=@group,@end:\n\tvim: set nofoldenable:\n */\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Dark/inlineMedia.css",
    "content": "\n/* @group Images */\n\n.inlineImage,\n.inlineVideo,\n.inlineVideoService {\n\tmargin-top: 8px !important;\n\tmargin-bottom: 8px !important;\n}\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 15px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n\n/* @end */\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Dark/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Underlying Window Color</key>\n\t<string>#2D2D2D</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Light/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconDark.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Light/design.css",
    "content": "/* Colors taken from the Tomorrow and base16 themes:\n * https://github.com/ChrisKempson/Tomorrow-Theme\n * https://github.com/chriskempson/base16\n */\n\n/* @group Inline media */\n\n@import \"inlineMedia.css\";\n\n/* @end */\n\n/* @group Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: light;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n}\n\nbody {\n\tcolor: #4D4D4C; /* Tomorrow: Foreground */\n\theight: 100%;\n\tz-index: 100;\n\tfont-size: 12px;\n\toverflow: hidden;\n\tbackground-color: #FFFFFF; /* Tomorrow: Background */\n\tfont-family: \"EspressoMono-Regular\", \"Menlo\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 1.7em); /* height minus topic */\n}\n\ndiv.line {\n\tpadding: 2px 5px 2px 5px;\n\tclear: both;\n}\n\n.sender {\n\tcursor: pointer;\n\tfont-weight: 700;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* @end */\n\n/* @group Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #fbfbfb;\n\tbox-shadow: inset 1px 0px 0px 0px #e8e8e8;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #c1c1c1;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #7d7d7d;\n}\n\n/* @end */\n\n/* @group Misc */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #EFEFEF; /* Tomorrow: Current Line */\n\tborder: 1px solid #D6D6D6; /* Tomorrow: Selection */\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n\ttext-align: center;\n}\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* @end */\n\n/* @group Time */\n\n.time {\n\tcolor: #C5C8C6; /* Tomorrow Night: Foreground */\n\twhite-space: nowrap;\n}\n\nbody[dir=\"rtl\"] .time {\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* @end */\n\n/* @group Links */\n\na {\n\tcolor: #4271AE; /* Tomorrow: Blue */\n\tborder-color: #4271AE; /* Tomorrow: Blue */\n\ttext-decoration: none;\n\tborder-bottom: dotted 1px;\n}\n\na:hover {\n\tcolor: #8959A8; /* Tomorrow: Purple */\n\tborder-color: #8959A8; /* Tomorrow: Purple */\n}\n\n/* @end */\n\n/* @group Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tz-index: 400;\n\topacity: 0; /* Set by JavaScript */\n\tcolor: #718C00; /* Tomorrow Night Blue: Green */\n\tposition: fixed;\n\tpadding: 2px 0.5em 3px;\n\tbackground-color: rgba(209, 241, 169, 0.95); /* Tomorrow Night Blue: Green 95% */\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n * https://github.com/hbang/Simplified-Light-Modifications\n */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n/* @end */\n\n/* @group Separating History */\n\n#mark {\n\tclear: both;\n\tposition: relative;\n\tz-index: 295;\n\tmargin-top: -1px;\n\tborder-bottom: 1px dashed;\n\tborder-color: #C82829; /* Tomorrow: Red */\n\t-webkit-transition: 0.2s linear;\n}\n\n/* @end */\n\n/* @group Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #b6b6b6;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* @end */\n\n/* @group Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #dbdbdb;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #a6a6a6;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* @end */\n\n/* @group NOTICE / CTCP / WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #EAB700; /* Tomorrow: Yellow */\n\tz-index: 191;\n\tbackground-color: rgba(255, 238, 173, 0.25); /* Tomorrow Night Blue: Yellow 25% */\n\tposition: relative;\n}\n\n/* @end */\n\n/* @group Selected User */\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition: background-color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition: background-color 0.5s;\n\tz-index: 190;\n\tposition: relative;\n\tbackground-color: rgba(255, 197, 143, 0.25) !important; /* Tomorrow Night Blue: Orange 25% */\n}\n\n/* @end */\n\n/* @group PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n\tz-index: 191;\n\tposition: relative;\n\tfont-weight: normal;\n\tbackground-color: rgba(255, 157, 164, 0.25) !important; /* Tomorrow Night Blue: Red 25% */\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\twhite-space: pre-wrap;\n}\n\n/* @end */\n\n/* @group ACTION */\n\ndiv.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"•\";\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tmargin-left: 0.4em;\n}\n\ndiv.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n}\n\n/* @end */\n\n/* @group DEBUG / INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #C5C8C6; /* Tomorrow Night: Foreground */\n\tz-index: 190;\n\tbackground: rgba(214, 214, 214, 0.25); /* Tomorrow: Selection 25% */\n\tposition: relative;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] .message {\n\tcolor: #C82829;\n\tfont-weight: 700;\n}\n\n/* @end */\n\n/* @group Message of the Day (MOTD)\n *\n * 720, 721, 722 are used by ShadowIRCd for Oper MOTD.\n * 372, 375, 376 are normal MOTD shared by several IRCds.\n */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"EspressoMono-Regular\", \"Menlo\" !important;\n}\n\n/* @end */\n\n/* @group General Events */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n\tcolor: #C5C8C6; /* Tomorrow Night: Foreground */\n}\n\n/* Slightly more interesting events */\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"mode\"][data-command=mode] {\n\tcolor: #8E908C; /* Tomorrow: Comment */\n}\n\n/* @group Event Indicators */\n\ndiv.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n\tcolor: #718C00; /* Tomorrow: Green */\n}\n\ndiv.line[data-line-type=\"kick\"] .message:before,\ndiv.line[data-line-type=\"part\"] .message:before,\ndiv.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n\tcolor: #C82829; /* Tomorrow: Red */\n}\n\ndiv.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"◦\";\n\tcolor: #3E999F; /* Tomorrow: Aqua */\n}\n\n/* @end */\n\n/* @end */\n\n/* @group Own Messages */\n\n.sender[data-member-type=\"myself\"] {\n\tcolor: #4271AE; /* Tomorrow: Blue */\n}\n\ndiv[data-member-type=\"myself\"] {\n\tbackground-color: rgba(187, 218, 255, 0.25); /* Tomorrow Night Blue: Blue 25% */\n}\n\n/* @end */\n\n/* @group mIRC Color Codes */\n\n/* @group Foreground Colors */\n\n.effect[data-foreground-color=\"0\"] {\n\tcolor: #D6D6D6 !important; /* Tomorrow: Selection */\n}\n\n.effect[data-foreground-color=\"1\"] {\n\tcolor: #4D4D4C !important; /* Tomorrow: Foreground */\n}\n\n.effect[data-foreground-color=\"2\"] {\n\tcolor: #4271AE !important; /* Tomorrow: Blue */\n}\n\n.effect[data-foreground-color=\"3\"] {\n\tcolor: #718C00 !important; /* Tomorrow: Green */\n}\n\n.effect[data-foreground-color=\"4\"] {\n\tcolor: #C82829 !important; /* Tomorrow: Red */\n}\n\n.effect[data-foreground-color=\"5\"] {\n\tcolor: #DE935F !important; /* Tomorrow Night: Red */\n}\n\n.effect[data-foreground-color=\"6\"] {\n\tcolor: #8959A8 !important; /* Tomorrow: Purple */\n}\n\n.effect[data-foreground-color=\"7\"] {\n\tcolor: #F5871F !important; /* Tomorrow: Orange */\n}\n\n.effect[data-foreground-color=\"8\"] {\n\tcolor: #EAB700 !important; /* Tomorrow: Yellow */\n}\n\n.effect[data-foreground-color=\"9\"] {\n\tcolor: #B9CA4A !important; /* Tomorrow Night Bright: Green */\n}\n\n.effect[data-foreground-color=\"10\"] {\n\tcolor: #3E999F !important; /* Tomorrow: Aqua */\n}\n\n.effect[data-foreground-color=\"11\"] {\n\tcolor: #66CCCC !important; /* Tomorrow Night Eighties: Aqua */\n}\n\n.effect[data-foreground-color=\"12\"] {\n\tcolor: #7AA6DA !important; /* Tomorrow Night Bright: Blue */\n}\n\n.effect[data-foreground-color=\"13\"] {\n\tcolor: #C397D8 !important; /* Tomorrow Night Bright: Purple */\n}\n\n.effect[data-foreground-color=\"14\"] {\n\tcolor: #8E908C !important; /* Tomorrow: Comment */\n}\n\n.effect[data-foreground-color=\"15\"] {\n\tcolor: #C5C8C6 !important; /* Tomorrow Night: Foreground */\n}\n\n/* @end */\n\n/* @group Background Colors */\n\n.effect[data-background-color=\"0\"] {\n\tbackground-color: #D6D6D6 !important; /* Tomorrow: Selection */\n}\n\n.effect[data-background-color=\"1\"] {\n\tbackground-color: #4D4D4C !important; /* Tomorrow: Foreground */\n}\n\n.effect[data-background-color=\"2\"] {\n\tbackground-color: #4271AE !important; /* Tomorrow: Blue */\n}\n\n.effect[data-background-color=\"3\"] {\n\tbackground-color: #718C00 !important; /* Tomorrow: Green */\n}\n\n.effect[data-background-color=\"4\"] {\n\tbackground-color: #C82829 !important; /* Tomorrow: Red */\n}\n\n.effect[data-background-color=\"5\"] {\n\tbackground-color: #DE935F !important; /* Tomorrow Night: Red */\n}\n\n.effect[data-background-color=\"6\"] {\n\tbackground-color: #8959A8 !important; /* Tomorrow: Purple */\n}\n\n.effect[data-background-color=\"7\"] {\n\tbackground-color: #F5871F !important; /* Tomorrow: Orange */\n}\n\n.effect[data-background-color=\"8\"] {\n\tbackground-color: #EAB700 !important; /* Tomorrow: Yellow */\n}\n\n.effect[data-background-color=\"9\"] {\n\tbackground-color: #B9CA4A !important; /* Tomorrow Night Bright: Green */\n}\n\n.effect[data-background-color=\"10\"] {\n\tbackground-color: #3E999F !important; /* Tomorrow: Aqua */\n}\n\n.effect[data-background-color=\"11\"] {\n\tbackground-color: #66CCCC !important; /* Tomorrow Night Eighties: Aqua */\n}\n\n.effect[data-background-color=\"12\"] {\n\tbackground-color: #7AA6DA !important; /* Tomorrow Night Bright: Blue */\n}\n\n.effect[data-background-color=\"13\"] {\n\tbackground-color: #C397D8 !important; /* Tomorrow Night Bright: Purple */\n}\n\n.effect[data-background-color=\"14\"] {\n\tbackground-color: #8E908C !important; /* Tomorrow: Comment */\n}\n\n.effect[data-background-color=\"15\"] {\n\tbackground-color: #C5C8C6 !important; /* Tomorrow Night: Foreground */\n}\n\n/* @end */\n\n/* @end */\n\n/*\n\tvim: set foldmethod=marker:\n\tvim: set foldmarker=@group,@end:\n\tvim: set nofoldenable:\n */\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Light/inlineMedia.css",
    "content": "\n/* @group Images */\n\n.inlineImage,\n.inlineVideo,\n.inlineVideoService {\n\tmargin-top: 8px !important;\n\tmargin-bottom: 8px !important;\n}\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 15px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n\n/* @end */\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/Varieties/Light/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>light</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000033</string>\n\t<key>Indentation Offset</key>\n\t<integer>6</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-light</string>\n\t<key>Underlying Window Color</key>\n\t<string>#FFFFFF</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/copyright.txt",
    "content": "This style is based on the Simplified Light style shipped \nwith Textual as of version 4.1.4.\n\nThe colors are taken from the Tomorrow and base16 themes \nof Chris Kempson.\n\nFor more information, see: \nhttps://github.com/FroZnShiva/Textual-Style-Tomorrow_Night_Eighties\n\nSimplified Light original copyright:\n\nThis style is a modified and stripped down version of \nthe \"Simplified\" theme developed by \"Cowboy\" Ben Alman\n(http://benalman.com/). Copyright © 2010, 2011, 2012.\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/scripts.js",
    "content": "/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.95);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Tomorrow/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/Templates/encryptedMessageLock.mustache",
    "content": "<span class=\"encryptionLock\"><img src=\"{{applicationResourcePath}}/encryptionLockIconLight.tiff\" alt=\"[encrypted]\" title=\"This communication is encrypted.\" /></span>"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/copyright.txt",
    "content": "Developed by Daniel Bird"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/design.css",
    "content": "\n/* Inline media */\n\n@import \"inlineMedia.css\";\n\n/* Basic Body Structure */\n\n:root {\n\tsupported-color-schemes: dark;\n}\n\n* {\n\tmargin: 0;\n\tpadding: 0;\n\tfont-size: 100%;\n\tword-wrap: break-word;\n\tword-break: break-word;\n\tline-height: 1.7em;\n}\n\nbody {\n\tcolor: #e7e7e7;\n\theight: 100%;\n \tz-index: 100;\n\tfont-size: 11px;\n\toverflow: hidden;\n\tbackground-color: #272822;\n\tfont-family: \"Lucida Grande\";\n}\n\n#body {\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\topacity: 0;\n\twidth: 100%;\n\tmax-height: 100%;\n\toverflow-y: auto;\n\tz-index: 100;\n\tposition: absolute;\n\topacity: 0; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Only factor in height of topic bar when selected == true\n because that is only time the topic is displayed according\n to the logic defined by baseLayout.css */\nbody[data-selected=\"true\"][data-view-type=\"channel\"] #body {\n\tmax-height: calc(100% - 2.4em); /* height minus topic */\n}\n\ndiv.line {\n \tmargin-top: -1px;\n\tclear: both;\n}\n\nbody[dir=\"rtl\"] .sender {\n\tdisplay: inline-block;\n}\n\n/* Scrolling */\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar {\n\twidth: 17px;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar:horizontal {\n\theight: 0;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-track {\n\tbackground: #393939;\n\tbox-shadow: inset 1px 0px 0px 0px #4b4b4b;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb {\n\tbackground-color: #7c7c7c;\n\tborder: 4px solid transparent;\n\tborder-left: 5px solid transparent;\n\tborder-radius: 20px;\n\tbackground-clip: content-box;\n}\n\nbody[data-custom-scroller=\"true\"]::-webkit-scrollbar-thumb:hover {\n\tbackground-color: #b0b0b0;\n}\n\n/* Loading Screen */\n\n#loadingScreen {\n\tposition: absolute;\n\ttop: 45%;\n\tleft: calc(50% - (320px / 2)); /* half of width + padding */\n\twidth: 300px;\n\tfont-size: 18px;\n\tbackground: #181818;\n\tborder: 1px solid #333333;\n\tborder-radius: 5px;\n\tpadding: 5px 10px;\n\topacity: 1; /* Set by JavaScript */\n\t-webkit-transition: opacity 0.8s linear;\n}\n\n/* Time */\n\nbody[dir=\"ltr\"] .time {\n\tfont-size: 9px;\n\tcolor: #999;\n\twhite-space: nowrap;\n\ttext-transform:lowercase;\n\tpadding-right: 10px;\n}\n\nbody[dir=\"rtl\"] .time {\n\tcolor: #999;\n\twhite-space: nowrap;\n\tpadding-left: 0.4em;\n\tdisplay: inline-block;\n}\n\n/* Encryption Lock */\n\n.encryptionLock img {\n\tfloat: right;\n\tmargin: 0;\n\tpadding: 0;\n\theight: 11px;\n\tmargin-top: 2px;\n\tpadding-left: 10px;\n}\n\n/* Links */\n\na {\n\tcolor: #2199ff;\n\ttext-decoration: none;\n}\n\na:hover {\n\tcolor: #70baff;\n}\n\n/* Topic Bar */\n\n#topicBar {\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\topacity: 0; /* Set by JavaScript */\n\tz-index: 400;\n\tcolor: #555;\n\tposition: fixed;\n\tpadding: 2px 0.5em 3px;\n\tbox-shadow: 0 1px 5px #444;\n\tborder-bottom: 1px solid #222;\n\ttext-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n\tbackground: #171814;\n\t-webkit-transition: opacity 0.8s linear;\n\t-webkit-font-smoothing: subpixel-antialiased;\n\toverflow: hidden;\n\twhite-space: nowrap;\n\ttext-overflow: ellipsis;\n}\n\n/* Topic bar hover additions contributed with permission from the project:\n\t<https://github.com/hbang/Simplified-Light-Modifications> */\n\n#topicBar:hover {\n\toverflow: visible;\n\twhite-space: normal;\n}\n\n#topicBar a,\n#topicBar span.channel {\n\tcolor: #8E8E8E;\n\tborder-color: #8E8E8E;\n\ttext-shadow: 1px 1px rgba(10, 10, 10, 0.7);\n}\n\n/* Remember Line */\n\n#mark {\n\tposition: relative;\n\tclear: both;\n\tz-index: 295;\n\tmargin: 10px 0;\n\tborder-bottom: 1px dotted;\n\tborder-color: #444;\n\t-webkit-transition: 0.2s linear;\n}\n\n/* Selected User Message */\n\n.sender {\n\tcursor: pointer;\n}\n\ndiv.line[data-line-type=\"privmsg\"]:not(.selectedUser),\ndiv.line[data-line-type=\"action\"]:not(.selectedUser) {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .time:not(.selectedUser),\ndiv.line[data-line-type=\"action\"] .time:not(.selectedUser) {\n\ttransition: color 0.5s;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] .time {\n\ttransition: color 0.5s ease-in;\n\tcolor: #aaa;\n}\n\ndiv.line.selectedUser[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .time {\n\tcolor: #fff;\n}\n\ndiv.line.selectedUser[data-highlight=\"false\"] {\n\ttransition-property: border-top, border-bottom, background-color;\n\ttransition-duration: 0.5s, 0.5s, 0.5s;\n\n  \tz-index: 190;\n  \tposition: relative;\n\n\tborder-top: 0px !important;\n\tborder-bottom: 0px !important;\n  \tbackground-color: #34352d !important;\n}\n\n/* Message buffer loading animation */\n\n.message_buffer_loading_indicator {\n\ttext-align: center;\n\theight: 42px;\n\tposition: relative;\n\tz-index: 200;\n}\n\n.message_buffer_loading_indicator span {\n\tfont-family: Optima !important;\n\tfont-size: 35px;\n\tfont-weight: 600;\n\tletter-spacing: 5px;\n\tline-height: 43px;\n\tcolor: #797979;\n\t-webkit-animation: ellipsis-period 1.5s infinite;\n\tanimation: ellipsis-period 1.5s infinite;\n}\n\n.message_buffer_loading_indicator span:nth-child(1) {\n\t-webkit-animation-delay: 0.0s;\n\tanimation-delay: 0.0s;\n}\n\n.message_buffer_loading_indicator span:nth-child(2) {\n\t-webkit-animation-delay: 0.1s;\n\tanimation-delay: 0.1s;\n}\n\n.message_buffer_loading_indicator span:nth-child(3) {\n\t-webkit-animation-delay: 0.2s;\n\tanimation-delay: 0.2s;\n}\n\n@keyframes ellipsis-period {\n\t0% { opacity: 0.2; }\n\t20% { opacity: 1.0; }\n\t100% { opacity: 0.2; }\n}\n\n/* Message buffer session indicator */\n\n.date_indicator ,\n.session_indicator {\n\tdisplay: flex;\n\tdisplay: -webkit-flex;\n\tpadding: 0.5em 0;\n}\n\n.date_indicator > hr,\n.session_indicator > hr {\n\tbackground: #444;\n\tborder: 0;\n\theight: 1px;\n\tmargin-top: 0.6em;\n\tflex: 1;\n\t-webkit-flex: 1;\n}\n\n.date_indicator > span,\n.session_indicator > span {\n\tfont-style: oblique;\n\tmargin: 0 1em;\n\tcolor: #919191;\n}\n\n.date_indicator + #mark,\n.session_indicator + #mark {\n\tdisplay: none;\n}\n\n/* NOTICE/CTCP/WALLOPS */\n\ndiv.line[data-line-type=\"ctcp\"],\ndiv.line[data-line-type=\"notice\"],\ndiv.line[data-line-type=\"wallops\"] {\n\tcolor: #f00;\n  \tz-index: 191;\n\tbackground: #400;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #811;\n\tborder-bottom: 1px solid #811;\n}\n\ndiv.line[data-line-type=\"notice\"] .sender {\n\tcolor: #f00;\n}\n\n/* PRIVMSG */\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"false\"] {\n \tpadding: 3px 5px 3px 5px;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-highlight=\"true\"],\ndiv.line[data-line-type=\"action\"][data-highlight=\"true\"] {\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #988C00;\n\tborder-bottom: 1px solid #988C00;\n  \tbackground-color: #362C00 !important;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"privmsg\"][data-member-type=\"myself\"] .message {\n\tcolor: #fff;\n}\n\ndiv.line[data-line-type=\"privmsg\"] .sender {\n\n}\n\n/* ACTION */\n\ndiv.line[data-line-type=\"action\"] {\n \tpadding: 3px 5px 3px 5px;\n}\n\ndiv.line[data-line-type=\"action\"] .message {\n\tcolor: #aaa;\n}\n\ndiv.line[data-line-type=\"action\"] .sender {\n\tcolor: #aaa;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-right: 0.4em;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:before {\n\tcontent: \"\\2022\";\n\tmargin-left: 0.4em;\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"action\"] .sender:after {\n\tcontent: \"\";\n  \t/* margin-left: 0.4em; */\n}\n\n/* DEBUG/INVITE */\n\ndiv.line[data-line-type=\"invite\"],\ndiv.line[data-line-type=\"debug\"],\ndiv.line[data-line-type=\"dcc-file-transfer\"],\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] {\n\tcolor: #777;\n  \tz-index: 190;\n\tbackground: #222;\n  \tposition: relative;\n \tpadding: 2px 5px 2px 5px;\n\tborder-top: 1px solid #444;\n\tborder-bottom: 1px solid #444;\n}\n\n/* off-the-record-encryption-status Message Event */\ndiv.line[data-line-type=\"off-the-record-encryption-status\"] .message {\n\tcolor: #ff0000;\n\tfont-weight: 700;\n}\n\n/* Message of the Day (MOTD) */\n/* 720, 721, 722 are used by ShadowIRCd for Oper MOTD. */\n/* 372, 375, 376 are normal MOTD shared by several IRCds. */\n\ndiv.line[data-command=\"372\"],\ndiv.line[data-command=\"721\"] {\n\tborder: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"375\"],\ndiv.line[data-command=\"720\"] { /* Start. */\n\tborder-bottom: none;\n\tpadding-top: 2px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"376\"],\ndiv.line[data-command=\"722\"] { /* End. */\n\tborder-top: none;\n\tpadding-top: 3px;\n\tpadding-bottom: 3px;\n}\n\ndiv.line[data-command=\"372\"] .message,\ndiv.line[data-command=\"375\"] .message,\ndiv.line[data-command=\"376\"] .message\ndiv.line[data-command=\"720\"] .message,\ndiv.line[data-command=\"721\"] .message,\ndiv.line[data-command=\"722\"] .message {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* GENERAL EVENT */\n\ndiv.line[data-line-type=\"join\"],\ndiv.line[data-line-type=\"part\"],\ndiv.line[data-line-type=\"kick\"],\ndiv.line[data-line-type=\"quit\"],\ndiv.line[data-line-type=\"kill\"],\ndiv.line[data-line-type=\"nick\"],\ndiv.line[data-line-type=\"mode\"],\ndiv.line[data-line-type=\"topic\"],\ndiv.line[data-line-type=\"website\"] {\n \tpadding: 3px 5px 3px 5px;\n\tcolor: #666;\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"ltr\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"ltr\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-right: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"join\"] .message:before {\n\tcontent: \"→\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"kick\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"part\"] .message:before,\nbody[dir=\"rtl\"] div.line[data-line-type=\"quit\"] .message:before {\n\tcontent: \"←\";\n  \tcolor: #e00;\n  \t/* margin-left: 0.4em; */\n}\n\nbody[dir=\"rtl\"] div.line[data-line-type=\"nick\"] .message:before {\n\tcontent:\"•\";\n  \tcolor: #0c0;\n  \t/* margin-left: 0.4em; */\n}\n\n/* Nickname Colors */\n\ndiv.line[data-line-type=\"privmsg\"] .sender[data-member-type=\"myself\"] {\n\tcolor: #ff6f6f;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/inlineMedia.css",
    "content": "\n/* Images */\n\n.inlineImage .content,\n.inlineVideo .content,\n.inlineVideoService .content,\n.inlineHTML .content {\n\tdisplay: inline-block;\n\tfloat: left;\n\tmargin-right: 12px;\n\tmargin-left: 10px;\n\tmin-width: 40px;\n\tmax-width: 90%;\n}\n\n.inlineImage .closeButton,\n.inlineVideo .closeButton,\n.inlineVideoService .closeButton,\n.inlineHTML .closeButton {\n\tcursor: pointer;\n\tborder-radius: 5px;\n\tborder: 2px solid #a1a1a1;\n\tcolor: #a1a1a1;\n\tdisplay: inline-block;\n\tline-height: 14px;\n\tfont-size: 15px;\n\tfont-family: \"Helvetica Neue\" !important;\n\ttext-indent: 7px;\n\twidth: 16px;\n\theight: 16px;\n\tfloat: left;\n\tpadding-right: 7px;\n\tpadding-left: 0px;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/scripts.js",
    "content": "/* Defined in: \"Textual.app -> Contents -> Resources -> JavaScript -> API -> core.js\" */\n\nTextual.viewBodyDidLoad = function()\n{\n\tTextual.fadeOutLoadingScreen(1.00, 0.95);\n}\n\nTextual.messageAddedToView = function(line, fromBuffer)\n{\n\tvar element = document.getElementById(\"line-\" + line);\n\n\tConversationTracking.updateNicknameWithNewMessage(element);\n}\n\nTextual.nicknameSingleClicked = function(e)\n{\n\tConversationTracking.nicknameSingleClickEventCallback(e);\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Bundled Styles/Total Sublime/settings.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Appearance</key>\n\t<string>dark</string>\n\t<key>Channel View Overlay Color</key>\n\t<string>#00000066</string>\n\t<key>Force Invert Sidebars</key>\n\t<true/>\n\t<key>Indentation Offset</key>\n\t<integer>0</integer>\n\t<key>Nickname Color Style</key>\n\t<string>HSL-dark</string>\n\t<key>Nickname Format</key>\n\t<string>%@%n:</string>\n\t<key>Template Engine Versions</key>\n\t<dict>\n\t\t<key>default</key>\n\t\t<integer>4</integer>\n\t</dict>\n\t<key>Underlying Window Color</key>\n\t<string>#000000</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/core.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\nvar Textual = {};\n\n/* *********************************************************************** */\n/*                              View Callbacks                             */\n/* *********************************************************************** */\n\n/*  Callbacks for each WebView in Textual. */\n\n/*  These callbacks are limited to the context of this view. The view can represent either\n    a server console, a channel, or a private message. See viewInitiated() for information\n    about determining which type of view this is. */\n\n/*  In the context of these callbacks, \"client\" or \"associated client\" is an abstract concept.\n    When you create a new connection in Textual, you set it up by entering where to connect to\n    and what your identity will be (nickname, username, etc.). You also choose channels to join.\n    You may configure it other ways as well. Client is an encapsulation of this.\n    Client is the stateful part of the connection that keeps track of everything. */\n\n/*\n    viewInitiated():\n\n    @viewType:      Type of view: Server console, channel, or private message.\n                    Possible values: \"server\", \"channel\", \"query\" — query = private message.\n    @clientHash:    A unique identifier for the client.\n    @viewHash:\t    A unique identifier for the view. null for server console (use clientHash for that).\n    @viewName:      Name of view: Channel name, nickname for a private message, or null for server console.\n*/\nTextual.viewInitiated \t\t\t\t\t= function(viewType, clientHash, viewHash, viewName) {};\n\nTextual.messageAddedToView \t\t\t\t= function(lineNumber, fromBuffer) {};\nTextual.messageRemovedFromView \t\t\t= function(lineNumber) {};\n\nTextual.historyIndicatorAddedToView\t\t\t= function() {};\nTextual.historyIndicatorRemovedFromView \t= function() {};\n\nTextual.topicBarValueChanged \t\t\t\t= function(newTopic) {};\n\nTextual.viewFinishedLoading \t\t\t\t\t= function() {};\nTextual.viewFinishedLoadingHistory\t\t\t\t= function() {};\nTextual.viewFinishedReload \t\t\t\t\t\t= function() {};\nTextual.viewFontSizeChanged\t\t\t\t\t\t= function(bigger) {};\nTextual.viewPositionMovedToBottom\t\t\t\t= function() {};\nTextual.viewPositionMovedToHistoryIndicator \t= function() {};\nTextual.viewPositionMovedToLine \t\t\t\t= function(lineNumber) {};\nTextual.viewPositionMovedToTop \t\t\t\t\t= function() {};\n\n/*  This function is called when one of two conditions are met:\n    1. The day has changed by reaching midnight (00:00)\n    2. The system clock changes\n\n    For the second condition, Textual does not make an effort\n    to compare if the day has in-fact changed. It merely passes\n    the change down to the style to let it know.  */\nTextual.dateChanged\t\t\t\t\t\t= function(dayYear, dayMonth, dayDay) {};\n\n/*  This function is not called by Textual itself, but by WebKit.\n    It is appended to <body> as the function to call during onload phase.\n    It is used by the newer templates to replace viewDidFinishLoading()\n    as the function responsible for fading out the loading screen. */\nTextual.viewBodyDidLoad\t\t\t\t\t= function() {};\n\n/* *********************************************************************** */\n/*\t\t\t\t\t\t         Appearance\t\t\t\t\t\t\t\t   */\n/* *********************************************************************** */\n\n/*  app.appearance() can be used to determine the current appearance of Textual.\n    The return value is a string. For example: \"light\" or \"dark\" */\n/*  Textual.appearanceDidChange() can be used to observe changes to the appearance. */\n// app.appearance(callbackFunction);\n\n/*  A boolean entry named \"Post Textual.appearanceDidChange() Notifications\" must\n    be added to the settings.plist file in order to enable use of this callback. */\n/*  A style that has a variety for each appearance type will never receive a callback.\n    Those styles will have the best variety automatically selected by Textual and the\n    style will be reloaded to refresh the view. */\nTextual.appearanceDidChange\t\t\t\t\t= function(changedTo) {};\n\n/* *********************************************************************** */\n/*                             Event Handling                              */\n/* *********************************************************************** */\n\n/*\n    handleEvent() allows a style to receive status information about\n    several actions going on behind the scenes. The following event\n    tokens are currently supported:\n\n    serverConnecting                - Connecting to IRC\n    serverConnected                 - Connected to IRC\n    serverDisconnecting             - Disconnecting from IRC\n    serverDisconnected              - Disconnected from IRC\n    channelJoined                   - Channel joined\n    channelParted                   — Channel parted\n    channelMemberAdded              — Member added to the channel (joined)\n    channelMemberRemoved            — Member removed from the channel (parted)\n    nicknameChanged\t\t\t\t\t— Nickname of local user (you) changed\n\n    THESE EVENTS ARE PUSHED WHEN THEY OCCUR. When a style is reloaded,\n    these events are not sent again. Use sessionStorage or some other\n    means to save them if they are important.\n*/\n\n/*  A boolean entry named \"Post Textual.handleEvent() Notifications\" must be\n    added to the settings.plist file in order to enable use of this callback. */\nTextual.handleEvent                            = function(eventToken) {};\n\n/* *********************************************************************** */\n/*\t\t\t\t\t\tApplication Object\t\t\t\t\t\t\t\t   */\n/* *********************************************************************** */\n\n/* \n    The \"app\" object provides a communication channel between the style and Textual.\n\n    Functions are performed asynchronously which means a callback function is required\n    to receive return values. If a callback function is required, then the callback\n    function should take one argument, which is a variable defining the return value.\n    The type of the return value will vary depending on what the function does.\n\n    Example:\n        app.inlineMediaEnabledForView(\n            function(returnValue) {\n                console.log(returnValue);\n            }\n        )\n*/\n\n/* \n    app.inlineMediaEnabledForView(callbackFunction)\n\n    Is inline media enabled?\n\n    Return: boolean\n*/\n\n/* \n    app.serverIsConnected(callbackFunction)\n\n    Is the client connected?\n\n    Return: boolean\n*/\n\n/* \n    app.channelIsActive(callbackFunction)\n\n    Is the channel or private message active?\n\n    For channel: \t\t\tIs the channel joined?\n    For private message: \tIs the user online?\n\n    Return: boolean\n*/\n\n/*\n    app.serverChannelCount(callbackFunction)\n\n    Number of channels associated with the client.\n\n    Notice: This number includes private messages.\n\n    Return: integer\n*/\n\n/*\n    app.channelName(callbackFunction)\n\t\n    Name of the channel, nickname for a private message, or null for server console.\n\n    Return: nullable string\n*/\n\n/* \n    app.networkName(callbackFunction)\n\n    Name of the network connected to.\n\n    User configurable connection name is returned if the client isn't connected.\n\n    Example: \"freenode IRC Network\" or \"My Connection\"\n\n    Return: string\n*/\n\n/*\n    app.serverAddress(callbackFunction)\n\n    Address of the server connected to.\n\n    User configurable server address is returned if the client isn't connected.\n\n    Example: \"chat.freenode.net\"\n\n    Return: string\n*/\n\n/*\n    app.localUserNickname(callbackFunction)\n\n    Nickname of the local user (you).\n\n    Return: string\n*/\n\n/* \n    app.localUserHostmask(callbackFunction)\n\t\n    Hostmask of the local user (you).\n\t\n    Notice: Hostmask is not available until at least one channel is joined.\n\t\n    Return: nullable string\n*/\n\n/* *********************************************************************** */\n/*\t                         Print Debug Messages                          */\n/* *********************************************************************** */\n\n// app.logToConsole(<input>)\t\t- Log a message to the macOS system-wide console.\n\n/*  The app.printDebugInformation* functions documented below also call messageAddedToView()\n    which means calling them from within it will create an infinite loop. */\n\n// app.printDebugInformationToConsole(message)\t\t— Show a debug message to the user in the server console.\n// app.printDebugInformation(message)\t\t\t\t— Show a debug message to the user in this view.\n\n/* *********************************************************************** */\n/*\t                            Style Settings                             */\n/* *********************************************************************** */\n\n/*\n    Textual provides styles the ability to store values within a key-value store\n    which is shared amongst all views. This store is saved in Textual's preference\n    file and will persist even if the style is renamed, removed, or replaced.\n\n    - Enabling:\n        A string entry named \"Key-value Store Name\" must be added to the\n        settings.plist file in order to enable use of this feature.\n\t\n        The value of this entry is the name to save the store under.\n\n        Preferably, this will be the name of the style, but a different name can\n        be entered so that multiple varieties of a style can share the same store.\n\n    - Notice:\n        • null (not undefined) is returned when a value does not exist for a key.\n        • To remove the value of a key from the store, set null as its value.\n */\n\n// app.styleSettingsRetrieveValue(key, callbackFunction)\t— Retrieve value of /key/ from the key-value store.\n// app.styleSettingsSetValue(key, value, callbackFunction)\t— Set /value/ to /key/ in the key-value store.\n\n/*  This function is performed when a style setting changed. It is performed on\n    all views, including the one that was responsible for changing the value. */\nTextual.styleSettingDidChange                       = function(changedKey) {};\n\n/* *********************************************************************** */\n/*                          Textual Preferences                            */\n/* *********************************************************************** */\n\n/*  A boolean entry named \"Post Textual.preferencesDidChange() Notifications\" must\n    be added to the settings.plist file in order to enable use of this callback. */\n/*  This callback is rate-limit at one call per-second, per-view. */\n/*  This callback exists for extremely specific use cases. In general, if you need\n    something that doesn't exist above, then it's better to ask for it to be added\n    and not rely on this callback. */\nTextual.preferencesDidChange\t\t\t= function() {};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/corePrivate.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* Private objects */\nvar _Textual = {};\n\n/* Resource management */\nTextual.initializeCore = function(resourcesPath)\n{\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/clickMenuSelection.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/documentBody.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/events.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/inlineMedia.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/messageBuffer.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/core/scrollTo.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/scroller/state.js\");\n\n\t/* Only load auto scroller if we believe this is WebKit2 */\n\tif (window.webkit && typeof window.webkit.messageHandlers === \"undefined\") {\n\t\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/scroller/automaticEmpty.js\");\n\t} else {\n\t\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/scroller/automatic.js\");\n\t}\n\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/conversationTracking.js\");\n\tTextual.includeScriptResourceFile(resourcesPath + \"/JavaScript/API/private/scriptSink.js\");\n};\n\nTextual.includeStyleResourceFile = function(file)\n{\n\tif (/loaded|complete/.test(document.readyState)) {\n\t\tvar newFile = document.createElement(\"link\");\n\n\t\tnewFile.charset = \"UTF-8\";\n\t\tnewFile.href = file;\n\t\tnewFile.media = \"screen\";\n\t\tnewFile.rel = \"stylesheet\";\n\t\tnewFile.type = \"text/css\";\n\n\t\tdocument.getElementsByTagName(\"HEAD\")[0].appendChild(newFile);\n\t} else {\n\t\tdocument.write('<link href=\"' + file + '\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />');\n\t}\n};\n\nTextual.includeScriptResourceFile = function(file)\n{\n\tif (/loaded|complete/.test(document.readyState)) {\n\t\tvar newFile = document.createElement(\"script\");\n\n\t\tnewFile.setAttribute(\"charset\", \"UTF-8\");\n\n\t\tnewFile.charset = \"UTF-8\";\n\t\tnewFile.src = file;\n\t\tnewFile.type = \"text/javascript\";\n\n\t\tdocument.getElementsByTagName(\"HEAD\")[0].appendChild(newFile);\n\t} else {\n\t\tdocument.write('<script type=\"text/javascript\" src=\"' + file + '\"></scr' + 'ipt>');\n\t}\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/conversationTracking.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nvar ConversationTracking = {};\n\n/* State tracking */\nConversationTracking.trackedNicknames = [];\n\n/* Core functions */\nConversationTracking.nicknameSingleClickEventCallback = function(senderElement)\n{\n\t/* This is called when .sender is clicked */\n\tvar nickname = senderElement.dataset.nickname;\n\n\t/* Toggle status for nickname */\n\tvar trackingIndex = ConversationTracking.trackedNicknames.indexOf(nickname);\n\n\tif (trackingIndex >= 0) {\n\t\tConversationTracking.trackedNicknames.splice(trackingIndex, 1);\n\t} else {\n\t\tConversationTracking.trackedNicknames.push(nickname);\n\t}\n\n\t/* Gather basic information */\n\tvar documentBody = Textual.documentBodyElement();\n\n\tvar plainTextLines = documentBody.querySelectorAll('div[data-line-type=\"privmsg\"], div[data-line-type=\"action\"]');\n\n\t/* Update all elements of the DOM matching conditions */\n\tfor (var i = 0; i < plainTextLines.length; i++) {\n\t\tvar lineSender = plainTextLines[i].querySelector(\".sender\");\n\n\t\tif (lineSender && lineSender.dataset.nickname === nickname) {\n\t\t\tConversationTracking.toggleSelectionStatusForSenderElement(lineSender);\n\t\t}\n\t}\n};\n\nConversationTracking.updateNicknameWithNewMessage = function(lineElement)\n{\n\tvar elementType = lineElement.dataset.lineType;\n\n\t/* We only want to target plain text messages */\n\tif (elementType !== \"privmsg\" &&\n\t\telementType !== \"action\" &&\n\t\telementType !== \"notice\") \n\t{\n\t\treturn;\n\t}\n\n\tvar senderElement = lineElement.querySelector(\".sender\");\n\n\tif (senderElement) {\n\t\t/* Is this a tracked nickname? */\n\t\tvar nickname = senderElement.dataset.nickname;\n\n\t\tif (ConversationTracking.isNicknameTracked(nickname) === false) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* Toggle status on for new message */\n\t\tConversationTracking.toggleSelectionStatusForSenderElement(senderElement);\n\t}\n};\n\nConversationTracking.toggleSelectionStatusForSenderElement = function(senderElement)\n{\n\tvar line = senderElement.lineContainer();\n\n\tline.classList.toggle(\"selectedUser\");\n};\n\n/* Helper functions */\nConversationTracking.isNicknameTracked = function(nickname)\n{\n\tif (ConversationTracking.trackedNicknames.indexOf(nickname) >= 0) {\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/clickMenuSelection.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* Selection */\nTextual.currentSelection = function() /* PUBLIC */\n{\n\treturn window.getSelection().toString();\n};\n\nTextual.clearSelection = function() /* PUBLIC */\n{\n\twindow.getSelection().empty();\n};\n\n_Textual.clearSelectionAndPreventDefault = function() /* PRIVATE */\n{\n\tTextual.clearSelection();\n\n\tevent.preventDefault();\n};\n\n_Textual.recordSelection = function() /* PRIVATE */\n{\n\tvar selectedText = Textual.currentSelection();\n\n\tappPrivate.setSelection(selectedText);\n};\n\n_Textual._selectionChangedCallback = function() /* PRIVATE */\n{\n\t_Textual.recordSelection();\n};\n\n_Textual.copySelectionOnMouseUpEvent = function() /* PRIVATE */\n{\n\tif (window.event.metaKey || window.event.altKey) {\n\t\treturn;\n\t}\n\n\tappPrivate.copySelectionWhenPermitted(\n\t   function(returnValue) {\n\t\t\tif (returnValue) {\n\t\t\t\tTextual.clearSelection();\n\t\t\t}\n\t   }\n\t);\n};\n\n_Textual._openGenericContextualMenu = function() /* PRIVATE */\n{\n\n};\n\nTextual.openChannelNameContextualMenu = function() /* PUBLIC */\n{\n\t_Textual.setPolicyChannelName();\n};\n\nTextual.openURLManagementContextualMenu = function() /* PUBLIC */\n{\n\t_Textual.setPolicyURLAddress();\n};\n\nTextual.openStandardNicknameContextualMenu = function() /* PUBLIC */\n{\n\t_Textual.setPolicyStandardNickname();\n};\n\nTextual.openInlineNicknameContextualMenu = function() /* PUBLIC */\n{\n\t_Textual.setPolicyInlineNickname();\n};\n\n_Textual.setPolicyStandardNickname = function() /* PRIVATE */\n{\n\tvar userNickname = event.target.dataset.nickname;\n\n\tappPrivate.setNickname(userNickname);\n};\n\n_Textual.setPolicyInlineNickname = function() /* PRIVATE */\n{\n\tvar userNickname = event.target.textContent;\n\n\tvar userMode = event.target.dataset.mode;\n\n\tif (userMode && userMode.length > 0 && userNickname.indexOf(userMode) === 0) {\n\t\tappPrivate.setNickname(userNickname.substring(1));\n\t} else {\n\t\tappPrivate.setNickname(userNickname);\n\t}\n};\n\n_Textual.setPolicyURLAddress = function() /* PRIVATE */\n{\n\tappPrivate.setURLAddress(event.target.getAttribute(\"href\"));\n};\n\n_Textual.setPolicyChannelName = function() /* PRIVATE */\n{\n\tappPrivate.setChannelName(event.target.textContent);\n};\n\n/* Double click actions */\nTextual._nicknameDoubleClickTimer = null;\n\nTextual.nicknameMaybeWasDoubleClicked = function(e) /* PUBLIC */\n{\n\tif (Textual._nicknameDoubleClickTimer) {\n\t\tclearTimeout(Textual._nicknameDoubleClickTimer);\n\n\t\tTextual._nicknameDoubleClickTimer = null;\n\n\t\tTextual.nicknameDoubleClicked(e);\n\t} else {\n\t\tTextual._nicknameDoubleClickTimer = setTimeout(function() {\n\t\t\tTextual._nicknameDoubleClickTimer = null;\n\n\t\t\tTextual.nicknameSingleClicked(e);\n\t\t}, 250);\n\t}\n};\n\nTextual.nicknameSingleClicked = function(e) /* PUBLIC */\n{\n\t// API does not handle this action by default...\n};\n\nTextual.channelNameDoubleClicked = function() /* PUBLIC */\n{\n\t_Textual.clearSelectionAndPreventDefault();\n\n\t_Textual.setPolicyChannelName();\n\n\tappPrivate.channelNameDoubleClicked();\n};\n\nTextual.nicknameDoubleClicked = function() /* PUBLIC */\n{\n\t_Textual.clearSelectionAndPreventDefault();\n\n\t_Textual.setPolicyStandardNickname();\n\n\tappPrivate.nicknameDoubleClicked();\n};\n\nTextual.inlineNicknameDoubleClicked = function() /* PUBLIC */\n{\n\t_Textual.clearSelectionAndPreventDefault();\n\n\t_Textual.setPolicyInlineNickname();\n\n\tappPrivate.nicknameDoubleClicked();\n};\n\n/* Bind to events */\ndocument.addEventListener(\"contextmenu\", _Textual._openGenericContextualMenu, false);\n\ndocument.addEventListener(\"selectionchange\", _Textual._selectionChangedCallback, false);\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/documentBody.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* Loading screen */\nTextual.loadingScreenElement = function() /* PUBLIC */\n{\n\treturn document.getElementById(\"loadingScreen\");\n};\n\nTextual.fadeOutLoadingScreen = function(bodyOp, topicOp) /* PUBLIC */\n{\n\tvar documentBody = Textual.documentBodyElement();\n\n\tvar topicBar = Textual.topicBarElement();\n\n\tvar loadingScreen = Textual.loadingScreenElement();\n\n\t/* Modify the opacity values of the various elements */\n\tloadingScreen.style.opacity = 0.00;\n\n\tdocumentBody.style.opacity = bodyOp;\n\n\tif (topicBar !== null) {\n\t\ttopicBar.style.opacity = topicOp;\n\t}\n\n\t/* The fade time for the loading screen depends on the CSS of the actual\n\tstyle, but there is no reason it should take more than five (5) seconds.\n\tWe will wait that amount of time before setting the overlay to hidden.\n\tSetting it to hidden makes it not copiable after it is not visible. */\n\tsetTimeout(function() {\n\t\tvar loadingScreen = Textual.loadingScreenElement();\n\n\t\tloadingScreen.style.display = \"none\";\n\t}, 5000);\n};\n\n/* Topic bar */\nTextual._topicBarElementReference = null; /* PRIVATE */\n\nTextual.topicBarElement = function() /* PUBLIC */\n{\n\tif (Textual._topicBarElementReference === null) {\n\t\tTextual._topicBarElementReference = document.getElementById(\"topicBar\");\n\t}\n\n\treturn Textual._topicBarElementReference;\n};\n\nTextual.topicBarValue = function(asText) /* PUBLIC */\n{\n\tvar topicBar = Textual.topicBarElement();\n\n\tif (topicBar) {\n\t\tif (typeof asText === 'undefined' || asText === true) {\n\t\t\treturn topicBar.textContent;\n\t\t} else {\n\t\t\treturn topicBar.innerHTML;\n\t\t}\n\t}\n\n\treturn null;\n};\n\nTextual.setTopicBarValue = function(topicValue, topicValueHTML) /* PUBLIC */\n{\n\tvar topicBar = Textual.topicBarElement();\n\n\tif (topicBar) {\n\t\ttopicBar.innerHTML = topicValueHTML;\n\n\t\tTextual.topicBarValueChanged(topicValue);\n\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\nTextual.setTopicBarVisible = function(isVisible) /* PUBLIC */\n{\n\tvar topicBar = Textual.topicBarElement();\n\n\tif (topicBar) {\n\t\tif (isVisible) {\n\t\t\ttopicBar.style.display = \"\";\n\t\t} else {\n\t\t\ttopicBar.style.display = \"none\";\n\t\t}\n\t}\n};\n\nTextual.topicBarDoubleClicked = function() /* PUBLIC */\n{\n\tappPrivate.topicBarDoubleClicked();\n};\n\n/* History indicator */\n_Textual.historyIndicatorAdd = function(templateHTML) /* PRIVATE */\n{\n\t_Textual.historyIndicatorRemove();\n\n\tMessageBuffer.bufferElementAppend(templateHTML);\n\n\tTextual.historyIndicatorAddedToView();\n};\n\n_Textual.historyIndicatorRemove = function() /* PRIVATE */\n{\n\tvar e = document.getElementById(\"mark\");\n\n\tif (e) {\n\t\te.remove();\n\n\t\tTextual.historyIndicatorRemovedFromView();\n\t}\n};\n\n/* Document body */\nTextual._documentBodyElementReference = null; /* PRIVATE */\n\nTextual.documentBodyElement = function() /* PUBLIC */\n{\n\tif (Textual._documentBodyElementReference === null) {\n\t\tTextual._documentBodyElementReference = document.getElementById(\"body\");\n\t}\n\n\treturn Textual._documentBodyElementReference;\n};\n\nTextual.documentHTML = function() /* PUBLIC */\n{\n\treturn document.documentElement.innerHTML;\n};\n\n/* History */\n_Textual.documentBodyAppendHistoric = function(templateHTML, lineNumbers, isReload) /* PRIVATE */\n{\n\tvar atBottom = TextualScroller.isScrolledToBottom();\n\n\tif (atBottom === false) {\n\t\tTextualScroller.saveRestorationFirstDataPoint();\n\t}\n\n\tMessageBuffer.bufferElementPrepend(templateHTML, lineNumbers);\n\n\tif (atBottom === false) {\n\t\tTextualScroller.saveRestorationSecondDataPoint();\n\n\t\tTextualScroller.restoreScrollPosition();\n\t}\n};\n\n/* Text */\nTextual.changeTextSizeMultiplier = function(sizeMultiplier) /* PUBLIC */\n{\n\tif (sizeMultiplier === 1.0) {\n\t\tdocument.body.style.fontSize = \"\";\n\t} else {\n\t\tdocument.body.style.fontSize = ((sizeMultiplier * 100.0) + \"%\");\n\t}\n};\n\n/* Line numbers */\nHTMLDocument.prototype.getElementByLineNumber = function(lineNumber)\n{\n\tlineNumber = lineNumber.standardizedLineNumber();\n\n\treturn document.getElementById(lineNumber);\n};\n\nString.prototype.standardizedLineNumber = function() /* PUBLIC */\n{\n\tif (this.indexOf(\"line-\") !== 0) {\n\t\treturn (\"line-\" + this);\n\t}\n\n\treturn this;\n};\n\nString.prototype.lineNumberContents = function(lineNumber) /* PUBLIC */\n{\n\tif (this.indexOf(\"line-\") === 0) {\n\t\treturn this.substr(5);\n\t}\n\n\treturn this;\n};\n\n/* Given an element, find which .line element contains it. */\nElement.prototype.lineContainer = function()\n{\n\tvar testElement = (function(element) {\n\t\tif (element.id && \n\t\t\telement.id.indexOf(\"line-\") === 0 &&\n\t\t\telement.classList &&\n\t\t\telement.classList.contains(\"line\")) \n\t\t{\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t});\n\n\tvar line = null; /* default value */\n\n\t/* Test this element and all its parents */\n\tvar currentElement = this;\n\n\tdo {\n\t\tline = testElement(currentElement);\n\n\t\tif (line) {\n\t\t\tbreak;\n\t\t}\n\t} while (currentElement = currentElement.parentElement);\n\n\t/* Returns the line container or null */\n\treturn line;\n};\n\nElement.prototype.lineNumberContents = function()\n{\n\tvar line = this.lineContainer();\n\n\tif (!line) {\n\t\treturn null;\n\t}\n\n\tvar lineNumber = line.id;\n\n\treturn lineNumber.lineNumberContents();\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/events.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nTextual.finishedLoadingView = false; /* PUBLIC */\nTextual.finishedLoadingHistory = false; /* PUBLIC */\n\n/* State management */\n_Textual.notifyDidBecomeVisible = function() /* PRIVATE */\n{\n\tTextual.clearSelection();\n\n\tdocument.body.dataset.visible = \"true\";\n};\n\n_Textual.notifyDidBecomeHidden = function() /* PRIVATE */\n{\n\tTextual.clearSelection();\n\n\tdocument.body.dataset.visible = false;\n};\n\n_Textual.notifySelectionChanged = function(isSelected) /* PRIVATE */\n{\n\t/* Changing this attribute may change the height of the body \n\tbecause of the disappearance and reappearance of the topic.\n\tIt is easiest for us to keep a record of where we were before\n\tchanging this attribute, then scroll to that. */\n\tvar scrolledToBottom = TextualScroller.isScrolledToBottom();\n\n\tif (isSelected) {\n\t\tdocument.body.dataset.selected = \"true\";\n\t} else {\n\t\tdocument.body.dataset.selected = \"false\";\n\t}\n\n\tif (scrolledToBottom) {\n\t\tTextualScroller.scrollToBottom();\n\t}\n};\n\nTextual.viewBodyDidLoadInt = function() /* PRIVATE */\n{\n\tconsole.warn(\"Textual.viewBodyDidLoadInt() is deprecated. Use _Textual.viewBodyDidLoad() instead.\");\n\n\t_Textual.viewBodyDidLoad();\n};\n\n_Textual._viewBodyDidLoadAnimationFrame = null; /* PRIVATE */\n\n_Textual.viewBodyDidLoad = function() /* PRIVATE */\n{\n\t/* Wait until element is available before binding to it. */\n\t_TextualScroller.bindToBestElement();\n\n\t/* On styles with a dark background, a white flash occurs because there is a very\n\t small delay between the view being created and the background process laying out\n\t its contents. To work around this, Textual presents an overlay view that matches\n\t the background color of the style. We then request an animation frame that calls\n\t app.finishedLayingOutView, instructing Textual that it can destroy the overlay view. */\n\n\tif (app.isWebKit2()) {\n\t\t_Textual._viewBodyDidLoadAnimationFrame =\n\t\twindow.requestAnimationFrame(function() {\n\t\t\t_Textual._viewBodyDidLoad();\n\t\t});\n\t} else {\n\t\t_Textual._viewBodyDidLoad();\n\t}\n};\n\n_Textual._viewBodyDidLoad = function() /* PRIVATE */\n{\n\t_Textual._viewBodyDidLoadAnimationFrame = null;\n\n\tappPrivate.finishedLayingOutView();\n\n\tTextual.viewBodyDidLoad();\n};\n\n_Textual.viewFinishedLoading = function(configuration) /* PRIVATE */\n{\n\tvar isSelected = configuration.selected;\n\tvar isVisible = configuration.visible;\n\tvar isReloadingTheme = configuration.reloadingTheme;\n\tvar textSizeMultiplier = configuration.textSizeMultiplier;\n\tvar scrollbackLimit = configuration.scrollbackLimit;\n\n\t_TextualScroller.createMutationObserver();\n\n\tif (isVisible) {\n\t\t_Textual.notifyDidBecomeVisible();\n\n\t\t_Textual.notifySelectionChanged(isSelected);\n\t} else {\n\t\t_Textual.notifyDidBecomeHidden();\n\t}\n\n\tif (isReloadingTheme) {\n\t\tTextual.viewFinishedReload();\n\t} else {\n\t\tTextual.viewFinishedLoading();\n\t}\n\n\t/* If this view is not visible to the user, then cancel the animation\n\t frame set by Textual.viewBodyDidLoadInt() because there is no use for it. */\n\tif (isVisible === false && isSelected === false) {\n\t\tif (_Textual._viewBodyDidLoadAnimationFrame) {\n\t\t\twindow.cancelAnimationFrame(_Textual._viewBodyDidLoadAnimationFrame);\n\n\t\t\t_Textual._viewBodyDidLoad();\n\t\t}\n\t}\n\n\tTextual.changeTextSizeMultiplier(textSizeMultiplier);\n\n\tif (scrollbackLimit !== 0) { // 0 = use default\n\t\t_MessageBuffer.setBufferLimit(scrollbackLimit);\n\t}\n};\n\n_Textual.viewFinishedLoadingHistory = function() /* PRIVATE */\n{\n\tTextual.finishedLoadingHistory = true;\n\n\tTextual.viewFinishedLoadingHistory();\n};\n\n_Textual.messageAddedToView = function(lineNumber, fromBuffer) /* PRIVATE */\n{\n\t/* Allow lineNumber to be an array of line numbers or a single line number. */\n\tif (Array.isArray(lineNumber)) {\n\t\tfor (var i = 0; i < lineNumber.length; i++) {\n\t\t\tTextual.messageAddedToView(lineNumber[i], fromBuffer);\n\t\t}\n\t} else {\n\t\tTextual.messageAddedToView(lineNumber, fromBuffer);\n\t}\n\n\tappPrivate.notifyLinesAddedToView(lineNumber);\n};\n\n_Textual.messageRemovedFromView = function(lineNumber) /* PRIVATE */\n{\n\t/* Allow lineNumber to be an array of line numbers or a single line number. */\n\tif (Array.isArray(lineNumber)) {\n\t\tfor (var i = 0; i < lineNumber.length; i++) {\n\t\t\tTextual.messageRemovedFromView(lineNumber[i]);\n\t\t}\n\t} else {\n\t\tTextual.messageRemovedFromView(lineNumber);\n\t}\n\n\tappPrivate.notifyLinesRemovedFromView(lineNumber);\n};\n\n/* Events */\n_Textual._mouseUpEventCallback = function() /* PRIVATE */\n{\n\t_Textual.copySelectionOnMouseUpEvent();\n};\n\n/* Bind to events */\ndocument.addEventListener(\"mouseup\", _Textual._mouseUpEventCallback, false);\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/inlineMedia.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* ************************************************** */\n/*              Document Prototypes                   */\n/* ************************************************** */\n\nHTMLDocument.prototype.getInlineMediaById = function(mediaId) /* PUBLIC */\n{\n\tif (mediaId.indexOf(\"inlineMedia-\") !== 0) {\n\t\tmediaId = (\"inlineMedia-\" + mediaId);\n\t}\n\n\treturn this.getElementById(mediaId);\n};\n\nHTMLDocument.prototype.getInlineMediaAnchorById = function(mediaId) /* PUBLIC */\n{\n\treturn document.body.querySelector(\"a[data-ilm-anchor=\\\"\" + mediaId + \"\\\"]\");\n};\n\n/* ************************************************** */\n/*                 Media Prototype                    */\n/* ************************************************** */\n\nvar InlineMediaPrototype = function() {\n\n};\n\nInlineMediaPrototype.prototype._isSubclass = function()\n{\n\treturn (Object.getPrototypeOf(this) !== InlineMediaPrototype.prototype);\n};\n\nInlineMediaPrototype.prototype.showOnClick = function(mediaId) /* PUBLIC */\n{\n\tthis.show(mediaId);\n\n\treturn false; // Do not perform navigation\n};\n\nInlineMediaPrototype.prototype.hideOnClick = function(mediaId) /* PUBLIC */\n{\n\tthis.hide(mediaId);\n\n\treturn false; // Do not perform navigation\n};\n\nInlineMediaPrototype.prototype.toggleOnClick = function(mediaId) /* PUBLIC */\n{\n\tif (this.isSafeToPerformToggle() === false) {\n\t\tconsole.log(\"Cancelled toggling inline media because of isSafeToPerformToggle() condition.\");\n\n\t\treturn true; // Perform navigation\n\t}\n\n\tthis.toggle(mediaId);\n\n\treturn false; // Do not perform navigation\n};\n\nInlineMediaPrototype.prototype.show = function(mediaId) /* PUBLIC */\n{\n\tthis.changeVisibility(mediaId, \"show\");\n};\n\nInlineMediaPrototype.prototype.hide = function(mediaId) /* PUBLIC */\n{\n\tthis.changeVisibility(mediaId, \"hide\");\n};\n\nInlineMediaPrototype.prototype.toggle = function(mediaId) /* PUBLIC */\n{\n\tthis.changeVisibility(mediaId, \"toggle\");\n};\n\nInlineMediaPrototype.prototype.changeVisibility = function(mediaId, display) /* PRIVATE */\n{\n\tvar mediaElement = document.getInlineMediaById(mediaId);\n\n\t/* Determine whether we will hide the media or show it */\n\tvar displayNone;\n\n\tif (display === \"hide\") {\n\t\tdisplayNone = true;\n\t} else if (display === \"show\") {\n\t\tdisplayNone = false;\n\t} else if (display === \"toggle\") {\n\t\tdisplayNone = (\tmediaElement && \n\t\t\t\t\t\tmediaElement.style.display !== \"none\");\n\t} else {\n\t\tthrow \"Invalid 'display' value\";\n\t}\n\n\t/* ********************************************* */\n\n\t/* The logic for each type of action is defined below as a\n\tself contained function. This makes it easier to maintain. */\n\n\t/* Remove media */\n\tvar _changeVisibilityByRemoving = (function()\n\t{\n\t\tif (this.willRemoveMedia(mediaId, mediaElement) === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tmediaElement.remove();\n\n\t\tthis.didRemoveMedia(mediaId);\n\t}).bind(this);\n\n\t/* Show media */\n\tvar _changeVisibilityByDisplaying = (function()\n\t{\n\t\tif (this.willShowMedia(mediaId, mediaElement) === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tmediaElement.style.display = \"\";\n\n\t\tthis.didShowMedia(mediaId, mediaElement);\n\t}).bind(this);\n\n\t/* Load media */\n\tvar _changeVisibilityByLoading = (function()\n\t{\n\t\tvar anchor = document.getInlineMediaAnchorById(mediaId);\n\n\t\tif (!anchor) {\n\t\t\tconsole.error(\"Failed to find inline media anchor that matches ID: \" + mediaId);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!anchor.dataset.ilmLoading) {\n\t\t\tanchor.dataset.ilmLoading = \"true\";\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.willLoadMedia(mediaId) === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar address = anchor.href;\n\n\t\tvar lineNumber = anchor.lineNumberContents();\n\n\t\tvar index = this.indexOfMediaAnchor(anchor);\n\n\t\tappPrivate.loadInlineMedia(address, mediaId, lineNumber, index);\n\t}).bind(this);\n\n\t/* ********************************************* */\n\n\tif (displayNone) \n\t{\n\t\t/* When hiding media, we remove it completely from the DOM. \n\t\tThe onclick event for toggling media will always exist in\n\t\tthe anchor which means the user can shift click that to load \n\t\tthe media again if they so choose. */\n\n\t\t_changeVisibilityByRemoving();\n\t}\n\telse if (mediaElement)\n\t{\n\t\t/* If the media already exists, then we have nothing\n\t\tto do here other than set the display property. */\n\n\t\t_changeVisibilityByDisplaying();\n\t}\n\telse \n\t{\n\t\t/* We aren't hiding the media and the media does not \n\t\talready exist in the DOM, which means we need to fire\n\t\toff a request to load it. */\n\n\t\t_changeVisibilityByLoading();\n\t}\n};\n\nInlineMediaPrototype.prototype.isSafeToPerformToggle = function() /* PUBLIC */\n{\n\t/* This logic is placed in a function to leave room for expansion. */\n\n\treturn (window.event.shiftKey === true);\n};\n\nInlineMediaPrototype.prototype.willLoadMedia = function(mediaId) /* PUBLIC */\n{\n\treturn true;\n};\n\nInlineMediaPrototype.prototype.didLoadMedia = function(mediaId, mediaElement)\n{\n\n};\n\nInlineMediaPrototype.prototype.didLoadMediaWithPayload = function(payload) /* PUBLIC */\n{\n\tvar mediaId = payload.uniqueIdentifier;\n\n\tthis._didLoadMediaModifyAnchor(mediaId);\n\n\tvar mediaElement = document.getInlineMediaById(mediaId);\n\n\tthis.didLoadMedia(mediaId, mediaElement);\n};\n\nInlineMediaPrototype.prototype._didLoadMediaModifyAnchor = function(mediaId) /* PRIVATE */\n{\n\tvar anchor = document.getInlineMediaAnchorById(mediaId);\n\n\tif (!anchor) {\n\t\tconsole.error(\"Failed to find inline media anchor that matches ID: \" + mediaId);\n\n\t\treturn;\n\t}\n\n\t/* Modify attributes */\n\tif (anchor.dataset.ilmLoading) {\n\t\tdelete anchor.dataset.ilmLoading;\n\t}\n\n\t/* Replace onclick event with one for current class */\n\tif (this._isSubclass()) {\n\t\tanchor.onclick = (function() {\n\t\t\treturn this.toggleOnClick(mediaId);\n\t\t}).bind(this);\n\t}\n};\n\nInlineMediaPrototype.prototype.willShowMedia = function(mediaId, mediaElement) /* PUBLIC */\n{\n\tmediaElement.prepareForMutation();\n\n\treturn true;\n};\n\nInlineMediaPrototype.prototype.didShowMedia = function(mediaId, mediaElement) /* PUBLIC */\n{\n\n};\n\nInlineMediaPrototype.prototype.willRemoveMedia = function(mediaId, mediaElement) /* PUBLIC */\n{\n\tmediaElement.prepareForMutation();\n\n\treturn true;\n};\n\nInlineMediaPrototype.prototype.didRemoveMedia = function(mediaId) /* PUBLIC */\n{\n\n};\n\nInlineMediaPrototype.prototype.entrypoint = function(payload, insertHTMLCallback)\n{\n\tdocument.prepareForMutation();\n\n\tinsertHTMLCallback(payload.html);\n};\n\nInlineMediaPrototype.prototype.indexOfMedia = function(mediaId)\n{\n\tvar anchor = document.getInlineMediaAnchorById(mediaId);\n\n\tif (!anchor) {\n\t\tconsole.error(\"Failed to find inline media anchor that matches ID: \" + mediaId);\n\n\t\treturn undefined;\n\t}\n\t\n\treturn this.indexOfMediaAnchor(anchor);\n};\n\nInlineMediaPrototype.prototype.indexOfMediaAnchor = function(anchor)\n{\n\tvar allAnchors = anchor.parentElement.getElementsByTagName(\"a\");\n\n\tvar index = Array.prototype.indexOf.call(allAnchors, anchor);\n\n\treturn index;\n};\n\n/* ************************************************** */\n/*                Media Public Interface              */\n/* ************************************************** */\n\nvar InlineMedia = Object.create(InlineMediaPrototype.prototype);\n\n/* ************************************************** */\n/*                Media Private Interface             */\n/* ************************************************** */\n\nvar _InlineMediaLoader = {};\n\n_InlineMediaLoader._loadedStyleResources = new Array(); /* PRIVATE */\n_InlineMediaLoader._loadedScriptResources = new Array(); /* PRIVATE */\n\n_InlineMediaLoader.processPayload = function(payload) /* PRIVATE */\n{\n\t/* Load CSS resources */\n\tvar styleResources = payload.styleResources;\n\n\tif (Array.isArray(styleResources)) {\n\t\tfor (var i = 0; i < styleResources.length; i++) {\n\t\t\tvar file = styleResources[i];\n\n\t\t\tif (_InlineMediaLoader._loadedStyleResources.indexOf(file) < 0) {\n\t\t\t\t_InlineMediaLoader._loadedStyleResources.push(file);\n\n\t\t\t\tTextual.includeStyleResourceFile(file);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Load JavaScript resources */\n\tvar scriptResources = payload.scriptResources;\n\n\tif (Array.isArray(scriptResources)) {\n\t\tfor (var i = 0; i < scriptResources.length; i++) {\n\t\t\tvar file = scriptResources[i];\n\n\t\t\tif (_InlineMediaLoader._loadedScriptResources.indexOf(file) < 0) {\n\t\t\t\t_InlineMediaLoader._loadedScriptResources.push(file);\n\n\t\t\t\tTextual.includeScriptResourceFile(file);\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Insert HTML */\n\tvar entrypoint = payload.entrypoint;\n\n\tif (typeof entrypoint === \"string\" && \n\t\tentrypoint.length > 0 &&\n\t\tentrypoint !== \"InlineMedia\") /* Don't allow module to use this */\n\t{\n\t\t_InlineMediaLoader.ppStep2WithEntrypoint(payload);\n\t} else {\n\t\t_InlineMediaLoader.ppStep2WithoutEntrypoint(payload);\n\t}\n};\n\n_InlineMediaLoader.ppStep2WithoutEntrypoint = function(payload) /* PRIVATE */\n{\n\t_InlineMediaLoader.ppStep3(InlineMedia, payload, null);\n};\n\n_InlineMediaLoader.ppStep2WithEntrypoint = function(payload) /* PRIVATE */\n{\n\tvar callToEntrypoint = (function(i) {\n\t\ttry {\n\t\t\tvar entrypoint = window[payload.entrypoint];\n\t\t} catch (error) {\n\n\t\t}\n\n\t\t/* If the entrypoint exists as an object already, \n\t\t then we call out to it and exit. */\n\t\tif (entrypoint && typeof entrypoint === \"object\") {\n\t\t\tentrypoint.entrypoint(\n\t\t\t\tpayload.entrypointPayload, \n\n\t\t\t\t(function(html) {\n\t\t\t\t\t_InlineMediaLoader.ppStep3(entrypoint, payload, html);\n\t\t\t\t})\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* If the entrypoint does not exist as an object yet,\n\t\t then we loop this function several times until it is\n\t\t one (script resource is loading), or until we exhaust\n\t\t the tries we are willing to take. */\n\t\tif (i === 100) { // 10 seconds\n\t\t\tconsole.error(\"Failed to process payload because entrypoint is not an object.\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tsetTimeout((function() {\n\t\t\tcallToEntrypoint(i + 1);\n\t\t}), 100); // ms\n\t});\n\n\tcallToEntrypoint(0);\n};\n\n_InlineMediaLoader.ppStep3 = function(entrypoint, payload, html) /* PRIVATE */\n{\n\t/* The entrypoint function for subclasses is expected\n\tto call prepareForMutation() when it thinks is best.\n\tWhen the entrypoint is InlineMedia, the entrypoint \n\tfunction is never called. We therefore call it here\n\twhen that is the entrypoint. */\n\tif (entrypoint === InlineMedia) {\n\t\tdocument.prepareForMutation();\n\t}\n\n\t/* Insert HTML */\n\t_InlineMediaLoader.insertPayload(payload, html);\n\n\t/* Inform delegate */\n\tentrypoint.didLoadMediaWithPayload(payload);\n};\n\n_InlineMediaLoader.insertPayload = function(payload, html) /* PRIVATE */\n{\n\tvar lineNumber = payload.lineNumber;\n\n\tvar line = document.getElementByLineNumber(lineNumber);\n\n\tif (!line) {\n\t\tconsole.error(\"Failed to find line that matches ID: \" + lineNumber);\n\n\t\treturn;\n\t}\n\n\tvar mediaContainer = line.querySelector(\".inlineMediaContainer\");\n\n\tif (!mediaContainer) {\n\t\tconsole.warning(\"The template for this style appears to be missing a span with the class\" +\n\t\t\t\t\t\t\"'inlineMediaContainer' — please fix this to support inline media.\");\n\n\t\treturn;\n\t}\n\n\t/* Validate HTML */\n\tif (html === null) {\n\t\thtml = payload.html;\n\t}\n\n\tif (html.length === 0) {\n\t\tconsole.error(\"HTML is empty\");\n\n\t\treturn;\n\t}\n\n\t/* Given index of this item, find item before that index\n\tto insert the HTML at, or insert at end of container. */\n\tvar index = payload.index;\n\n\tif (index === 0) {\n\t\t/* Insert at beginning */\n\t\tmediaContainer.insertAdjacentHTML(\"afterbegin\", html);\n\t} else {\n\t\tvar childIndex = (index - 1);\n\t\tvar childNode = null;\n\t\tvar childNodes = mediaContainer.children;\n\n\t\tif (childNodes.length > childIndex) {\n\t\t\tchildNode = childNodes[childIndex];\n\t\t}\n\n\t\tif (childNode) {\n\t\t\tchildNode.insertAdjacentHTML(\"afterend\", html);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Insert at end */\n\t\tmediaContainer.insertAdjacentHTML(\"beforeend\", html);\n\t}\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/messageBuffer.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nvar MessageBuffer = {};\nvar _MessageBuffer = {};\n\n/* ************************************************** */\n/*                   State Tracking                   */\n/* ************************************************** */\n\n/* The number of elements in the buffer. \nThis count only includes lines (messages). Not other\nitems that the style may insert into the buffer. */\n_MessageBuffer._bufferCurrentSize = 0; /* PRIVATE */\n\n/* When old messages are NOT being loaded, this \nis the number of elements we want to keep. */\n_MessageBuffer._bufferSizeSoftLimitDefault = 200; /* PRIVATE */\n_MessageBuffer._bufferSizeSoftLimit = _MessageBuffer._bufferSizeSoftLimitDefault; /* PRIVATE */\n\n/* When old messages are being loaded, this \nis the number of elements we want to keep. */\n_MessageBuffer._bufferSizeHardLimitDefault = 1000; /* PRIVATE */\n_MessageBuffer._bufferSizeHardLimit = _MessageBuffer._bufferSizeHardLimitDefault; /* PRIVATE */\n\n/* The number of lines to fetch when loading old messages.\nWhen old lines are fetched, the number of lines returned \nare also removed from the relevant buffer. */\n_MessageBuffer._loadMessagesBatchSize = 200; /* PRIVATE */\n\n/* _MessageBuffer._loadMessages() sets the following properties\nwhen it performs an action. These properties are not used for\nanything other than state tracking. If false, new messages are\nloaded, else the event is ignored. */\n/* The user can scroll downward while messages are still being\nloaded from scrolling upward. Therefore, we use a separate \nproperty to keep track of each type of load. */ \n_MessageBuffer._loadingMessagesBeforeLineDuringScroll = false; /* PRIVATE */\n_MessageBuffer._loadingMessagesAfterLineDuringScroll = false; /* PRIVATE */\n\n/* Set to true once we have loaded all old messages. */\n_MessageBuffer._bufferTopIsComplete = false; /* PRIVATE */\n_MessageBuffer._bufferBottomIsComplete = true; /* PRIVATE */\n\n/* _MessageBuffer._jumpToLine() sets the following property\nwhen it performs an action. */\n_MessageBuffer._loadingMessagesDuringJump = false; /* PRIVATE */\n\n/* ************************************************** */\n/*                  Line Management                   */\n/* ************************************************** */\n\nMessageBuffer.firstLineInBuffer = function(buffer) /* PUBLIC */\n{\n\tvar lines = buffer.querySelectorAll(\"div.line[id^='line-']\");\n\n\treturn lines[0];\n};\n\nMessageBuffer.lastLineInBuffer = function(buffer) /* PUBLIC */\n{\n\tvar lines = buffer.querySelectorAll(\"div.line[id^='line-']\");\n\n\treturn lines[(lines.length - 1)];\n};\n\n/* ************************************************** */\n/*                  Main Buffer                       */\n/* ************************************************** */\n\n_MessageBuffer._bufferElementReference = null; /* PRIVATE */\n\nMessageBuffer.bufferElement = function() /* PUBLIC */\n{\n\tif (_MessageBuffer._bufferElementReference === null) {\n\t\t_MessageBuffer._bufferElementReference = document.getElementById(\"messageBuffer\");\n\t}\n\n\treturn _MessageBuffer._bufferElementReference;\n};\n\nMessageBuffer.bufferElementPrepend = function(html, lineNumbers) /* PUBLIC */\n{\n\t_MessageBuffer.bufferElementInsert(\"afterbegin\", html, lineNumbers);\n};\n\nMessageBuffer.bufferElementAppend = function(html, lineNumbers) /* PUBLIC */\n{\n\t_MessageBuffer.bufferElementInsert(\"beforeend\", html, lineNumbers);\n};\n\n_MessageBuffer.bufferElementInsert = function(placement, html, lineNumbers) /* PRIVATE */\n{\n\t/* Do not append to bottom if bottom does not reflect\n\tthe most recent state of the buffer. */\n\tif (_MessageBuffer._bufferBottomIsComplete === false) {\n\t\treturn;\n\t}\n\n\tvar buffer = MessageBuffer.bufferElement();\n\n\tbuffer.prepareForMutation();\n\n\tbuffer.insertAdjacentHTML(placement, html);\n\n\tif (lineNumbers) {\n\t\t_MessageBuffer._bufferCurrentSize += lineNumbers.length;\n\n\t\t_MessageBuffer.resizeBufferIfNeeded();\n\n\t\ttry {\n\t\t\t_Textual.messageAddedToView(lineNumbers, false);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\t\t\t\n\t\t}\n\t}\n};\n\n/* ************************************************** */\n/*               Buffer Size Management               */\n/* ************************************************** */\n\nMessageBuffer.noteMessageRemovedFromBuffer = function()\n{\n\t_MessageBuffer._adjustCurrentBufferSize(-1);\n};\n\nMessageBuffer.noteMessagesRemovedFromBuffer = function(numberRemoved)\n{\n\t_MessageBuffer._adjustCurrentBufferSize(-1 * numberRemoved);\n};\n\n_MessageBuffer._adjustCurrentBufferSize = function(byHowMuch)\n{\n\tconsole.log(\"Adjusting buffer by: \" + byHowMuch);\n\t\n\tvar newSize = (_MessageBuffer._bufferCurrentSize + byHowMuch);\n\n\tif (newSize < 0) {\n\t\tnewSize = 0;\n\t} else if (newSize > _MessageBuffer._bufferSizeHardLimit) {\n\t\tnewSize = _MessageBuffer._bufferSizeHardLimit;\n\t}\n\n\t_MessageBuffer._bufferCurrentSize = newSize;\n\t\n\tconsole.log(\"Buffer adjusted to: \" + newSize);\n};\n\n/* Allow user to set a custom buffer limit */\n_MessageBuffer.setBufferLimit = function(limit) /* PRIVATE */\n{\n\tif (limit < 100 || limit > 50000) {\n\t\t_MessageBuffer._bufferSizeSoftLimit = _MessageBuffer._bufferSizeSoftLimitDefault;\n\t\t_MessageBuffer._bufferSizeHardLimit = _MessageBuffer._bufferSizeHardLimitDefault;\n\t} else {\n\t\t_MessageBuffer._bufferSizeSoftLimit = limit;\n\t\t_MessageBuffer._bufferSizeHardLimit = limit;\n\t}\n};\n\n/* Determine whether buffer should be resized depending on status. */\n_MessageBuffer.resizeBufferIfNeeded = function() /* PRIVATE */\n{\n\t/* We remove lines under the conditions:\n\t1. Size limit must be exceeded. \n\t2. When user is not scrolled, we remove from the top of the buffer.\n\t3. When user is scrolled below 50% of the scrollable area, then we\n\t   remove from the bottom of the buffer.\n\t4. When user is scrolled above 50% of the scrollable area, then we\n\t   remove form the top of the buffer. */\n\n\t/* Enforce soft limit for #2 */\n\tif (_MessageBuffer.scrolledToBottomOfBuffer()) {\n\t\t_MessageBuffer.enforceSoftLimit(true);\n\n\t\treturn;\n\t}\n\n\t/* Enforce hard limit for #3 and #4 */\n\tvar scrollPercent = TextualScroller.percentScrolled();\n\n\tvar removeFromTop = (scrollPercent > 50.0);\n\n\t_MessageBuffer.enforceHardLimit(removeFromTop);\n};\n\n/* Given number of lines added: enforce limit and remove from top or bottom. */\n_MessageBuffer.enforceSoftLimit = function(fromTop) /* PRIVATE */\n{\n\t_MessageBuffer.enforceLimit(_MessageBuffer._bufferSizeSoftLimit, fromTop);\n};\n\n_MessageBuffer.enforceHardLimit = function(fromTop) /* PRIVATE */\n{\n\t_MessageBuffer.enforceLimit(_MessageBuffer._bufferSizeHardLimit, fromTop);\n};\n\n_MessageBuffer.enforceLimit = function(limit, fromTop) /* PRIVATE */\n{\n\tvar numberToRemove = (_MessageBuffer._bufferCurrentSize - limit);\n\n\tif (numberToRemove <= 0) {\n\t\treturn;\n\t}\n\n\t_MessageBuffer.resizeBuffer(numberToRemove, fromTop);\n};\n\n_MessageBuffer.resizeBuffer = function(numberToRemove, fromTop) /* PRIVATE */\n{\n\tif (numberToRemove <= 0) {\n\t\tthrow \"Silly number to remove\";\n\t}\n\n\tvar lineNumbers = new Array();\n\n\tvar buffer = MessageBuffer.bufferElement();\n\n\tbuffer.prepareForMutation();\n\n\tvar numberRemoved = 0;\n\n\t/* To avoid an infinite loop by never having a \n\tfirstChild or lastChild that is a line, we use\n\tsiblings and break when there are none left. */\n\tvar currentElement = null;\n\tvar nextElement = null;\n\n\tdo {\n\t\tif (currentElement === null) {\n\t\t\tif (fromTop) {\n\t\t\t\tcurrentElement = buffer.firstChild;\n\t\t\t} else {\n\t\t\t\tcurrentElement = buffer.lastChild;\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentElement = nextElement;\n\t\t}\n\n\t\tif (currentElement === null) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (fromTop) {\n\t\t\tnextElement = currentElement.nextElementSibling;\n\t\t} else {\n\t\t\tnextElement = currentElement.previousElementSibling;\n\t\t}\n\n\t\tvar elementId = currentElement.id;\n\n\t\tif (elementId && elementId.indexOf(\"line-\") === 0) {\n\t\t\t/* We wait until the next line element before \n\t\t\texiting loop so that we can remove markers or\n\t\t\tanything related to lines that were removed. */\n\t\t\tif (numberRemoved >= numberToRemove) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlineNumbers.push(elementId);\n\n\t\t\tnumberRemoved += 1;\n\t\t}\n\n\t\tcurrentElement.remove();\n\t} while (true); // lol, I know.\n\n\tif (fromTop) {\n\t\t_MessageBuffer._bufferTopIsComplete = false;\n\t} else {\n\t\t_MessageBuffer._bufferBottomIsComplete = false;\n\t}\n\n\tvar lineNumbersCount = lineNumbers.length;\n\n\tif (lineNumbersCount > 0) {\n\t\t_MessageBuffer._bufferCurrentSize -= lineNumbersCount;\n\n\t\t_Textual.messageRemovedFromView(lineNumbers);\n\t}\n\n\tconsole.log(\"Removed \" + lineNumbersCount + \" lines from buffer\");\n};\n\n/* Timer set once user scrolls back to the bottom. */\n/* Timer is used in case user scrolls back up shortly after. */\n_MessageBuffer._bufferHardLimitResizeTimer = null; /* PRIVATE */\n\n_MessageBuffer.cancelHardLimitResize = function() /* PRIVATE */\n{\n\tif (_MessageBuffer._bufferHardLimitResizeTimer === null) {\n\t\treturn;\n\t}\n\n\tclearTimeout(_MessageBuffer._bufferHardLimitResizeTimer);\n\n\t_MessageBuffer._bufferHardLimitResizeTimer = null;\n};\n\n_MessageBuffer.scheduleHardLimitResize = function() /* PRIVATE */\n{\n\tif (_MessageBuffer._bufferHardLimitResizeTimer !== null) {\n\t\treturn;\n\t}\n\n\t/* Do not create timer if we are scrolling programmatically */\n\tif (_MessageBuffer._loadingMessagesDuringJump) {\n\t\treturn;\n\t}\n\n\t/* No need to create timer if we haven't exceeded hard limit. */\n\tif (_MessageBuffer._bufferCurrentSize <= _MessageBuffer._bufferSizeSoftLimit) {\n\t\treturn;\n\t}\n\n\t/* Do not create timer if we aren't at the true bottom. */\n\tif (_MessageBuffer.scrolledToBottomOfBuffer() === false) {\n\t\treturn;\n\t}\n\n\t/* Create timer */\n\t_MessageBuffer._bufferHardLimitResizeTimer =\n\tsetTimeout(function() {\n\t\tconsole.log(\"Buffer hard limit resize timer fired\");\n\n\t\tvar numberToRemove = (_MessageBuffer._bufferCurrentSize - _MessageBuffer._bufferSizeSoftLimit);\n\n\t\tif (numberToRemove <= 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t_MessageBuffer.resizeBuffer(numberToRemove, true);\n\n\t\t_MessageBuffer._bufferHardLimitResizeTimer = null;\n\t}, 5000);\n\n\tconsole.log(\"Buffer hard limit resize timer started\");\n};\n\n/* ************************************************** */\n/*                  Load Messages                     */\n/* ************************************************** */\n\n/* This function picks the best line to load old messages next to. */\n_MessageBuffer.loadMessagesDuringScroll = function(before) /* PRIVATE */\n{\n\t/* _MessageBuffer._loadMessages() is only called during scroll events by\n\tthe user. We keep track of a request is already active then so that we\n\tdo not keep sending them out while the user waits for one to finish. */\n\tif (_MessageBuffer._loadingMessagesDuringJump) {\n\t\tconsole.log(\"Cancelled request to load messages because another request is active\");\n\n\t\treturn;\n\t}\n\n\tif (before) \n\t{\n\t\tif (Textual.finishedLoadingHistory === false) {\n\t\t\tconsole.log(\"Cancelled request to load messages above line because history isn't loaded\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (_MessageBuffer._loadingMessagesBeforeLineDuringScroll) {\n\t\t\tconsole.log(\"Cancelled request to load messages above line because another request is active\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (_MessageBuffer._bufferTopIsComplete) {\n\t\t\tconsole.log(\"Cancelled request to load messages because there is nothing new to load\");\n\n\t\t\treturn;\n\t\t}\n\t}\n\telse // before\n\t{\n\t\tif (_MessageBuffer._loadingMessagesAfterLineDuringScroll) {\n\t\t\tconsole.log(\"Cancelled request to load messages below line because another request is active\");\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (_MessageBuffer._bufferBottomIsComplete) {\n\t\t\tconsole.log(\"Cancelled request to load messages because there is nothing new to load\");\n\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/* Find first line */\t\n\tvar buffer = MessageBuffer.bufferElement();\n\n\tvar line = null;\n\n\tif (before) {\n\t\tline = MessageBuffer.firstLineInBuffer(buffer);\n\t} else {\n\t\tline = MessageBuffer.lastLineInBuffer(buffer);\n\t}\n\n\t/* There is nothing in either buffer */\n\tif (line === null) {\n\t\tconsole.log(\"No line to load from\");\n\n\t\treturn;\n\t}\n\n\t/* Load messages */\n\tif (before) {\n\t\t_MessageBuffer._loadingMessagesBeforeLineDuringScroll = true;\n\t} else {\n\t\t_MessageBuffer._loadingMessagesAfterLineDuringScroll = true;\n\t}\n\n\tvar lineNumberContents = line.id.lineNumberContents();\n\n\t_MessageBuffer.loadMessagesDuringScrollWithPayload(\n\t\t{\n\t\t\t\"before\" : before,\n\t\t\t\"line\" : line,\n\t\t\t\"lineNumberContents\" : lineNumberContents\n\t\t}\n\t);\n};\n\n/* Given a line we want to load old messages next to, we do so. */\n_MessageBuffer.loadMessagesDuringScrollWithPayload = function(requestPayload) /* PRIVATE */\n{\n\tvar before = requestPayload.before;\n\tvar line = requestPayload.line;\n\tvar lineNumberContents = requestPayload.lineNumberContents;\n\n\t/* Define logic that will be performed when \n\tare are ready to load the messages. */\n\tvar loadMessagesLogic = (function() {\n\t\tvar postflightCallback = (function(renderedMessages) {\n\t\t\trequestPayload.renderedMessages = renderedMessages;\n\n\t\t\t_MessageBuffer.loadMessagesDuringScrollWithPayloadPostflight(requestPayload);\n\n\t\t\t_MessageBuffer.removeLoadingIndicator(line);\n\t\t});\n\n\t\tconsole.log(\"Loading messages before (\" + before  + \") line \" + lineNumberContents);\n\n\t\tif (before) {\n\t\t\tappPrivate.renderMessagesBefore(\n\t\t\t\tlineNumberContents, \n\t\t\t\t_MessageBuffer._loadMessagesBatchSize, \n\t\t\t\tpostflightCallback\n\t\t\t);\n\t\t} else {\n\t\t\tappPrivate.renderMessagesAfter(\n\t\t\t\tlineNumberContents, \n\t\t\t\t_MessageBuffer._loadMessagesBatchSize, \n\t\t\t\tpostflightCallback\n\t\t\t);\n\t\t}\n\t});\n\n\t/* Present loading indicator then trigger logic. */\n\t_MessageBuffer.addLoadingIndicator(before, line, loadMessagesLogic);\n};\n\n/* Postflight for loading old messages */\n_MessageBuffer.loadMessagesDuringScrollWithPayloadPostflight = function(requestPayload) /* PRIVATE */\n{\n\t/* Payload state */\n\tvar before = requestPayload.before;\n\tvar line = requestPayload.line;\n\tvar renderedMessages = requestPayload.renderedMessages;\n\n\tvar lineNumbers = null;\n\tvar html = null;\n\n\t/* Perform logging */\n\tvar renderedMessagesCount = renderedMessages.length;\n\n\tconsole.log(\"Request to load messages for \" + line.id + \" returned \" + renderedMessagesCount + \" results\");\n\n\tif (renderedMessagesCount > 0) {\n\t\t/* Array which will house every line number that was loaded. \n\t\tThe style needs this information so it can perform whatever action. */\n\t\tlineNumbers = new Array();\n\n\t\t/* Array which will house every segment of HTML to append. */\n\t\thtml = new Array();\n\n\t\t/* Process result */\n\t\tfor (var i = 0; i < renderedMessagesCount; i++) {\n\t\t\tvar renderedMessage = renderedMessages[i];\n\n\t\t\tvar lineNumber = renderedMessage.lineNumber;\n\n\t\t\tif (lineNumber) {\n\t\t\t\tlineNumbers.push(renderedMessage.lineNumber);\n\t\t\t}\n\n\t\t\thtml.push(renderedMessage.html);\n\t\t}\n\n\t\t/* Append HTML */\n\t\tvar htmlString = html.join(\"\");\n\n\t\tif (before) {\n\t\t\tline.prepareForMutation();\n\n\t\t\tline.insertAdjacentHTML('beforebegin', htmlString);\n\t\t} else {\n\t\t\tline.insertAdjacentHTML('afterend', htmlString);\n\t\t}\n\n\t\t_MessageBuffer._bufferCurrentSize += lineNumbers.length;\n\t} // renderedMessagesCount > 0\n\n\t/* If the number of results is less than our batch size,\n\tthen we can probably make a best guess that we have loaded\n\tall the old messages that are available. */\n\tif (renderedMessagesCount < _MessageBuffer._loadMessagesBatchSize) {\n\t\tif (before) {\n\t\t\t_MessageBuffer._bufferTopIsComplete = true;\n\t\t} else {\n\t\t\t_MessageBuffer._bufferBottomIsComplete = true;\n\t\t}\n\t}\n\n\tif (renderedMessagesCount > 0) {\n\t\t/* Enforce size limit. This function expects the count to already be \n\t\tincremented which is why we call it AFTER the append. */\n\t\t/* Value of before is reversed because we want to remove from the\n\t\topposite of where we added. */\n\t\t_MessageBuffer.enforceHardLimit(!before);\n\n\t\t/* Cancel any mutations already queued so that we don't scroll. */\n\t\t/* Place after resizeBuffer() because that triggers a mutation. */\n\t\tline.cancelMutation();\n\n\t\t/* Post line numbers so style can do something with them. */\n\t\ttry {\n\t\t\t_Textual.messageAddedToView(lineNumbers, true);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\t\t\t\n\t\t}\n\n\t\t/* Scroll line into view */\n\t\tif (before) {\n\t\t\tline.scrollIntoViewAlignTop();\n\t\t} else {\n\t\t\tline.scrollIntoViewAlignBottom();\n\t\t}\n\t} // renderedMessagesCount > 0\n\n\t/* Toggle automatic scrolling */\n\t/* Call after resize so that it has latest state of bottom. */\n\t_MessageBuffer.toggleAutomaticScrolling();\n\n\t/* Flush state */\n\tif (before) {\n\t\t_MessageBuffer._loadingMessagesBeforeLineDuringScroll = false;\n\t} else {\n\t\t_MessageBuffer._loadingMessagesAfterLineDuringScroll = false;\n\t}\n};\n\n_MessageBuffer.loadMessagesWithJump = function(lineNumber, callbackFunction) /* PRIVATE */\n{\n\t/* Safety checks */\n\tif (_MessageBuffer._loadingMessagesDuringJump) {\n\t\tconsole.log(\"Cancelled request to load messages because another request is active\");\n\n\t\treturn;\n\t}\n\n\tif (Textual.finishedLoadingHistory === false) {\n\t\tconsole.log(\"Cancelled request to load messages because history isn't loaded\");\n\n\t\treturn;\n\t}\n\n\tif (_MessageBuffer._loadingMessagesBeforeLineDuringScroll ||\n\t\t_MessageBuffer._loadingMessagesAfterLineDuringScroll) \n\t{\n\t\tconsole.log(\"Cancelled request to load messages because another request is active\");\n\n\t\treturn;\n\t}\n\n\tif (_MessageBuffer._bufferTopIsComplete &&\n\t\t_MessageBuffer._bufferBottomIsComplete) \n\t{\n\t\tconsole.log(\"Cancelled request to load messages because there is nothing new to load\");\n\n\t\treturn;\n\t}\n\n\t/* This function may be called without scrolling which means we\n\tshould cancel the resize timer. */\n\t_MessageBuffer.cancelHardLimitResize();\n\n\t/* The line does not exist in the buffer, which means we have to \n\tload it. When we load the message, we also load X number of messages\n\tabove it and X number of messages below it. */\n\t/* When jumping, we do not use the message buffer loading indicator\n\tbecause the user does not require a visual indicator. */\n\t_MessageBuffer._loadingMessagesDuringJump = true;\n\n\tvar lineNumberContents = lineNumber.lineNumberContents();\n\n\tvar requestPayload = {\n\t\t\"lineNumberContents\" : lineNumberContents,\n\t\t\"lineNumberStandardized\" : lineNumber,\n\t\t\"callbackFunction\" : callbackFunction\n\t};\n\n\tconsole.log(\"Loading line \" + lineNumberContents);\n\n\tappPrivate.renderMessageWithSiblings(\n\t\tlineNumberContents,\n\n\t\t_MessageBuffer._loadMessagesBatchSize, // load X above\n\t\t_MessageBuffer._loadMessagesBatchSize, // load X below\n\n\t\t(function(renderedMessages) {\n\t\t\trequestPayload.renderedMessages = renderedMessages;\n\n\t\t\t_MessageBuffer.loadMessagesWithJumpPostflight(requestPayload);\n\t\t})\n\t);\n};\n\n_MessageBuffer.loadMessagesWithJumpPostflight = function(requestPayload) /* PRIVATE */\n{\n\t/* Payload state */\n\tvar callbackFunction = requestPayload.callbackFunction;\n\tvar lineNumberContents = requestPayload.lineNumberContents;\n\tvar lineNumberStandardized = requestPayload.lineNumberStandardized;\n\tvar renderedMessages = requestPayload.renderedMessages;\n\n\tvar lineNumbers = null;\n\tvar html = null;\n\n\t/* Perform logging */\n\tvar renderedMessagesCount = renderedMessages.length;\n\n\tconsole.log(\"Request to load messages for \" + lineNumberContents + \" returned \" + renderedMessagesCount + \" results\");\n\n\tif (renderedMessagesCount > 0) {\n\t\t/* Array which will house every line number that was loaded. \n\t\tThe style needs this information so it can perform whatever action. */\n\t\tlineNumbers = new Array();\n\n\t\t/* Array which will house every segment of HTML to append. */\n\t\thtml = new Array();\n\n\t\t/* Process result */\n\t\tfor (var i = 0; i < renderedMessagesCount; i++) {\n\t\t\tvar renderedMessage = renderedMessages[i];\n\n\t\t\tvar lineNumber = renderedMessage.lineNumber;\n\n\t\t\tif (lineNumber) {\n\t\t\t\tlineNumbers.push(renderedMessage.lineNumber);\n\t\t\t}\n\n\t\t\thtml.push(renderedMessage.html);\n\t\t}\n\n\t\t/* When we jump to a line that is not visible, we replace \n\t\tthe entire buffer with the rendered messages. This avoids \n\t\tthe hassle of having to navigate the DOM merging lines. \n\t\tThis may change in the future based on user feedback,\n\t\tbut for now this is acceptable. */\n\n\t\t/* Append HTML */\n\t\tvar htmlString = html.join(\"\");\n\n\t\tvar buffer = MessageBuffer.bufferElement();\n\n\t\tbuffer.insertAdjacentHTML('afterbegin', htmlString);\n\n\t\t/* Resize the buffer by removing messages from the bottom\n\t\tso that the only lines that remain are those appended. */\n\t\t_MessageBuffer.resizeBuffer(_MessageBuffer._bufferCurrentSize, false);\n\n\t\t/* Cancel any mutations already queued so that we don't scroll. */\n\t\t/* Place after resizeBuffer() because that triggers a mutation. */\n\t\tbuffer.cancelMutation();\n\n\t\t/* Update buffer size to include appended lines. */\n\t\t_MessageBuffer._bufferCurrentSize += lineNumbers.length;\n\n\t\t/* Post line numbers so style can do something with them. */\n\t\ttry {\n\t\t\t_Textual.messageAddedToView(lineNumbers, true);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\t\t\t\n\t\t}\n\n\t\t/* Toggle automatic scrolling */\n\t\t/* Call after resize so that it has latest state of bottom. */\n\t\t_MessageBuffer.toggleAutomaticScrolling();\n\t} // renderedMessagesCount > 0\n\n\t/* Try jumping to line and inform callback of result. */\n\tcallbackFunction( \n\t\tTextual.scrollToElement(lineNumberStandardized) \n\t);\n\n\t/* Flush state */\n\t_MessageBuffer._loadingMessagesDuringJump = false;\n};\n\n/* ************************************************** */\n/*                Loading Indicator                   */\n/* ************************************************** */\n\n_MessageBuffer.addLoadingIndicator = function(before, toLine, callbackFunction) /* PRIVATE */\n{\n\tcallbackFunction();\n};\n\n_MessageBuffer.removeLoadingIndicator = function(fromLine) /* PRIVATE */\n{\n\n};\n\n/* ************************************************** */\n/*                  Scrolling                         */\n/* ************************************************** */\n\n/* Scrolling */\n_MessageBuffer._documentScrolledCallback = function(scrolledUpward) /* PRIVATE */\n{\n\tif (scrolledUpward) {\n\t\tif (TextualScroller.isScrolledToTop()) {\n\t\t\t_MessageBuffer.loadMessagesDuringScroll(true);\n\t\t}\n\n\t\t_MessageBuffer.cancelHardLimitResize();\n\t}\n\n\tif (scrolledUpward === false && TextualScroller.isScrolledToBottom()) {\n\t\t_MessageBuffer.loadMessagesDuringScroll(false);\n\n\t\t_MessageBuffer.scheduleHardLimitResize();\n\t}\n};\n\n_MessageBuffer._documentScrolledUpwardCallback = function() /* PRIVATE */\n{\n\t_MessageBuffer._documentScrolledCallback(true);\n};\n\n_MessageBuffer._documentScrolledDownwardCallback = function() /* PRIVATE */\n{\n\t_MessageBuffer._documentScrolledCallback(false);\n};\n\n_MessageBuffer._automaticScrollingEnabled = true; /* PRIVATE */\n\n_MessageBuffer.toggleAutomaticScrollingOn = function(turnOn) /* PRIVATE */\n{\n\tif (_MessageBuffer._automaticScrollingEnabled !== turnOn) {\n\t\t_MessageBuffer._automaticScrollingEnabled = turnOn;\n\t} else {\n\t\treturn;\n\t}\n\n\tif (turnOn) {\n\t\tappPrivate.setAutomaticScrollingEnabled(true);\n\t} else {\n\t\tappPrivate.setAutomaticScrollingEnabled(false);\n\t}\n};\n\n_MessageBuffer.toggleAutomaticScrolling = function() /* PRIVATE */\n{\n\t_MessageBuffer.toggleAutomaticScrollingOn(_MessageBuffer._bufferBottomIsComplete);\n};\n\n_MessageBuffer.scrolledToBottomOfBuffer = function() /* PRIVATE */\n{\n\treturn (_MessageBuffer._bufferBottomIsComplete &&\n\t\t\tTextualScroller.isScrolledToBottom());\n};\n\nMessageBuffer.jumpToLine = function(lineNumber, callbackFunction) /* PUBLIC */\n{\n\tvar lineNumberStandardized = lineNumber.standardizedLineNumber();\n\n\tif (Textual.scrollToElement(lineNumberStandardized)) {\n\t\tcallbackFunction(true);\n\n\t\treturn;\n\t}\n\n\t_MessageBuffer.loadMessagesWithJump(lineNumberStandardized, callbackFunction);\n};\n\n/* Bind to events */\ndocument.addEventListener(\"scrolledUpward\", _MessageBuffer._documentScrolledUpwardCallback, false);\ndocument.addEventListener(\"scrolledDownward\", _MessageBuffer._documentScrolledDownwardCallback, false);\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/core/scrollTo.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* Scrolling */\nTextual.scrollToBottomOfView = function(fireNotification) /* PUBLIC */\n{\n\tTextualScroller.scrollToBottom();\n\n\tif (fireNotification) {\n\t\tTextual.viewPositionMovedToBottom();\n\t}\n};\n\nTextual.scrollToTopOfView = function(fireNotification) /* PUBLIC */\n{\n\tTextualScroller.scrollToTop();\n\n\tif (fireNotification) {\n\t\tTextual.viewPositionMovedToTop();\n\t}\n};\n\nTextual.scrollToLine = function(lineNumber) /* PUBLIC */\n{\n\tTextual.jumpToLine(lineNumber);\n};\n\nTextual.jumpToLine = function(lineNumber) /* PUBLIC */\n{\n\tMessageBuffer.jumpToLine(\n\t\tlineNumber, \n\n\t\t(function(success) {\n\t\t\tvar scrolledToBottom = false;\n\n\t\t\tif (success) {\n\t\t\t\tscrolledToBottom = TextualScroller.isScrolledToBottom();\n\n\t\t\t\tTextual.viewPositionMovedToLine(lineNumber);\n\t\t\t}\n\n\t\t\tappPrivate.notifyJumpToLineCallback(lineNumber, success, scrolledToBottom);\n\t\t})\n\t);\n};\n\nTextual.scrollToElement = function(elementName) /* PUBLIC */\n{\n\tvar element = document.getElementById(elementName);\n\n\tif (element) {\n\t\tTextualScroller.scrollElementToCenter(element);\n\n\t\treturn true;\n\t}\n\n\treturn false;\n};\n\nTextual.scrollToHistoryIndicator = function() /* PUBLIC */\n{\n\tif (Textual.scrollToElement(\"mark\")) {\n\t\tTextual.viewPositionModToHistoryIndicator();\n\t}\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/scriptSink.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */ \n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nvar app = {};\nvar appInternal = {};\nvar appPrivate = {};\n\n/* ************************************************** */\n/*                   Internal                         */\n/* ************************************************** */\n\nappInternal.promiseIndex = 1;\nappInternal.promisedCallbacks = {};\n\nappInternal.promiseKept = function(promiseIndex, returnValue)\n{\n\t/* Check to see if an array entry exists for given index. */\n\tvar callbackFunction = appInternal.promisedCallbacks[promiseIndex];\n\n\t/* If an array entry did exist, then perform it as a function. */\n\tif (typeof callbackFunction !== \"undefined\") {\n\t\tcallbackFunction(returnValue);\n\n\t\tdelete appInternal.promisedCallbacks[promiseIndex];\n\t}\n};\n\nappInternal.makePromise = function(callbackFunction)\n{\n\t/* Best to be safe about the data we take in. */\n\tif (appInternal.isValidCallbackFunction(callbackFunction) === false) {\n\t\tthrow \"Invalid callback function\";\n\t}\n\n\t/* Insert the promise then return its index (count minus one) */\n\tvar promiseIndex = appInternal.promiseIndex;\n\n\tappInternal.promiseIndex += 1;\n\tappInternal.promisedCallbacks[promiseIndex] = callbackFunction;\n\n\treturn promiseIndex;\n};\n\nappInternal.isValidCallbackFunction = function(callbackFunction)\n{\n\tif (callbackFunction && typeof callbackFunction === \"function\") {\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n};\n\n/* ************************************************** */\n/*                   Private                          */\n/* ************************************************** */\n\nappPrivate.finishedLayingOutView = function()\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.finishedLayingOutView.postMessage(null);\n\t} else {\n\t\tTextualScriptSink.finishedLayingOutView();\n\t}\n};\n\nappPrivate.setAutomaticScrollingEnabled = function(enabled)\n{\n\tif (app.isWebKit2()) {\n\t\tTextualScroller.setAutomaticScrollingEnabled(enabled);\n\t} else {\n\t\tTextualScriptSink.setAutomaticScrollingEnabled(enabled);\n\t}\n};\n\nappPrivate.setURLAddress = function(object)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.setURLAddress.postMessage(object);\n\t} else {\n\t\tTextualScriptSink.setURLAddress(object);\n\t}\n};\n\nappPrivate.setSelection = function(object)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.setSelection.postMessage(object);\n\t} else {\n\t\tTextualScriptSink.setSelection(object);\n\t}\n};\n\nappPrivate.setChannelName = function(object)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.setChannelName.postMessage(object);\n\t} else {\n\t\tTextualScriptSink.setChannelName(object);\n\t}\n};\n\nappPrivate.setNickname = function(object)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.setNickname.postMessage(object);\n\t} else {\n\t\tTextualScriptSink.setNickname(object);\n\t}\n};\n\nappPrivate.channelNameDoubleClicked = function()\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.channelNameDoubleClicked.postMessage(null);\n\t} else {\n\t\tTextualScriptSink.channelNameDoubleClicked();\n\t}\n};\n\nappPrivate.nicknameDoubleClicked = function()\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.nicknameDoubleClicked.postMessage(null);\n\t} else {\n\t\tTextualScriptSink.nicknameDoubleClicked();\n\t}\n};\n\nappPrivate.topicBarDoubleClicked = function()\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.topicBarDoubleClicked.postMessage(null);\n\t} else {\n\t\tTextualScriptSink.topicBarDoubleClicked();\n\t}\n};\n\nappPrivate.copySelectionWhenPermitted = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.copySelectionWhenPermitted.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.copySelectionWhenPermitted(dataValue);\n\t}\n};\n\nappPrivate.displayContextMenu = function()\n{\n\twindow.webkit.messageHandlers.displayContextMenu.postMessage(null);\n};\n\nappPrivate.renderMessagesBefore = function(lineNumber, maximumNumberOfLines, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [lineNumber, maximumNumberOfLines]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.renderMessagesBefore.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.renderMessagesBefore(dataValue);\n\t}\n};\n\nappPrivate.renderMessagesAfter = function(lineNumber, maximumNumberOfLines, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [lineNumber, maximumNumberOfLines]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.renderMessagesAfter.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.renderMessagesAfter(dataValue);\n\t}\n};\n\nappPrivate.renderMessagesInRange = function(lineNumberAfter, lineNumberBefore, maximumNumberOfLines, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [lineNumberAfter, lineNumberBefore, maximumNumberOfLines]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.renderMessagesInRange.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.renderMessagesInRange(dataValue);\n\t}\n};\n\nappPrivate.renderMessageWithSiblings = function(lineNumber, numberOfLinesBefore, numberOfLinesAfter, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [lineNumber, numberOfLinesBefore, numberOfLinesAfter]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.renderMessageWithSiblings.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.renderMessageWithSiblings(dataValue);\n\t}\n};\n\nappPrivate.renderTemplate = function(templateName, templateAttributes, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [templateName, templateAttributes]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.renderTemplate.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.renderTemplate(dataValue);\n\t}\n};\n\nappPrivate.notifyJumpToLineCallback = function(lineNumber, successful, scrolledToBottom)\n{\n\tvar dataValue = {\"values\" : [lineNumber, successful, scrolledToBottom]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.notifyJumpToLineCallback.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.notifyJumpToLineCallback(dataValue);\n\t}\n};\n\nappPrivate.notifyLinesAddedToView = function(lineNumbers)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.notifyLinesAddedToView.postMessage(lineNumbers);\n\t} else {\n\t\tTextualScriptSink.notifyLinesAddedToView(lineNumbers);\n\t}\n};\n\nappPrivate.notifyLinesRemovedFromView = function(lineNumbers)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.notifyLinesRemovedFromView.postMessage(lineNumbers);\n\t} else {\n\t\tTextualScriptSink.notifyLinesRemovedFromView(lineNumbers);\n\t}\n};\n\nappPrivate.loadInlineMedia = function(address, uniqueIdentifier, lineNumber, index)\n{\n\tvar dataValue = {\"values\" : [address, uniqueIdentifier, lineNumber, index]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.loadInlineMedia.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.loadInlineMedia(dataValue);\n\t}\n};\n\nappPrivate.encryptionAuthenticateUser = function()\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.encryptionAuthenticateUser.postMessage(null);\n\t} else {\n\t\tTextualScriptSink.encryptionAuthenticateUser();\n\t}\n};\n\n/* ************************************************** */\n/*                   Public                           */\n/* ************************************************** */\n\napp.isWebKit2 = function()\n{\n\tif (window.webkit && typeof window.webkit.messageHandlers !== \"undefined\") {\n\t\treturn true;\n\t} else {\n\t\treturn false;\n\t}\n};\n\napp.channelMemberCount = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.channelMemberCount.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.channelMemberCount(dataValue);\n\t}\n};\n\napp.serverChannelCount = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.serverChannelCount.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.serverChannelCount(dataValue);\n\t}\n};\n\napp.serverIsConnected = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.serverIsConnected.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.serverIsConnected(dataValue);\n\t}\n};\n\napp.channelIsActive = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.channelIsActive.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.channelIsActive(dataValue);\n\t}\n};\n\napp.channelIsJoined = function(callbackFunction)\n{\n\tconsole.warn(\"app.channelIsJoined() is deprecated. Use app.channelIsActive() instead.\");\n\n\tapp.channelIsActive(callbackFunction);\n};\n\napp.channelName = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.channelName.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.channelName(dataValue);\n\t}\n};\n\napp.serverAddress = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.serverAddress.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.serverAddress(dataValue);\n\t}\n};\n\napp.networkName = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.networkName.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.networkName(dataValue);\n\t}\n};\n\napp.localUserNickname = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.localUserNickname.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.localUserNickname(dataValue);\n\t}\n};\n\napp.localUserHostmask = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.localUserHostmask.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.localUserHostmask(dataValue);\n\t}\n};\n\napp.logToConsole = function(message)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.logToConsole.postMessage(message);\n\t} else {\n\t\tTextualScriptSink.logToConsole(message);\n\t}\n};\n\napp.printDebugInformationToConsole = function(message)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.printDebugInformationToConsole.postMessage(message);\n\t} else {\n\t\tTextualScriptSink.printDebugInformationToConsole(message);\n\t}\n};\n\napp.printDebugInformation = function(message)\n{\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.printDebugInformation.postMessage(message);\n\t} else {\n\t\tTextualScriptSink.printDebugInformation(message);\n\t}\n};\n\napp.inlineMediaEnabledForView = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.inlineMediaEnabledForView.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.inlineMediaEnabledForView(dataValue);\n\t}\n};\n\napp.sidebarInversionIsEnabled = function(callbackFunction)\n{\n\tconsole.warn(\"app.sidebarInversionIsEnabled() is deprecated. Use app.appearance() instead.\");\n\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.sidebarInversionIsEnabled.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.sidebarInversionIsEnabled(dataValue);\n\t}\n};\n\napp.appearance = function(callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.appearance.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.appearance(dataValue);\n\t}\n};\n\napp.nicknameColorStyleHash = function(nickname, nicknameColorStyle, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [nickname, nicknameColorStyle]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.nicknameColorStyleHash.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.nicknameColorStyleHash(dataValue);\n\t}\n};\n\napp.sendPluginPayload = function(payloadLabel, payloadContent)\n{\n\tvar dataValue = {\"values\" : [payloadLabel, payloadContent]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.sendPluginPayload.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.sendPluginPayload(dataValue);\n\t}\n};\n\napp.styleSettingsRetrieveValue = function(key, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [key]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.styleSettingsRetrieveValue.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.styleSettingsRetrieveValue(dataValue);\n\t}\n};\n\napp.styleSettingsSetValue = function(key, value, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [key, value]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.styleSettingsSetValue.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.styleSettingsSetValue(dataValue);\n\t}\n};\n\napp.retrievePreferencesWithMethodName = function(name, callbackFunction)\n{\n\tvar promiseIndex = appInternal.makePromise(callbackFunction);\n\n\tvar dataValue = {\"promiseIndex\" : promiseIndex, \"values\" : [name]};\n\n\tif (app.isWebKit2()) {\n\t\twindow.webkit.messageHandlers.retrievePreferencesWithMethodName.postMessage(dataValue);\n\t} else {\n\t\tTextualScriptSink.retrievePreferencesWithMethodName(dataValue);\n\t}\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/scroller/automatic.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* ************************************************** */\n/*                     Visibility                     */\n/* ************************************************** */\n\nTextualScroller.documentIsVisible = undefined; /* PUBLIC */\n\n_TextualScroller._documentVisibilityChangedCallback = function() /* PRIVATE */\n{\n\tvar documentHidden = document.hidden;\n\n\tif (documentHidden) {\n\t\tTextualScroller.documentIsVisible = false;\n\t} else {\n\t\tTextualScroller.documentIsVisible = true;\n\n\t\tTextualScroller.restoreScrolledToBottom();\n\t}\n};\n\n_TextualScroller._documentResizedCallback = function()\n{\n\tTextualScroller.restoreScrolledToBottom();\n};\n\n/* ************************************************** */\n/*                 Automatic Scroller                 */\n/* ************************************************** */\n\n_TextualScroller._performScrollTimeout = null; /* PRIVATE */\n_TextualScroller._performScrollNextPass = undefined; /* PRIVATE */\n\n_TextualScroller.performScrollPreflight = function() /* PRIVATE */\n{\n\t/* Do nothing if we are already planning to scroll. */\n\tif (_TextualScroller._performScrollTimeout) {\n\t\treturn;\n\t}\n\n\tif (_TextualScroller._performScrollNextPass) {\n\t\treturn;\n\t}\n\n\t/* Are we at the bottom? */\n\t_TextualScroller._performScrollNextPass =\n\tTextualScroller.isScrolledToBottom();\n};\n\n_TextualScroller.performScrollCancel = function() /* PRIVATE */\n{\n\tif (_TextualScroller._performScrollTimeout) {\n\t\tclearTimeout(_TextualScroller._performScrollTimeout);\n\n\t\t_TextualScroller._performScrollTimeout = null;\n\t}\n\n\t_TextualScroller._performScrollNextPass = undefined;\n};\n\nTextualScroller.performScroll = function() /* PUBLIC */\n{\n\t/* Do nothing if we are already planning to scroll. */\n\tif (_TextualScroller._performScrollTimeout) {\n\t\treturn;\n\t}\n\n\t/* Do not perform automatic scroll if we weren't at bottom. */\n\tif (!_TextualScroller._performScrollNextPass) {\n\t\treturn;\n\t}\n\n\tvar performAutomaticScroll = (function() {\n\t\t_TextualScroller._performScrollTimeout = null;\n\t\t_TextualScroller._performScrollNextPass = undefined;\n\n\t\t_TextualScroller.performScroll();\n\t});\n\n\t_TextualScroller._performScrollTimeout = \n\tsetTimeout(performAutomaticScroll, 0);\n};\n\n_TextualScroller.performScroll = function() /* PRIVATE */\n{\t\n\t/* Do not perform automatic scroll if is disabled. */\n\tif (!TextualScroller.automaticScrollingEnabled) {\n\t\treturn;\n\t}\n\n\t/* Do not perform automatic scroll if the document is not visible. */\n\tif (!TextualScroller.documentIsVisible) {\n\t\treturn;\n\t}\n\n\t/* Scroll to bottom */\n\tTextualScroller.scrollToBottom();\n};\n\n/* This function sets a flag that tells the scroller not to do anything,\nregardless of whether it is visible or not. Visibility will control whether\nthe timer itself is activate, not this function. */\nTextualScroller.automaticScrollingEnabled = true; /* PRIVATE */\n\nTextualScroller.setAutomaticScrollingEnabled = function(enabled) /* PUBLIC */\n{\n\tTextualScroller.automaticScrollingEnabled = enabled;\n};\n\n/* ************************************************** */\n/*              Mutation Observer Helpers             */\n/* ************************************************** */\n\nHTMLDocument.prototype.prepareForMutation = function() /* PUBLIC */\n{\n\t_TextualScroller.prepareForMutation();\n};\n\nHTMLDocument.prototype.cancelMutation = function() /* PUBLIC */\n{\n\t_TextualScroller.cancelMutation();\n};\n\nElement.prototype.prepareForMutation = function() /* PUBLIC */\n{\n\tdocument.prepareForMutation();\n};\n\nElement.prototype.cancelMutation = function() /* PUBLIC */\n{\n\tdocument.cancelMutation();\n};\n\n_TextualScroller.prepareForMutation = function()\n{\n\t_TextualScroller.performScrollPreflight();\n};\n\n_TextualScroller.cancelMutation = function()\n{\n\t_TextualScroller.performScrollCancel();\n};\n\n/* ************************************************** */\n/*                 Mutation Observer                  */\n/* ************************************************** */\n\n_TextualScroller._mutationObserver = null; /* PRIVATE */\n\n_TextualScroller._mutationObserverCallback = function(mutations) /* PRIVATE */\n{\n\tTextualScroller.performScroll();\n};\n\n_TextualScroller.createMutationObserver = function() /* PRIVATE */\n{\n\tvar buffer = MessageBuffer.bufferElement();\n\n\tvar observer = new MutationObserver(_TextualScroller._mutationObserverCallback);\n\n\tobserver.observe(\n\t\tbuffer, \n\n\t\t{\n\t\t\tchildList: true,\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\"wants-reveal\", \"style\"], // for inline media\n\t\t\tsubtree: true\n\t\t}\n\t);\n\n\t_TextualScroller._mutationObserver = observer;\n};\n\n/* ************************************************** */\n/*                      Events                        */\n/* ************************************************** */\n\nwindow.addEventListener(\"resize\", _TextualScroller._documentResizedCallback, false);\n\ndocument.addEventListener(\"visibilitychange\", _TextualScroller._documentVisibilityChangedCallback, false);\n\n/* Populate initial visibility state and maybe create timer */\n_TextualScroller._documentVisibilityChangedCallback();\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/scroller/automaticEmpty.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\n/* ************************************************** */\n/*                 Automatic Scroller                 */\n/* ************************************************** */\n\nTextualScroller.performScroll = function() /* PUBLIC */\n{\n\n};\n\nTextualScroller.setAutomaticScrollingEnabled = function(enabled) /* PUBLIC */\n{\n\n};\n\n/* ************************************************** */\n/*                 Mutation Observer                  */\n/* ************************************************** */\n\nHTMLDocument.prototype.prepareForMutation = function() /* PUBLIC */\n{\n\n};\n\nHTMLDocument.prototype.cancelMutation = function() /* PUBLIC */\n{\n\n};\n\nElement.prototype.prepareForMutation = function() /* PUBLIC */\n{\n\n};\n\nElement.prototype.cancelMutation = function() /* PUBLIC */\n{\n\n};\n\n_TextualScroller.createMutationObserver = function() /* PRIVATE */\n{\n\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/JavaScript/API/private/scroller/state.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"use strict\";\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nvar TextualScroller = {};\nvar _TextualScroller = {};\n\n/* ************************************************** */\n/*                   State Tracking                   */\n/* ************************************************** */\n\n/* Element to scroll */\n_TextualScroller._scrolledElement = null;\n\n/* Minimum distance from bottom to be scrolled upwards\nbefore TextualScroller.userScrolled is true. */\n_TextualScroller._userScrolledMinimum = 25; /* PRIVATE */\n\n/* Whether or not we are scrolled above the bottom. */\nTextualScroller.userScrolled = false; /* PUBLIC */\n\n/* Set to true when scrolled upwards. */\nTextualScroller.scrolledUpwards = false; /* PUBLIC */\n\n/* Cached scroll position */\nTextualScroller.scrollPositionCurrentValue = 0; /* PUBLIC */\nTextualScroller.scrollPositionPreviousValue = 0; /* PUBLIC */\n\n/* Cached scroll height */\nTextualScroller.scrollHeightCurrentValue = 0; /* PUBLIC */\nTextualScroller.scrollHeightPreviousValue = 0; /* PUBLIC */\n\n_TextualScroller._documentScrolledCallback = function() /* PRIVATE */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\t/* Height of scrollable area */\n\tvar scrollHeightPrevious = TextualScroller.scrollHeightCurrentValue;\n\n\tvar scrollHeightCurrent = scrolledElement.scrollHeight;\n\n\t/* The current position scrolled to */\n\tvar clientHeight = scrolledElement.clientHeight;\n\n\tvar scrollPositionCurrent = (scrolledElement.scrollTop + clientHeight);\n\n\tvar scrollPositionPrevious = TextualScroller.scrollPositionCurrentValue;\n\n\t/* If nothing changed, we ignore the event.\n\tIt is possible to receive a scroll event but nothing changes\n\tbecause we ignore elastic scrolling. User can reach bottom,\n\telastic scroll, then bounce back. We get notification for\n\tboth times we reach bottom, but values do not change. */\n\tif (scrollHeightPrevious === scrollHeightCurrent &&\n\t\tscrollPositionPrevious === scrollPositionCurrent) \n\t{\n\t\treturn;\n\t}\n\n\t/* Even if user is elastic scrolling, we want to record\n\tthe latest scroll height values. */\n\tTextualScroller.scrollHeightPreviousValue = scrollHeightPrevious;\n\tTextualScroller.scrollHeightCurrentValue = scrollHeightCurrent;\n\n\t/* Ignore elastic scrolling */\n\tif (scrollPositionCurrent < clientHeight ||\n\t\tscrollPositionCurrent > scrollHeightCurrent) \n\t{\n\t\treturn;\n\t}\n\n\t/* Only record scroll position changes if we weren't elastic scrolling. */\n\tTextualScroller.scrollPositionPreviousValue = scrollPositionPrevious;\n\tTextualScroller.scrollPositionCurrentValue = scrollPositionCurrent;\n\n\t/* Scrolled upwards? */\n\tvar scrolledUpwards = (scrollPositionCurrent < scrollPositionPrevious);\n\n\tTextualScroller.scrolledUpwards = scrolledUpwards;\n\n\t/* User scrolled above bottom? */\n\tvar userScrolled = ((scrollHeightCurrent - scrollPositionCurrent) > _TextualScroller._userScrolledMinimum);\n\n\tTextualScroller.userScrolled = userScrolled;\n\n\t/* Post custom scroll event */\n\tif (scrolledUpwards) {\n\t\tdocument.dispatchEvent(new Event('scrolledUpward'));\n\t} else {\n\t\tdocument.dispatchEvent(new Event('scrolledDownward'));\n\t}\n};\n\n/* ************************************************** */\n/*               Position Restore                     */\n/* ************************************************** */\n\n_TextualScroller._restoreScrolledUpwards = undefined; /* PRIVATE */\n_TextualScroller._restoreScrollHeightFirstValue = undefined; /* PRIVATE */\n_TextualScroller._restoreScrollHeightSecondValue = undefined; /* PRIVATE */\n\nTextualScroller.saveRestorationFirstDataPoint = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\t_TextualScroller._restoreScrollHeightFirstValue = scrolledElement.scrollHeight;\n\n\t_TextualScroller._restoreScrolledUpwards = TextualScroller.scrolledUpwards;\n};\n\nTextualScroller.saveRestorationSecondDataPoint = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\t_TextualScroller._restoreScrollHeightSecondValue = scrolledElement.scrollHeight;\n};\n\nTextualScroller.restoreScrollPosition = function() /* PUBLIC */\n{\n\tvar scrollHeightDifference = (_TextualScroller._restoreScrollHeightSecondValue - \n\t\t\t\t\t\t\t\t  _TextualScroller._restoreScrollHeightFirstValue);\n\n\tif (scrollHeightDifference === 0) {\n\t\treturn;\n\t}\n\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\tvar scrollTo = 0;\n\n\tif (_TextualScroller._restoreScrolledUpwards === false) {\n\t\tscrollTo = (scrolledElement.scrollHeight - scrollHeightDifference);\n\t} else {\n\t\tscrollTo = (scrolledElement.scrollHeight + scrollHeightDifference);\n\t}\n\n\tif (scrollTo < 0) {\n\t\tscrollTo = 0;\n\t}\n\n\tscrolledElement.scrollTop = scrollTo;\n\n\t_TextualScroller._restoreScrollHeightFirstValue = undefined;\n\t_TextualScroller._restoreScrollHeightSecondValue = undefined;\n\n\t_TextualScroller._restoreScrolledUpwards = undefined;\n};\n\nTextualScroller.restoreScrolledToBottom = function() /* PUBLIC */\n{\n\tif (TextualScroller.userScrolled === false) {\n\t\tTextualScroller.scrollToBottom();\n\t}\n};\n\n/* ************************************************** */\n/*              Element Prototypes                    */\n/* ************************************************** */\n\nElement.prototype.scrollCenterIn = function(parentElement) /* PUBLIC */\n{\n\tif (this === parentElement) {\n\t\tthrow \"Can't scroll self into center\";\n\t}\n\n\tvar parentElementRect = parentElement.getBoundingClientRect();\n\tvar parentElementHeight = parentElementRect.height;\n\tvar parentElementTop = parentElement.scrollTop;\n\n\tvar elementRect = this.getBoundingClientRect();\n\tvar elementTop = (elementRect.top + parentElementTop);\n\tvar elementCenter = (elementTop - (parentElementHeight / 2));\n\n\treturn elementCenter;\n};\n\nElement.prototype.percentScrolled = function() /* PUBLIC */\n{\n\treturn (((this.scrollTop + this.clientHeight) / this.scrollHeight) * 100.0);\n};\n\nElement.prototype.isScrolledToTop = function() /* PUBLIC */\n{\n\treturn (this.scrollTop <= 0);\n};\n\nElement.prototype.scrollToTop = function() /* PUBLIC */\n{\n\tthis.scrollTop = 0;\n};\n\nElement.prototype.scrollIntoViewAlignTop = function() /* PUBLIC */\n{\n\tthis.scrollIntoView(true);\n};\n\nElement.prototype.scrollIntoViewAlignBottom = function() /* PUBLIC */\n{\n\tthis.scrollIntoView(false);\n};\n\nElement.prototype.isScrolledToBottom = function() /* PUBLIC */\n{\n\treturn ((this.scrollTop + this.clientHeight) >= this.scrollHeight);\n};\n\nElement.prototype.scrollToBottom = function() /* PUBLIC */\n{\n\tthis.scrollTop = this.scrollHeight;\n};\n\n/* ************************************************** */\n/*              Element Prototype Proxies             */\n/* ************************************************** */\n\nTextualScroller.scrollElementToCenter = function(element) /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\tvar scrollCenter = element.scrollCenterIn(scrolledElement);\n\n\tscrolledElement.scrollTop = scrollCenter;\n};\n\nTextualScroller.percentScrolled = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\treturn scrolledElement.percentScrolled();\n};\n\nTextualScroller.isScrolledToTop = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\treturn scrolledElement.isScrolledToTop();\n};\n\nTextualScroller.scrollToTop = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\tscrolledElement.scrollToTop();\n};\n\nTextualScroller.isScrolledToBottom = function() /* PUBLIC */\n{\n\t/* If a timer is set to scroll to the bottom already,\n\tthen we lie about our current position. */\n\tif (_TextualScroller._performScrollTimeout) {\n\t\treturn true;\n\t}\n\n\tif (!TextualScroller.userScrolled) {\n\t\treturn true;\n\t}\n\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\treturn scrolledElement.isScrolledToBottom();\n};\n\nTextualScroller.scrollToBottom = function() /* PUBLIC */\n{\n\tvar scrolledElement = _TextualScroller._scrolledElement;\n\n\tscrolledElement.scrollToBottom();\n};\n\n/* ************************************************** */\n/*                     Events                         */\n/* ************************************************** */\n\n/* This function is public interface which styles are \nallowed to override which we should add extra sanity. */\nTextualScroller.bindToElement = function(newElement) /* PUBLIC */\n{\n\tif (!newElement ||\n\t\t!newElement.nodeType ||\n\t\t newElement.nodeType !== Node.ELEMENT_NODE) \n\t{\n\t\tthrow \"Argument is not an element\";\n\t}\n\n\tvar oldElement = _TextualScroller._scrolledElement;\n\n\tif (oldElement) {\n\t\tif (oldElement !== document.body) {\n\t\t\toldElement.removeEventListener(\"scroll\", _TextualScroller._documentScrolledCallback);\n\t\t} else {\n\t\t\twindow.removeEventListener(\"scroll\", _TextualScroller._documentScrolledCallback);\n\t\t}\n\t}\n\n\tif (newElement !== document.body) {\n\t\tnewElement.addEventListener(\"scroll\", _TextualScroller._documentScrolledCallback, false);\n\t} else {\n\t\twindow.addEventListener(\"scroll\", _TextualScroller._documentScrolledCallback, false);\n\t}\n\n\t_TextualScroller._scrolledElement = newElement;\n};\n\n_TextualScroller.bindToBestElement = function()\n{\n\tvar bindToElement = (function(element) {\n\t\tif (window.getComputedStyle(element).overflowY === \"hidden\") {\n\t\t\treturn false;\n\t\t}\n\n\t\tTextualScroller.bindToElement(element);\n\n\t\treturn true;\n\t});\n\n\tif (bindToElement(document.body)) {\n\t\tconsole.log(\"Binding to document body\");\n\n\t\treturn;\n\t} else if (bindToElement(Textual.documentBodyElement())) {\n\t\tconsole.log(\"Binding to #body_home\");\n\n\t\treturn;\n\t} else if (bindToElement(MessageBuffer.bufferElement())) {\n\t\tconsole.log(\"Binding to #message_buffer\");\n\n\t\treturn;\n\t}\n\n\tconsole.error(\"No element to bind to. Manually call TextualScroller.bindToElement()\");\n};\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/baseLayout.css",
    "content": "\n/*\n\n\t PLEASE READ\n\n\t The following CSS definitions exist for the internal use of Textual.\n\t If you are a style developer reading this and plan on using custom\n\t templates, then DO NOT modify these. You can touch anything else you\n\t want, but we are trying to have some consistency between styles.\n\n\t PLEASE READ\n\n */\n\n/* Print actions */\n@media print {\n\t#topicBar {\n\t\tdisplay: none;\n\t}\n}\n\n/* Reserved lines */\n/* Fixed width font line */\ntt {\n\tfont-family: \"Menlo\" !important;\n}\n\n/* mIRC Color Codes */\n.effect[data-foreground-color='0']  { color: #ffffff; }\n.effect[data-foreground-color='1']  { color: #000000; }\n.effect[data-foreground-color='2']  { color: #000088; }\n.effect[data-foreground-color='3']  { color: #008800; }\n.effect[data-foreground-color='4']  { color: #ff0000; }\n.effect[data-foreground-color='5']  { color: #880000; }\n.effect[data-foreground-color='6']  { color: #880088; }\n.effect[data-foreground-color='7']  { color: #ff8800; }\n.effect[data-foreground-color='8']  { color: #ffff00; }\n.effect[data-foreground-color='9']  { color: #00ff00; }\n.effect[data-foreground-color='10'] { color: #008888; }\n.effect[data-foreground-color='11'] { color: #00ffff; }\n.effect[data-foreground-color='12'] { color: #0000ff; }\n.effect[data-foreground-color='13'] { color: #ff00ff; }\n.effect[data-foreground-color='14'] { color: #888888; }\n.effect[data-foreground-color='15'] { color: #cccccc; }\n.effect[data-foreground-color='16'] { color: #470000; }\n.effect[data-foreground-color='17'] { color: #472100; }\n.effect[data-foreground-color='18'] { color: #474700; }\n.effect[data-foreground-color='19'] { color: #324700; }\n.effect[data-foreground-color='20'] { color: #004700; }\n.effect[data-foreground-color='21'] { color: #00472c; }\n.effect[data-foreground-color='22'] { color: #004747; }\n.effect[data-foreground-color='23'] { color: #002747; }\n.effect[data-foreground-color='24'] { color: #000047; }\n.effect[data-foreground-color='25'] { color: #2e0047; }\n.effect[data-foreground-color='26'] { color: #470047; }\n.effect[data-foreground-color='27'] { color: #47002a; }\n.effect[data-foreground-color='28'] { color: #740000; }\n.effect[data-foreground-color='29'] { color: #743a00; }\n.effect[data-foreground-color='30'] { color: #747400; }\n.effect[data-foreground-color='31'] { color: #517400; }\n.effect[data-foreground-color='32'] { color: #007400; }\n.effect[data-foreground-color='33'] { color: #007449; }\n.effect[data-foreground-color='34'] { color: #007474; }\n.effect[data-foreground-color='35'] { color: #004074; }\n.effect[data-foreground-color='36'] { color: #000074; }\n.effect[data-foreground-color='37'] { color: #4b0074; }\n.effect[data-foreground-color='38'] { color: #740074; }\n.effect[data-foreground-color='39'] { color: #740045; }\n.effect[data-foreground-color='40'] { color: #b50000; }\n.effect[data-foreground-color='41'] { color: #b56300; }\n.effect[data-foreground-color='42'] { color: #b5b500; }\n.effect[data-foreground-color='43'] { color: #7db500; }\n.effect[data-foreground-color='44'] { color: #00b500; }\n.effect[data-foreground-color='45'] { color: #00b571; }\n.effect[data-foreground-color='46'] { color: #00b5b5; }\n.effect[data-foreground-color='47'] { color: #0063b5; }\n.effect[data-foreground-color='48'] { color: #0000b5; }\n.effect[data-foreground-color='49'] { color: #7500b5; }\n.effect[data-foreground-color='50'] { color: #b500b5; }\n.effect[data-foreground-color='51'] { color: #b5006b; }\n.effect[data-foreground-color='52'] { color: #ff0000; }\n.effect[data-foreground-color='53'] { color: #ff8c00; }\n.effect[data-foreground-color='54'] { color: #ffff00; }\n.effect[data-foreground-color='55'] { color: #b2ff00; }\n.effect[data-foreground-color='56'] { color: #00ff00; }\n.effect[data-foreground-color='57'] { color: #00ffa0; }\n.effect[data-foreground-color='58'] { color: #00ffff; }\n.effect[data-foreground-color='59'] { color: #008cff; }\n.effect[data-foreground-color='60'] { color: #0000ff; }\n.effect[data-foreground-color='61'] { color: #a500ff; }\n.effect[data-foreground-color='62'] { color: #ff00ff; }\n.effect[data-foreground-color='63'] { color: #ff0098; }\n.effect[data-foreground-color='64'] { color: #ff5959; }\n.effect[data-foreground-color='65'] { color: #ffb459; }\n.effect[data-foreground-color='66'] { color: #ffff71; }\n.effect[data-foreground-color='67'] { color: #cfff60; }\n.effect[data-foreground-color='68'] { color: #6fff6f; }\n.effect[data-foreground-color='69'] { color: #65ffc9; }\n.effect[data-foreground-color='70'] { color: #6dffff; }\n.effect[data-foreground-color='71'] { color: #59b4ff; }\n.effect[data-foreground-color='72'] { color: #5959ff; }\n.effect[data-foreground-color='73'] { color: #c459ff; }\n.effect[data-foreground-color='74'] { color: #ff66ff; }\n.effect[data-foreground-color='75'] { color: #ff59bc; }\n.effect[data-foreground-color='76'] { color: #ff9c9c; }\n.effect[data-foreground-color='77'] { color: #ffd39c; }\n.effect[data-foreground-color='78'] { color: #ffff9c; }\n.effect[data-foreground-color='79'] { color: #e2ff9c; }\n.effect[data-foreground-color='80'] { color: #9cff9c; }\n.effect[data-foreground-color='81'] { color: #9cffdb; }\n.effect[data-foreground-color='82'] { color: #9cffff; }\n.effect[data-foreground-color='83'] { color: #9cd3ff; }\n.effect[data-foreground-color='84'] { color: #9c9cff; }\n.effect[data-foreground-color='85'] { color: #dc9cff; }\n.effect[data-foreground-color='86'] { color: #ff9cff; }\n.effect[data-foreground-color='87'] { color: #ff94d3; }\n.effect[data-foreground-color='88'] { color: #000000; }\n.effect[data-foreground-color='89'] { color: #131313; }\n.effect[data-foreground-color='90'] { color: #282828; }\n.effect[data-foreground-color='91'] { color: #363636; }\n.effect[data-foreground-color='92'] { color: #4d4d4d; }\n.effect[data-foreground-color='93'] { color: #656565; }\n.effect[data-foreground-color='94'] { color: #818181; }\n.effect[data-foreground-color='95'] { color: #9f9f9f; }\n.effect[data-foreground-color='96'] { color: #bcbcbc; }\n.effect[data-foreground-color='97'] { color: #e2e2e2; }\n.effect[data-foreground-color='98'] { color: #ffffff; }\n\n.effect[data-background-color='0']  { background-color: #ffffff; }\n.effect[data-background-color='1']  { background-color: #000000; }\n.effect[data-background-color='2']  { background-color: #000088; }\n.effect[data-background-color='3']  { background-color: #008800; }\n.effect[data-background-color='4']  { background-color: #ff0000; }\n.effect[data-background-color='5']  { background-color: #880000; }\n.effect[data-background-color='6']  { background-color: #880088; }\n.effect[data-background-color='7']  { background-color: #ff8800; }\n.effect[data-background-color='8']  { background-color: #ffff00; }\n.effect[data-background-color='9']  { background-color: #00ff00; }\n.effect[data-background-color='10'] { background-color: #008888; }\n.effect[data-background-color='11'] { background-color: #00ffff; }\n.effect[data-background-color='12'] { background-color: #0000ff; }\n.effect[data-background-color='13'] { background-color: #ff00ff; }\n.effect[data-background-color='14'] { background-color: #888888; }\n.effect[data-background-color='15'] { background-color: #cccccc; }\n.effect[data-background-color='16'] { background-color: #470000; }\n.effect[data-background-color='17'] { background-color: #472100; }\n.effect[data-background-color='18'] { background-color: #474700; }\n.effect[data-background-color='19'] { background-color: #324700; }\n.effect[data-background-color='20'] { background-color: #004700; }\n.effect[data-background-color='21'] { background-color: #00472c; }\n.effect[data-background-color='22'] { background-color: #004747; }\n.effect[data-background-color='23'] { background-color: #002747; }\n.effect[data-background-color='24'] { background-color: #000047; }\n.effect[data-background-color='25'] { background-color: #2e0047; }\n.effect[data-background-color='26'] { background-color: #470047; }\n.effect[data-background-color='27'] { background-color: #47002a; }\n.effect[data-background-color='28'] { background-color: #740000; }\n.effect[data-background-color='29'] { background-color: #743a00; }\n.effect[data-background-color='30'] { background-color: #747400; }\n.effect[data-background-color='31'] { background-color: #517400; }\n.effect[data-background-color='32'] { background-color: #007400; }\n.effect[data-background-color='33'] { background-color: #007449; }\n.effect[data-background-color='34'] { background-color: #007474; }\n.effect[data-background-color='35'] { background-color: #004074; }\n.effect[data-background-color='36'] { background-color: #000074; }\n.effect[data-background-color='37'] { background-color: #4b0074; }\n.effect[data-background-color='38'] { background-color: #740074; }\n.effect[data-background-color='39'] { background-color: #740045; }\n.effect[data-background-color='40'] { background-color: #b50000; }\n.effect[data-background-color='41'] { background-color: #b56300; }\n.effect[data-background-color='42'] { background-color: #b5b500; }\n.effect[data-background-color='43'] { background-color: #7db500; }\n.effect[data-background-color='44'] { background-color: #00b500; }\n.effect[data-background-color='45'] { background-color: #00b571; }\n.effect[data-background-color='46'] { background-color: #00b5b5; }\n.effect[data-background-color='47'] { background-color: #0063b5; }\n.effect[data-background-color='48'] { background-color: #0000b5; }\n.effect[data-background-color='49'] { background-color: #7500b5; }\n.effect[data-background-color='50'] { background-color: #b500b5; }\n.effect[data-background-color='51'] { background-color: #b5006b; }\n.effect[data-background-color='52'] { background-color: #ff0000; }\n.effect[data-background-color='53'] { background-color: #ff8c00; }\n.effect[data-background-color='54'] { background-color: #ffff00; }\n.effect[data-background-color='55'] { background-color: #b2ff00; }\n.effect[data-background-color='56'] { background-color: #00ff00; }\n.effect[data-background-color='57'] { background-color: #00ffa0; }\n.effect[data-background-color='58'] { background-color: #00ffff; }\n.effect[data-background-color='59'] { background-color: #008cff; }\n.effect[data-background-color='60'] { background-color: #0000ff; }\n.effect[data-background-color='61'] { background-color: #a500ff; }\n.effect[data-background-color='62'] { background-color: #ff00ff; }\n.effect[data-background-color='63'] { background-color: #ff0098; }\n.effect[data-background-color='64'] { background-color: #ff5959; }\n.effect[data-background-color='65'] { background-color: #ffb459; }\n.effect[data-background-color='66'] { background-color: #ffff71; }\n.effect[data-background-color='67'] { background-color: #cfff60; }\n.effect[data-background-color='68'] { background-color: #6fff6f; }\n.effect[data-background-color='69'] { background-color: #65ffc9; }\n.effect[data-background-color='70'] { background-color: #6dffff; }\n.effect[data-background-color='71'] { background-color: #59b4ff; }\n.effect[data-background-color='72'] { background-color: #5959ff; }\n.effect[data-background-color='73'] { background-color: #c459ff; }\n.effect[data-background-color='74'] { background-color: #ff66ff; }\n.effect[data-background-color='75'] { background-color: #ff59bc; }\n.effect[data-background-color='76'] { background-color: #ff9c9c; }\n.effect[data-background-color='77'] { background-color: #ffd39c; }\n.effect[data-background-color='78'] { background-color: #ffff9c; }\n.effect[data-background-color='79'] { background-color: #e2ff9c; }\n.effect[data-background-color='80'] { background-color: #9cff9c; }\n.effect[data-background-color='81'] { background-color: #9cffdb; }\n.effect[data-background-color='82'] { background-color: #9cffff; }\n.effect[data-background-color='83'] { background-color: #9cd3ff; }\n.effect[data-background-color='84'] { background-color: #9c9cff; }\n.effect[data-background-color='85'] { background-color: #dc9cff; }\n.effect[data-background-color='86'] { background-color: #ff9cff; }\n.effect[data-background-color='87'] { background-color: #ff94d3; }\n.effect[data-background-color='88'] { background-color: #000000; }\n.effect[data-background-color='89'] { background-color: #131313; }\n.effect[data-background-color='90'] { background-color: #282828; }\n.effect[data-background-color='91'] { background-color: #363636; }\n.effect[data-background-color='92'] { background-color: #4d4d4d; }\n.effect[data-background-color='93'] { background-color: #656565; }\n.effect[data-background-color='94'] { background-color: #818181; }\n.effect[data-background-color='95'] { background-color: #9f9f9f; }\n.effect[data-background-color='96'] { background-color: #bcbcbc; }\n.effect[data-background-color='97'] { background-color: #e2e2e2; }\n.effect[data-background-color='98'] { background-color: #ffffff; }\n\n/* Selection */\nbody[data-selected=\"false\"] {\n\tpointer-events: none;\n}\n\nbody[data-selected=\"false\"] #topicBar {\n\tdisplay: none;\n}\n\n/* Spoilers */\n/* !importmant must be used in this context because\n when we have hex colors, those are set using the\n style attribute which we must overpower. */\n.effect[data-is-spoiler='true']:hover {\n\tcolor: inherit !important;\n\tbackground-color: transparent !important;\n}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/baseLayout.mustache",
    "content": "<html>\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset={{userConfiguredTextEncoding}}\">\n\n\t\t{{#activeStyleCSSFiles}}\n\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{{.}}?{{cacheToken}}\" charset=\"UTF-8\">\n\t\t{{/activeStyleCSSFiles}}\n\n\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"{{applicationTemplatesPath}}/baseLayout.css?{{cacheToken}}\" charset=\"UTF-8\">\n\n\t\t<script src=\"{{applicationResourcePath}}/JavaScript/API/core.js\" type=\"text/javascript\" charset=\"UTF-8\"></script>\n\t\t<script src=\"{{applicationResourcePath}}/JavaScript/API/corePrivate.js\" type=\"text/javascript\" charset=\"UTF-8\"></script>\n\n\t\t<script type=\"text/javascript\">\n\t\t\tTextual.initializeCore(\"{{applicationResourcePath}}\");\n\t\t</script>\n\n\t\t{{#activeStyleJSFiles}}\n\t\t<script src=\"{{.}}?{{cacheToken}}\" type=\"text/javascript\" charset=\"UTF-8\"></script>\n\t\t{{/activeStyleJSFiles}}\n\n\t\t<style type=\"text/css\">\n\t\t\thtml, body {\n\t\t\t\tfont-family: '{{userConfiguredFontName}}';\n\t\t\t\tfont-size: {{userConfiguredFontSize}}pt;\n\t\t\t}\n\n\t\t\t{{#nicknameIndentationAvailable}}\n\t\t\t\tdiv.line p {\n\t\t\t\t\tmargin-left: {{predefinedTimestampWidth}}px;\n\t\t\t\t\ttext-indent: -{{predefinedTimestampWidth}}px;\n\t\t\t\t}\n\n\t\t\t\tdiv.line .time {\n\t\t\t\t\twidth: {{predefinedTimestampWidth}}px;\n\t\t\t\t}\n\t\t\t{{/nicknameIndentationAvailable}}\n\n\t\t\t{{{userStyleSheetRules}}}\n\t\t</style>\n\t</head>\n\n\t<body\n\n\t\tdir=\"{{textDirectionToken}}\"\n\n\t\tonload=\"_Textual.viewBodyDidLoad()\"\n\n\t\tdata-appearance=\"{{appearanceToken}}\"\n\n{{#usesCustomScrollers}}\n\t\tdata-custom-scroller=\"true\"\n{{/usesCustomScrollers}}\n\n\t\t{{! The operating system version declaration allows CSS selectors to target specific versions. }}\n\t\tdata-system-version=\"{{operatingSystemVersion}}\"\n\n{{#isChannelView}}\n\t\tdata-view-name=\"{{channelName}}\"\n{{/isChannelView}}\n\n{{#isPrivateMessageView}}\n\t\tdata-view-name=\"{{channelName}}\"\n{{/isPrivateMessageView}}\n\n{{#isUtilityView}}\n\t\tdata-view-name=\"{{channelName}}\"\n{{/isUtilityView}}\n\n\t\tdata-view-type=\"{{viewTypeToken}}\">\n\t\t\t{{! The elements \"body,\" \"messageBuffer,\" \"loadingScreen,\"\n\t\t\t\"topicBar,\" and \"mark\" must always remain the same id= as these\n\t\t\telements are used internally by Textual. }}\n\n\t\t\t<div id=\"loadingScreen\">View is Loading…</div>\n\n\t\t\t{{#isChannelView}}\n\t\t\t\t<div id=\"topicBar\" ondblclick=\"Textual.topicBarDoubleClicked()\">(No Topic)</div>\n\t\t\t{{/isChannelView}}\n\n\t\t\t<div id=\"body\">\n\t\t\t\t<div id=\"messageBuffer\">\n\t\t\t\t</div>\n\t\t\t</div>\n\t</body>\n</html>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/dateIndicator.mustache",
    "content": "\n<div class=\"date_indicator\">\n\t<hr />\n\t<span>{{dateIndicatorMessage}}</span>\n\t<hr />\n</div>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/encryptedMessageLock.mustache",
    "content": "\n<span class=\"encryptionLock\">{{! Not handled by default. }}</span>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/formattedMessageFragment.mustache",
    "content": "{{! When this is a new fragment, but not the last fragment,\nthen we use the following *ClosedAtStart tags to close any\nformatting that may be open for the previous fragment. }}\n{{#fragmentIsBoldClosedAtStart}}</b>{{/fragmentIsBoldClosedAtStart}}\n{{#fragmentIsItalicizedClosedAtStart}}</i>{{/fragmentIsItalicizedClosedAtStart}}\n{{#fragmentIsMonospaceClosedAtStart}}</tt>{{/fragmentIsMonospaceClosedAtStart}}\n{{#fragmentIsStruckthroughClosedAtStart}}</del>{{/fragmentIsStruckthroughClosedAtStart}}\n{{#fragmentIsUnderlinedClosedAtStart}}</u>{{/fragmentIsUnderlinedClosedAtStart}}\n{{#fragmentTextColorClosedAtStart}}\n</span>\n{{/fragmentTextColorClosedAtStart}}\n\n{{#fragmentTextColorOpened}}\n<span class=\"effect\"\n\t{{#fragmentTextColorUsesStyleTag}}\n\t\tstyle=\"\n\t\t\t{{#fragmentForegroundColorIsSet}}\n\t\t\t\tcolor: {{fragmentForegroundColor}};\n\t\t\t{{/fragmentForegroundColorIsSet}}\n\n\t\t\t{{#fragmentBackgroundColorIsSet}}\n\t\t\t\tbackground-color: {{fragmentBackgroundColor}};\n\t\t\t{{/fragmentBackgroundColorIsSet}}\n\t\t\"\n\t{{^fragmentTextColorUsesStyleTag}}\n\t\t{{#fragmentForegroundColorIsSet}}\n\t\t\tdata-foreground-color=\"{{fragmentForegroundColor}}\"\n\t\t{{/fragmentForegroundColorIsSet}}\n\n\t\t{{#fragmentBackgroundColorIsSet}}\n\t\t\tdata-background-color=\"{{fragmentBackgroundColor}}\"\n\t\t{{/fragmentBackgroundColorIsSet}}\n\t{{/fragmentTextColorUsesStyleTag}}\n\n\t{{#fragmentIsSpoiler}}\n\t\tdata-is-spoiler=\"true\"\n\t{{/fragmentIsSpoiler}}\n>\n{{/fragmentTextColorOpened}}\n{{#fragmentIsBoldOpened}}<b>{{/fragmentIsBoldOpened}}\n{{#fragmentIsItalicizedOpened}}<i>{{/fragmentIsItalicizedOpened}}\n{{#fragmentIsMonospaceOpened}}<tt>{{/fragmentIsMonospaceOpened}}\n{{#fragmentIsStruckthroughOpened}}<del>{{/fragmentIsStruckthroughOpened}}\n{{#fragmentIsUnderlinedOpened}}<u>{{/fragmentIsUnderlinedOpened}}\n\n{{#inlineNicknameMatchFound}}\n<span class=\"inlineSender\" ondblclick=\"Textual.inlineNicknameDoubleClicked()\" oncontextmenu=\"Textual.openInlineNicknameContextualMenu()\" data-mode=\"{{inlineNicknameUserModeSymbol}}\"\n\t{{#nicknameColorStyleOverride}}\n\t\tdata-override-color=\"true\"\n\t{{/nicknameColorStyleOverride}}\n\n\t{{^ isEmpty(inlineNicknameColorStyle) }}\n\t\tstyle=\"color: {{inlineNicknameColorStyle}};\"\n\t{{/ isEmpty(inlineNicknameColorStyle) }}>{{inlineNicknameUserModeSymbol}}\n{{/inlineNicknameMatchFound}}\n{{{messageFragment}}}\n{{#inlineNicknameMatchFound}}\n</span>\n{{/inlineNicknameMatchFound}}\n\n{{! When this is the end of the last fragment, we terminate all }}\n{{#fragmentIsBoldClosedAtEnd}}</b>{{/fragmentIsBoldClosedAtEnd}}\n{{#fragmentIsItalicizedClosedAtEnd}}</i>{{/fragmentIsItalicizedClosedAtEnd}}\n{{#fragmentIsMonospaceClosedAtEnd}}</tt>{{/fragmentIsMonospaceClosedAtEnd}}\n{{#fragmentIsStruckthroughClosedAtEnd}}</del>{{/fragmentIsStruckthroughClosedAtEnd}}\n{{#fragmentIsUnderlinedClosedAtEnd}}</u>{{/fragmentIsUnderlinedClosedAtEnd}}\n{{#fragmentTextColorClosedAtEnd}}\n</span>\n{{/fragmentTextColorClosedAtEnd}}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/historyIndicator.mustache",
    "content": "\n<div id=\"mark\"></div>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/messageBufferLoadingIndicator.mustache",
    "content": "\n<div id=\"mb_loading-{{lineNumber}}\" class=\"message_buffer_loading_indicator\">\n\t<span>•</span>\n\t<span>•</span>\n\t<span>•</span>\n</div>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/messageBufferSessionIndicator.mustache",
    "content": "\n{{! This template is deprecated. Use sessionIndicator.mustache instead. }}\n\n{{> sessionIndicator}}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/newMessagePostedWithSender.mustache",
    "content": "\n{{#showDateIndicator}}\n\t{{> dateIndicator}}\n{{/showDateIndicator}}\n\n<div\n\tclass=\"line {{lineClassAttribute}}\"\n\tid=\"line-{{lineNumber}}\"\n\n\tdata-command=\"{{command}}\"\n\n{{#isEncrypted}}\n\tdata-encrypted=\"true\"\n{{/isEncrypted}}\n\n\tdata-highlight=\"{{highlightAttribute}}\"\n\tdata-line-type=\"{{lineType}}\"\n\n{{^isRemoteMessage}}\n\tdata-member-type=\"{{nicknameType}}\"\n{{/isRemoteMessage}}\n\n\tdata-timestamp=\"{{timestamp}}\">\n\n\t<p>\n\t\t<span class=\"time\"\n\n\t\t{{^ isEmpty(localizedTimestamp) }}\n\t\t\ttitle=\"{{localizedTimestamp}}\"\n\t\t{{/ isEmpty(localizedTimestamp) }}>{{formattedTimestamp}} </span>\n\n{{#isEncrypted}}\n\t{{> encryptedMessageLock}}\n{{/isEncrypted}}\n\n\t\t<span class=\"message\">\n\t\t\t<span class=\"senderContainer\">\n\t\t\t\t<span class=\"sender\"\n\t\t\t\t\tonclick=\"Textual.nicknameMaybeWasDoubleClicked(this)\"\n\t\t\t\t\toncontextmenu=\"Textual.openStandardNicknameContextualMenu()\"\n\t\t\t\t\tdata-member-type=\"{{nicknameType}}\"\n\t\t\t\t\tdata-nickname=\"{{nickname}}\"\n\n\t\t\t\t\t{{#nicknameColorHashingEnabled}}\n\t\t\t\t\t\t{{#nicknameColorStyleOverride}}\n\t\t\t\t\t\tdata-override-color=\"true\"\n\t\t\t\t\t\t{{/nicknameColorStyleOverride}}\n\n\t\t\t\t\t\t{{^ isEmpty(nicknameColorStyle) }}\n\t\t\t\t\t\tstyle=\"color: {{nicknameColorStyle}};\"\n\t\t\t\t\t\t{{/ isEmpty(nicknameColorStyle) }}\n\t\t\t\t\t{{/nicknameColorHashingEnabled}}>{{formattedNickname}}</span>\n\t\t\t</span>\n\n\t\t\t<span class=\"innerMessage\">\n\t\t\t\t{{{formattedMessage}}}\n\n\t\t\t\t{{#inlineMediaEnabled}}\n\t\t\t\t\t<span class=\"inlineMediaContainer\"></span>\n\t\t\t\t{{/inlineMediaEnabled}}\n\t\t\t</span>\n\t\t</span>\n\t</p>\n</div>\n\n{{#showSessionIndicator}}\n\t{{> sessionIndicator}}\n{{/showSessionIndicator}}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/newMessagePostedWithoutSender.mustache",
    "content": "\n{{#showDateIndicator}}\n\t{{> dateIndicator}}\n{{/showDateIndicator}}\n\n<div\n\tclass=\"line {{lineClassAttribute}}\"\n\tid=\"line-{{lineNumber}}\"\n\n\tdata-command=\"{{command}}\"\n\tdata-line-type=\"{{lineType}}\"\n\n{{^isRemoteMessage}}\n\tdata-member-type=\"{{nicknameType}}\"\n{{/isRemoteMessage}}\n\n\tdata-timestamp=\"{{timestamp}}\">\n\n\t<p>\n\t\t<span class=\"time\"\n\n\t\t{{^ isEmpty(localizedTimestamp) }}\n\t\ttitle=\"{{localizedTimestamp}}\"\n\t\t{{/ isEmpty(localizedTimestamp) }}>{{formattedTimestamp}} </span>\n\n\t\t<span class=\"message\">\n\t\t\t{{{formattedMessage}}}\n\t\t</span>\n\t</p>\n</div>\n\n{{#showSessionIndicator}}\n\t{{> sessionIndicator}}\n{{/showSessionIndicator}}\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/renderedChannelNameLinkResource.mustache",
    "content": "\n<span class=\"channel\" ondblclick=\"Textual.channelNameDoubleClicked()\" oncontextmenu=\"Textual.openChannelNameContextualMenu()\">{{channelName}}</span>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/renderedStandardAnchorLinkResource.mustache",
    "content": "\n<a href=\"{{anchorLocation}}\" class=\"url\" oncontextmenu=\"Textual.openURLManagementContextualMenu()\" {{#anchorInlineMediaAvailable}} onclick=\"return InlineMedia.toggleOnClick('{{anchorInlineMediaUniqueID}}')\" data-ilm-anchor=\"{{anchorInlineMediaUniqueID}}\" {{/anchorInlineMediaAvailable}} >{{{anchorTitle}}}</a>\n"
  },
  {
    "path": "Sources/App/Resources/Styling/Style Default Templates/Version 4/sessionIndicator.mustache",
    "content": "\n{{! \"message_buffer_session_indicator\" is kept for backwards compatibility (<=7.0.10) }}\n\n<div class=\"session_indicator message_buffer_session_indicator\">\n\t<hr />\n\t<span>{{sessionIndicatorMessage}}</span>\n\t<hr />\n</div>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TDCChannelSpotlightAppearance.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Common</key>\n\t<dict>\n\t\t<key>Search Field</key>\n\t\t<dict>\n\t\t\t<key>controlTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>3</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>controlTextColor</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Search Result</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<true/>\n\t\t\t<key>keyboardShortcutDeselectedOffset</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>keyboardShortcutSelectedOffset</key>\n\t\t\t<integer>3</integer>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModern</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>Common</string>\n\t\t<key>Search Field</key>\n\t\t<dict>\n\t\t\t<key>noResultsTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>3</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>secondaryLabelColor</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Search Result</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>channelNameTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.9</string>\n\t\t\t</dict>\n\t\t\t<key>channelDescriptionTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.7</string>\n\t\t\t</dict>\n\t\t\t<key>keyboardShortcutTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.9</string>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>1.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Search Result</key>\n\t\t<dict>\n\t\t\t<key>channelNameTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.25</string>\n\t\t\t</dict>\n\t\t\t<key>channelDescriptionTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.35</string>\n\t\t\t</dict>\n\t\t\t<key>keyboardShortcutTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.25</string>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>1.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>BigSurDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernDark</string>\n\t</dict>\n\t<key>BigSurLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernLight</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TDCChannelSpotlightAppearanceTemplate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TEMPLATE APPEARANCE (NOT USED BY ANYTHING)</key>\n\t<dict>\n\t\t<key>Search Field</key>\n\t\t<dict>\n\t\t\t<key>controlTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>completionTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>noResultsTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Search Result</key>\n\t\t<dict>\n\t\t\t<key>selectionColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>channelNameTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>channelDescriptionTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>keyboardShortcutTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>keyboardShortcutDeselectedOffset</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>keyboardShortcutSelectedOffset</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMainWindowAppearance.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Common</key>\n\t<dict>\n\t\t<key>titlebarAccessoryViewLeftMargin</key>\n\t\t<integer>3</integer>\n\t\t<key>titlebarAccessoryViewRightMargin</key>\n\t\t<integer>5</integer>\n\t\t<key>channelViewOverlayDefaultBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.3</string>\n\t\t\t</dict>\n\t\t\t<key>inactiveWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.3</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>defaultWindowSize</key>\n\t\t<dict>\n\t\t\t<key>width</key>\n\t\t\t<real>800</real>\n\t\t\t<key>height</key>\n\t\t\t<real>474</real>\n\t\t</dict>\n\t\t<key>splitViewDividerColor</key>\n\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<integer>1</integer>\n\t\t\t<key>value</key>\n\t\t\t<string>0.65</string>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModern</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>Common</string>\n\t\t<key>titlebarAccessoryViewBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.462 0.462 0.462</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>loadingScreenBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<integer>3</integer>\n\t\t\t<key>value</key>\n\t\t\t<string>windowBackgroundColor</string>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>loadingScreenBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<integer>1</integer>\n\t\t\t<key>value</key>\n\t\t\t<string>1.0</string>\n\t\t</dict>\n\t</dict>\n\t<key>BigSurDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernDark</string>\n\t</dict>\n\t<key>BigSurLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernLight</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMainWindowAppearanceTemplate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TEMPLATE APPEARANCE (NOT USED BY ANYTHING)</key>\n\t<dict>\n\t\t<key>channelViewOverlayDefaultBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>inactiveWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>defaultWindowSize</key>\n\t\t<dict>\n\t\t\t<key>width</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>height</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t\t<key>loadingScreenBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<integer>2</integer>\n\t\t\t<key>value</key>\n\t\t\t<string>0.0 0.0 0.0</string>\n\t\t</dict>\n\t\t<key>splitViewDividerColor</key>\n\t\t<dict>\n\t\t\t<key>type</key>\n\t\t\t<integer>2</integer>\n\t\t\t<key>value</key>\n\t\t\t<string>0.0 0.0 0.0</string>\n\t\t</dict>\n\t\t<key>titlebarAccessoryViewBackgroundColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>inactiveWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>titlebarAccessoryViewLeftMargin</key>\n\t\t<integer>0</integer>\n\t\t<key>titlebarAccessoryViewRightMargin</key>\n\t\t<integer>0</integer>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMainWindowTextViewAppearance.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Common</key>\n\t<dict>\n\t\t<key>Text View</key>\n\t\t<dict>\n\t\t\t<key>inset</key>\n\t\t\t<dict>\n\t\t\t\t<key>width</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>height</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Background View</key>\n\t\t<dict>\n\t\t\t<key>contentBorderPadding</key>\n\t\t\t<integer>23</integer>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModern</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>Common</string>\n\t\t<key>Text View</key>\n\t\t<dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontLarge</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>14</integer>\n\t\t\t</dict>\n\t\t\t<key>fontExtraLarge</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>16</integer>\n\t\t\t</dict>\n\t\t\t<key>fontHumongous</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>24</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Background View</key>\n\t\t<dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.248 0.248 0.248</string>\n\t\t\t</dict>\n\t\t\t<key>dividerColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.150 0.150 0.150</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Text View</key>\n\t\t<dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>1.0</string>\n\t\t\t</dict>\n\t\t\t<key>placeholderTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.660 0.660 0.660</string>\n\t\t\t</dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.386 0.386 0.386</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.386 0.386 0.386</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outsidePrimaryShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.10</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.10</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outsidePrimaryShadowColor@2x</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.15</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.15</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Background View</key>\n\t\t<dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.957 0.957 0.957</string>\n\t\t\t</dict>\n\t\t\t<key>dividerColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.65</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Text View</key>\n\t\t<dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.15</string>\n\t\t\t</dict>\n\t\t\t<key>placeholderTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>1</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.50</string>\n\t\t\t</dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>insideShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>insideGradient</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<array>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.992 0.992 0.992</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.988 0.988 0.988</string>\n\t\t\t\t\t</dict>\n\t\t\t\t</array>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<array>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.992 0.992 0.992</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.988 0.988 0.988</string>\n\t\t\t\t\t</dict>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t\t<key>outsidePrimaryShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.15</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.15</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outsideSecondaryShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.10</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.10</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outsideSecondaryShadowColor@2x</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.06</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.06</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>BigSurDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernDark</string>\n\t</dict>\n\t<key>BigSurLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernLight</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMainWindowTextViewAppearanceTemplate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TEMPLATE APPEARANCE (NOT USED BY ANYTHING)</key>\n\t<dict>\n\t\t<key>Background View</key>\n\t\t<dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>dividerColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>contentBorderPadding</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t\t<key>Text View</key>\n\t\t<dict>\n\t\t\t<key>inset</key>\n\t\t\t<dict>\n\t\t\t\t<key>width</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t\t<key>height</key>\n\t\t\t\t<integer>0</integer>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>placeholderTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>backgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outlineColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>insideShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>insideGradient</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<array>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t\t</dict>\n\t\t\t\t</array>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<array>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t\t</dict>\n\t\t\t\t\t<dict>\n\t\t\t\t\t\t<key>type</key>\n\t\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t\t<key>value</key>\n\t\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t\t</dict>\n\t\t\t\t</array>\n\t\t\t</dict>\n\t\t\t<key>outsidePrimaryShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>outsideSecondaryShadowColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontLarge</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontExtraLarge</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontHumongous</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMemberListAppearance.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Common</key>\n\t<dict>\n\t\t<key>defaultWidth</key>\n\t\t<integer>120</integer>\n\t\t<key>minimumWidth</key>\n\t\t<integer>120</integer>\n\t\t<key>maximumWidth</key>\n\t\t<integer>300</integer>\n\t\t<key>Mark Badge</key>\n\t\t<dict>\n\t\t\t<key>leftMargin</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t\t<key>Member Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<true/>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModern</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>Common</string>\n\t\t<key>Member Cell</key>\n\t\t<dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Mark Badge</key>\n\t\t<dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>Helvetica</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t\t<key>weight</key>\n\t\t\t\t<integer>15</integer>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>Helvetica</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t\t<key>weight</key>\n\t\t\t\t<integer>15</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Member Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>awayTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Mark Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.15</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.15</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.1 0.1 0.1</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.1 0.1 0.1</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Member Cell</key>\n\t\t<dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>awayTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Mark Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232 0.7</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232 0.7</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>BigSurDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernDark</string>\n\t</dict>\n\t<key>BigSurLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernLight</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCMemberListAppearanceTemplate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TEMPLATE APPEARANCE (NOT USED BY ANYTHING)</key>\n\t<dict>\n\t\t<key>defaultWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>minimumWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>maximumWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>selectionColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>inactiveWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>User Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>awayTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Mark Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>name</key>\n\t\t\t\t\t<string>System</string>\n\t\t\t\t\t<key>size</key>\n\t\t\t\t\t<real>10</real>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>leftMargin</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCServerListAppearance.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Common</key>\n\t<dict>\n\t\t<key>defaultWidth</key>\n\t\t<integer>190</integer>\n\t\t<key>minimumWidth</key>\n\t\t<integer>120</integer>\n\t\t<key>maximumWidth</key>\n\t\t<integer>300</integer>\n\t\t<key>Server Cell</key>\n\t\t<dict>\n\t\t\t<key>labelLeftMargin</key>\n\t\t\t<string>5</string>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<key>Channel Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<true/>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModern</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>Common</string>\n\t\t<key>Server Cell</key>\n\t\t<dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>SystemBold</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>14</integer>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>14</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Channel Cell</key>\n\t\t<dict>\n\t\t\t<key>rowHeight</key>\n\t\t\t<integer>20</integer>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>12</integer>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Unread Badge</key>\n\t\t<dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>SystemMonospace</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>11</integer>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>SystemMonospace</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<integer>11</integer>\n\t\t\t</dict>\n\t\t\t<key>minimumWidth</key>\n\t\t\t<integer>22</integer>\n\t\t\t<key>height</key>\n\t\t\t<integer>14</integer>\n\t\t\t<key>padding</key>\n\t\t\t<integer>6</integer>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Server Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Channel Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.9</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.4</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>erroneousTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.85 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.85 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Unread Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.15</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.15</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0117 0.1562 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0117 0.1562 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.1 0.1 0.1</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.1 0.1 0.1</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>CommonModernLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModern</string>\n\t\t<key>Server Cell</key>\n\t\t<dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Channel Cell</key>\n\t\t<dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.25</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.55</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>erroneousTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.8203 0.0585 0.0585</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.8203 0.0585 0.0585</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Unread Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232 0.7</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232 0.7</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117 0.7</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.414 0.117 0.7</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.232 0.232 0.232</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>1.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t</dict>\n\t</dict>\n\t<key>BigSurDark</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernDark</string>\n\t</dict>\n\t<key>BigSurLight</key>\n\t<dict>\n\t\t<key>inheritFrom</key>\n\t\t<string>CommonModernLight</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/Appearance/TVCServerListAppearanceTemplate.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>TEMPLATE APPEARANCE (NOT USED BY ANYTHING)</key>\n\t<dict>\n\t\t<key>defaultWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>minimumWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>maximumWidth</key>\n\t\t<integer>0</integer>\n\t\t<key>selectionColor</key>\n\t\t<dict>\n\t\t\t<key>activeWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t\t<key>inactiveWindow</key>\n\t\t\t<dict>\n\t\t\t\t<key>type</key>\n\t\t\t\t<integer>2</integer>\n\t\t\t\t<key>value</key>\n\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Server Cell</key>\n\t\t<dict>\n\t\t\t<key>labelLeftMargin</key>\n\t\t\t<string>0</string>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>selectionImage</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string></string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string></string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Channel Cell</key>\n\t\t<dict>\n\t\t\t<key>rowEmphasized</key>\n\t\t\t<false/>\n\t\t\t<key>selectionImage</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string></string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>1</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string></string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>disabledTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>erroneousTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<key>Unread Badge</key>\n\t\t<dict>\n\t\t\t<key>normalBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightBackgroundColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>normalTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>selectedTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>highlightTextColor</key>\n\t\t\t<dict>\n\t\t\t\t<key>activeWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t\t<key>inactiveWindow</key>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>type</key>\n\t\t\t\t\t<integer>2</integer>\n\t\t\t\t\t<key>value</key>\n\t\t\t\t\t<string>0.0 0.0 0.0</string>\n\t\t\t\t</dict>\n\t\t\t</dict>\n\t\t\t<key>font</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t\t<key>fontSelected</key>\n\t\t\t<dict>\n\t\t\t\t<key>name</key>\n\t\t\t\t<string>System</string>\n\t\t\t\t<key>size</key>\n\t\t\t\t<real>10</real>\n\t\t\t</dict>\n\t\t\t<key>minimumWidth</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>height</key>\n\t\t\t<integer>0</integer>\n\t\t\t<key>padding</key>\n\t\t\t<integer>0</integer>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCAboutDialog.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"32700.99.1234\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"22690\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCAboutDialog\">\n            <connections>\n                <outlet property=\"versionInfoTextField\" destination=\"7\" id=\"ag2-GR-UdV\"/>\n                <outlet property=\"window\" destination=\"1\" id=\"25\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" id=\"1\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"1150\" y=\"679\" width=\"218\" height=\"244\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"2\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"219\" height=\"244\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3\">\n                        <rect key=\"frame\" x=\"61\" y=\"126\" width=\"98\" height=\"98\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"98\" id=\"3Sc-S8-gQx\"/>\n                            <constraint firstAttribute=\"width\" secondItem=\"3\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"kTe-n6-mhN\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"4\"/>\n                        <accessibility description=\"Logo Image\"/>\n                    </imageView>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5\">\n                        <rect key=\"frame\" x=\"80\" y=\"91\" width=\"59\" height=\"17\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Textual\" id=\"6\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"14\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7\">\n                        <rect key=\"frame\" x=\"34\" y=\"69\" width=\"151\" height=\"14\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Version 1.0.0 (Build #2335)\" id=\"8\">\n                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <accessibility description=\"Version Information\"/>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"40\">\n                        <rect key=\"frame\" x=\"42\" y=\"18\" width=\"135\" height=\"23\"/>\n                        <buttonCell key=\"cell\" type=\"roundTextured\" title=\"Acknowledgements\" bezelStyle=\"texturedRounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"41\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Acknowledgements\"/>\n                        <connections>\n                            <action selector=\"displayAcknowledgements:\" target=\"-2\" id=\"44\"/>\n                        </connections>\n                    </button>\n                    <button hidden=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MDL-oh-scd\">\n                        <rect key=\"frame\" x=\"219\" y=\"244\" width=\"0.0\" height=\"0.0\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"rounded\" alignment=\"center\" controlSize=\"mini\" transparent=\"YES\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"jdf-Pe-UVP\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"miniSystem\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" id=\"1mp-AV-yTo\"/>\n                            <constraint firstAttribute=\"width\" id=\"bRH-ja-pvz\"/>\n                        </constraints>\n                        <accessibility description=\"Close\"/>\n                        <connections>\n                            <action selector=\"performClose:\" target=\"1\" id=\"JxN-mK-MTd\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"7\" firstAttribute=\"centerX\" secondItem=\"2\" secondAttribute=\"centerX\" id=\"7dc-DM-OhA\"/>\n                    <constraint firstItem=\"7\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" constant=\"36\" id=\"GAj-ND-D6P\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"centerX\" secondItem=\"2\" secondAttribute=\"centerX\" id=\"Gmx-1B-Kee\"/>\n                    <constraint firstItem=\"MDL-oh-scd\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" id=\"I2h-px-ym1\"/>\n                    <constraint firstItem=\"5\" firstAttribute=\"top\" secondItem=\"3\" secondAttribute=\"bottom\" constant=\"18\" id=\"LqP-v5-xwR\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"MDL-oh-scd\" secondAttribute=\"trailing\" id=\"Oda-rS-ckT\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"TSu-8F-A7d\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"40\" secondAttribute=\"bottom\" constant=\"20\" symbolic=\"YES\" id=\"VzH-QN-2U2\"/>\n                    <constraint firstItem=\"40\" firstAttribute=\"centerX\" secondItem=\"2\" secondAttribute=\"centerX\" id=\"cgP-eI-aZl\"/>\n                    <constraint firstItem=\"7\" firstAttribute=\"top\" secondItem=\"5\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"eHu-4Q-o7e\"/>\n                    <constraint firstItem=\"5\" firstAttribute=\"centerX\" secondItem=\"2\" secondAttribute=\"centerX\" id=\"vBb-oA-EXK\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"27\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"31\" y=\"126\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCAddressBookSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCAddressBookSheet\">\n            <connections>\n                <outlet property=\"ignoreClientToClientProtocolCheck\" destination=\"dej-2i-HSG\" id=\"FzP-Lw-FT4\"/>\n                <outlet property=\"ignoreEntryHostmaskTextField\" destination=\"298\" id=\"8f4-Xr-W55\"/>\n                <outlet property=\"ignoreEntrySaveButton\" destination=\"485\" id=\"5P8-TR-FGV\"/>\n                <outlet property=\"ignoreEntryView\" destination=\"5\" id=\"nse-Nb-KaW\"/>\n                <outlet property=\"ignoreFileTransferRequestsCheck\" destination=\"FDs-Jz-PlJ\" id=\"xHx-kw-Fld\"/>\n                <outlet property=\"ignoreGeneralEventMessagesCheck\" destination=\"ywn-9P-Z6q\" id=\"D3U-RV-9bp\"/>\n                <outlet property=\"ignoreNoticeMessagesCheck\" destination=\"w5b-xP-tx9\" id=\"5tq-MJ-NU6\"/>\n                <outlet property=\"ignorePrivateMessageHighlightsCheck\" destination=\"sz9-Gj-RT4\" id=\"gzf-1U-oMj\"/>\n                <outlet property=\"ignorePrivateMessagesCheck\" destination=\"3jI-d3-bSu\" id=\"dbw-ny-qVf\"/>\n                <outlet property=\"ignorePublicMessageHighlightsCheck\" destination=\"ox2-rB-9ub\" id=\"DqH-bU-huS\"/>\n                <outlet property=\"ignorePublicMessagesCheck\" destination=\"ttJ-cs-J1G\" id=\"n4n-NM-Fw4\"/>\n                <outlet property=\"trackUserActivityCheck\" destination=\"563\" id=\"grh-lc-kQW\"/>\n                <outlet property=\"userTrackingEntryNicknameTextField\" destination=\"540\" id=\"D8Q-7L-BBk\"/>\n                <outlet property=\"userTrackingEntrySaveButton\" destination=\"529\" id=\"kqV-8E-4oZ\"/>\n                <outlet property=\"userTrackingEntryView\" destination=\"521\" id=\"7Q7-Zg-oll\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"521\" userLabel=\"Notify User Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"1015\" y=\"629\" width=\"370\" height=\"291\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"522\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"370\" height=\"291\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"539\">\n                        <rect key=\"frame\" x=\"18\" y=\"228\" width=\"334\" height=\"5\"/>\n                    </box>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"531\">\n                        <rect key=\"frame\" x=\"18\" y=\"58\" width=\"334\" height=\"5\"/>\n                    </box>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"530\">\n                        <rect key=\"frame\" x=\"219\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"551\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"589\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"529\">\n                        <rect key=\"frame\" x=\"293\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"552\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"586\"/>\n                        </connections>\n                    </button>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"563\">\n                        <rect key=\"frame\" x=\"29\" y=\"195\" width=\"310\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Display message when user becomes available\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"564\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"566\">\n                        <rect key=\"frame\" x=\"18\" y=\"175\" width=\"334\" height=\"5\"/>\n                    </box>\n                    <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" allowsMagnification=\"YES\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cib-aW-lDk\">\n                        <rect key=\"frame\" x=\"22\" y=\"79\" width=\"326\" height=\"80\"/>\n                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"LME-Ik-P6C\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"326\" height=\"80\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" allowsNonContiguousLayout=\"YES\" spellingCorrection=\"YES\" id=\"TVw-lr-Mo6\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"326\" height=\"80\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"326\" height=\"80\"/>\n                                    <size key=\"maxSize\" width=\"463\" height=\"10000000\"/>\n                                    <attributedString key=\"textStorage\">\n                                        <fragment content=\"Info:\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment>\n                                            <string key=\"content\"> Textual monitors Join, Part, and Quit activity on channels in which you are present to establish the activity pattern of someone that you would like to track. On servers that support it, Textual will also use commands such as </string>\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"ISON, MONITOR\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\" or \">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"WATCH\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\" to check the status of the person, even if you are not in the same channels.\">\n                                            <attributes>\n                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            </attributes>\n                                        </fragment>\n                                    </attributedString>\n                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"gki-G1-LfW\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"JIv-3f-fW9\">\n                            <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"541\">\n                        <rect key=\"frame\" x=\"14\" y=\"253\" width=\"68\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Nickname:\" id=\"542\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"540\" customClass=\"TVCValidatedTextField\">\n                        <rect key=\"frame\" x=\"88\" y=\"249\" width=\"266\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"Og3-X2-Mmk\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Enter any nickname to track\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"543\" customClass=\"TVCValidatedTextFieldCell\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"0.0\" colorSpace=\"deviceWhite\"/>\n                        </textFieldCell>\n                        <connections>\n                            <accessibilityConnection property=\"title\" destination=\"541\" id=\"TiN-Rr-XgG\"/>\n                        </connections>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"530\" firstAttribute=\"firstBaseline\" secondItem=\"529\" secondAttribute=\"firstBaseline\" id=\"5TE-1o-2Bb\"/>\n                    <constraint firstItem=\"cib-aW-lDk\" firstAttribute=\"centerX\" secondItem=\"522\" secondAttribute=\"centerX\" id=\"6px-w5-hqR\"/>\n                    <constraint firstItem=\"541\" firstAttribute=\"leading\" secondItem=\"522\" secondAttribute=\"leading\" constant=\"16\" id=\"78W-k0-oEv\"/>\n                    <constraint firstItem=\"539\" firstAttribute=\"trailing\" secondItem=\"566\" secondAttribute=\"trailing\" id=\"8be-Ag-J3c\"/>\n                    <constraint firstItem=\"541\" firstAttribute=\"firstBaseline\" secondItem=\"540\" secondAttribute=\"firstBaseline\" id=\"BML-2Z-O9h\"/>\n                    <constraint firstItem=\"540\" firstAttribute=\"leading\" secondItem=\"541\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"BRT-6z-UXD\"/>\n                    <constraint firstItem=\"cib-aW-lDk\" firstAttribute=\"top\" secondItem=\"566\" secondAttribute=\"bottom\" constant=\"18\" id=\"CND-X2-iht\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"529\" secondAttribute=\"bottom\" constant=\"20\" id=\"D81-r8-qwC\"/>\n                    <constraint firstItem=\"539\" firstAttribute=\"centerX\" secondItem=\"522\" secondAttribute=\"centerX\" id=\"Eyr-Rp-gM2\"/>\n                    <constraint firstItem=\"540\" firstAttribute=\"top\" secondItem=\"522\" secondAttribute=\"top\" constant=\"20\" id=\"FC0-Vk-6Ny\"/>\n                    <constraint firstItem=\"566\" firstAttribute=\"top\" secondItem=\"563\" secondAttribute=\"bottom\" constant=\"18\" id=\"HPr-d0-cZi\"/>\n                    <constraint firstItem=\"539\" firstAttribute=\"leading\" secondItem=\"522\" secondAttribute=\"leading\" constant=\"18\" id=\"KiF-Mc-9Go\"/>\n                    <constraint firstItem=\"531\" firstAttribute=\"top\" secondItem=\"cib-aW-lDk\" secondAttribute=\"bottom\" constant=\"18\" id=\"LD7-yH-xnD\"/>\n                    <constraint firstItem=\"563\" firstAttribute=\"centerX\" secondItem=\"522\" secondAttribute=\"centerX\" id=\"Mhl-V7-gtc\"/>\n                    <constraint firstItem=\"531\" firstAttribute=\"trailing\" secondItem=\"566\" secondAttribute=\"trailing\" id=\"Na2-6Y-5je\"/>\n                    <constraint firstItem=\"cib-aW-lDk\" firstAttribute=\"leading\" secondItem=\"522\" secondAttribute=\"leading\" constant=\"22\" id=\"RmV-MK-Wvn\"/>\n                    <constraint firstItem=\"529\" firstAttribute=\"top\" secondItem=\"531\" secondAttribute=\"bottom\" constant=\"20\" id=\"SaV-ZQ-KqQ\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"529\" secondAttribute=\"trailing\" constant=\"20\" id=\"T2U-sC-OFF\"/>\n                    <constraint firstItem=\"563\" firstAttribute=\"top\" secondItem=\"539\" secondAttribute=\"bottom\" constant=\"18\" id=\"WYl-yw-Thm\"/>\n                    <constraint firstItem=\"566\" firstAttribute=\"leading\" secondItem=\"531\" secondAttribute=\"leading\" id=\"eMH-RC-67j\"/>\n                    <constraint firstItem=\"563\" firstAttribute=\"leading\" secondItem=\"522\" secondAttribute=\"leading\" constant=\"31\" id=\"ffJ-Tt-d8B\"/>\n                    <constraint firstItem=\"530\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"522\" secondAttribute=\"leading\" constant=\"20\" id=\"jwl-LH-S0M\"/>\n                    <constraint firstItem=\"566\" firstAttribute=\"leading\" secondItem=\"539\" secondAttribute=\"leading\" id=\"m1B-Qr-LlP\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"540\" secondAttribute=\"trailing\" constant=\"16\" id=\"mMG-EG-2oB\"/>\n                    <constraint firstItem=\"539\" firstAttribute=\"top\" secondItem=\"540\" secondAttribute=\"bottom\" constant=\"18\" id=\"qrc-NA-9o4\"/>\n                    <constraint firstItem=\"529\" firstAttribute=\"leading\" secondItem=\"530\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"xPS-99-XYL\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"561\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"830\" y=\"243\"/>\n        </window>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Ignore User Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"407\" y=\"164\" width=\"526\" height=\"378\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"534\" height=\"378\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"298\" customClass=\"TVCValidatedTextField\">\n                        <rect key=\"frame\" x=\"93\" y=\"336\" width=\"421\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"6mg-Iy-kVt\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Enter a hostmask to ignore\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"299\" customClass=\"TVCValidatedTextFieldCell\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" white=\"1\" alpha=\"0.0\" colorSpace=\"deviceWhite\"/>\n                        </textFieldCell>\n                        <connections>\n                            <accessibilityConnection property=\"title\" destination=\"296\" id=\"orM-OL-W3d\"/>\n                        </connections>\n                    </textField>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"314\">\n                        <rect key=\"frame\" x=\"40\" y=\"227\" width=\"454\" height=\"5\"/>\n                    </box>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"632\">\n                        <rect key=\"frame\" x=\"40\" y=\"58\" width=\"454\" height=\"5\"/>\n                    </box>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PQp-5W-SVj\">\n                        <rect key=\"frame\" x=\"65\" y=\"195\" width=\"405\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Select one or more of the following items to ignore from this user:\" id=\"exY-LJ-Izn\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"296\">\n                        <rect key=\"frame\" x=\"18\" y=\"340\" width=\"69\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Hostmask:\" id=\"297\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"484\">\n                        <rect key=\"frame\" x=\"383\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"487\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"588\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"485\">\n                        <rect key=\"frame\" x=\"457\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"486\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"587\"/>\n                        </connections>\n                    </button>\n                    <gridView xPlacement=\"leading\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sN8-a1-QLi\">\n                        <rect key=\"frame\" x=\"89\" y=\"79\" width=\"356\" height=\"100\"/>\n                        <constraints>\n                            <constraint firstItem=\"dej-2i-HSG\" firstAttribute=\"leading\" secondItem=\"w5b-xP-tx9\" secondAttribute=\"trailing\" constant=\"53\" id=\"2xq-uQ-tc6\"/>\n                            <constraint firstItem=\"ttJ-cs-J1G\" firstAttribute=\"trailing\" secondItem=\"ox2-rB-9ub\" secondAttribute=\"trailing\" id=\"46e-PL-htK\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"3jI-d3-bSu\" secondAttribute=\"trailing\" constant=\"43\" id=\"7f0-LS-kj5\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"dej-2i-HSG\" secondAttribute=\"trailing\" constant=\"8\" id=\"HPe-5C-EL2\"/>\n                            <constraint firstItem=\"3jI-d3-bSu\" firstAttribute=\"trailing\" secondItem=\"sz9-Gj-RT4\" secondAttribute=\"trailing\" id=\"U98-X7-tug\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"FDs-Jz-PlJ\" secondAttribute=\"trailing\" constant=\"15\" id=\"erN-ad-VCD\"/>\n                            <constraint firstItem=\"3jI-d3-bSu\" firstAttribute=\"leading\" secondItem=\"ttJ-cs-J1G\" secondAttribute=\"trailing\" constant=\"56\" id=\"yOf-YQ-2Vc\"/>\n                        </constraints>\n                        <rows>\n                            <gridRow id=\"60g-I4-UZM\"/>\n                            <gridRow id=\"GPA-DF-G0l\"/>\n                            <gridRow id=\"5wc-DR-pnU\"/>\n                            <gridRow id=\"uuG-cG-S4B\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn id=\"RE2-kr-VyN\"/>\n                            <gridColumn id=\"MRh-9y-CGo\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"60g-I4-UZM\" column=\"RE2-kr-VyN\" id=\"JDC-Tp-9aS\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ttJ-cs-J1G\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"83\" width=\"128\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Public Messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"PzG-Hm-oqC\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"60g-I4-UZM\" column=\"MRh-9y-CGo\" id=\"yg5-tf-BQT\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3jI-d3-bSu\">\n                                    <rect key=\"frame\" x=\"180\" y=\"83\" width=\"133\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Private Messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"ZRo-uF-d94\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"GPA-DF-G0l\" column=\"RE2-kr-VyN\" id=\"xTN-yS-w3F\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"w5b-xP-tx9\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"55\" width=\"131\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Notice Messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"Ked-kr-pLR\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"GPA-DF-G0l\" column=\"MRh-9y-CGo\" id=\"Sst-OJ-aXv\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dej-2i-HSG\">\n                                    <rect key=\"frame\" x=\"180\" y=\"55\" width=\"168\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Client-to-Client (CTCP)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"PJ9-Th-HC2\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"5wc-DR-pnU\" column=\"RE2-kr-VyN\" id=\"NEt-QC-YVO\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ox2-rB-9ub\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"27\" width=\"128\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Public Highlights\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"wrU-ta-QxO\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"5wc-DR-pnU\" column=\"MRh-9y-CGo\" id=\"GZj-p4-ycj\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sz9-Gj-RT4\">\n                                    <rect key=\"frame\" x=\"180\" y=\"27\" width=\"133\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Private Highlights\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"sUM-Gf-Bag\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"uuG-cG-S4B\" column=\"RE2-kr-VyN\" id=\"3h8-Ly-dTB\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ywn-9P-Z6q\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"176\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"General Event Messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"qWA-65-snn\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"uuG-cG-S4B\" column=\"MRh-9y-CGo\" id=\"wfQ-md-bgu\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FDs-Jz-PlJ\">\n                                    <rect key=\"frame\" x=\"180\" y=\"-1\" width=\"161\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"File Transfer Requests\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"9mI-qk-w7S\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                </button>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                    <gridView xPlacement=\"leading\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"0.0\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tB2-1G-iBQ\">\n                        <rect key=\"frame\" x=\"76\" y=\"248\" width=\"382\" height=\"72\"/>\n                        <rows>\n                            <gridRow bottomPadding=\"2\" id=\"Kpp-Bb-tZs\"/>\n                            <gridRow id=\"B8x-hc-NKZ\"/>\n                            <gridRow id=\"cd4-bz-1Dn\"/>\n                            <gridRow id=\"GWF-7M-PGa\"/>\n                            <gridRow id=\"ipg-pN-zE1\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn xPlacement=\"trailing\" id=\"gXI-5Z-cSP\"/>\n                            <gridColumn id=\"S1x-gJ-amK\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"Kpp-Bb-tZs\" column=\"gXI-5Z-cSP\" id=\"Iwi-t9-9op\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cG4-7I-vs2\">\n                                    <rect key=\"frame\" x=\"19\" y=\"58\" width=\"48\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" alignment=\"right\" title=\"Format:\" id=\"6s6-vf-tWd\">\n                                        <font key=\"font\" metaFont=\"smallSystemBold\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"Kpp-Bb-tZs\" column=\"S1x-gJ-amK\" id=\"fKU-DX-NXv\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NBG-sm-fcb\">\n                                    <rect key=\"frame\" x=\"69\" y=\"58\" width=\"204\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" title=\"&lt;nickname&gt;!&lt;username&gt;@&lt;address&gt;\" id=\"10i-MR-fkD\">\n                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"B8x-hc-NKZ\" column=\"gXI-5Z-cSP\" id=\"acK-2F-ExI\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OjV-Aj-wiQ\">\n                                    <rect key=\"frame\" x=\"5\" y=\"42\" width=\"62\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" alignment=\"right\" title=\"Examples:\" id=\"NzA-7H-3Pn\">\n                                        <font key=\"font\" metaFont=\"smallSystemBold\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"B8x-hc-NKZ\" column=\"S1x-gJ-amK\" id=\"TeE-pc-TKL\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TD9-se-tAw\">\n                                    <rect key=\"frame\" x=\"69\" y=\"42\" width=\"307\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" title=\"*!*@* (matches every possible user — not recommended)\" id=\"0fp-nP-7zU\">\n                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"cd4-bz-1Dn\" column=\"gXI-5Z-cSP\" id=\"pdD-NF-0Cb\"/>\n                            <gridCell row=\"cd4-bz-1Dn\" column=\"S1x-gJ-amK\" id=\"iPw-rC-Ykd\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4U0-1G-9IA\">\n                                    <rect key=\"frame\" x=\"69\" y=\"28\" width=\"315\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" title=\"frank*!*@* (matches any nickname that starts with “frank”)\" id=\"SBB-bO-rCp\">\n                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"GWF-7M-PGa\" column=\"gXI-5Z-cSP\" id=\"swW-Lp-XMF\"/>\n                            <gridCell row=\"GWF-7M-PGa\" column=\"S1x-gJ-amK\" id=\"k1P-Q0-rMI\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fip-7x-R8J\">\n                                    <rect key=\"frame\" x=\"69\" y=\"14\" width=\"304\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" title=\"*!matt@* (matches any username that is equal to “matt”)\" id=\"18d-sU-ipn\">\n                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"ipg-pN-zE1\" column=\"gXI-5Z-cSP\" id=\"jmX-wX-8eL\"/>\n                            <gridCell row=\"ipg-pN-zE1\" column=\"S1x-gJ-amK\" id=\"6W6-Yn-nVH\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dZf-j9-oJ1\">\n                                    <rect key=\"frame\" x=\"69\" y=\"0.0\" width=\"265\" height=\"14\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" title=\"*!*@*.info (matches any address ending in “.info”)\" id=\"uSx-4A-ovI\">\n                                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"485\" secondAttribute=\"bottom\" constant=\"20\" id=\"2mU-00-1Gz\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"leading\" secondItem=\"632\" secondAttribute=\"leading\" id=\"4xj-AF-43q\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"298\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"5CL-NL-XDS\"/>\n                    <constraint firstItem=\"484\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"7mw-IS-5l0\"/>\n                    <constraint firstItem=\"485\" firstAttribute=\"top\" secondItem=\"632\" secondAttribute=\"bottom\" constant=\"20\" id=\"FAA-zB-Lq3\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"IcQ-8I-Kqb\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"top\" secondItem=\"tB2-1G-iBQ\" secondAttribute=\"bottom\" constant=\"18\" id=\"Iuj-2v-YoV\"/>\n                    <constraint firstItem=\"632\" firstAttribute=\"top\" secondItem=\"sN8-a1-QLi\" secondAttribute=\"bottom\" constant=\"18\" id=\"Lgl-Ge-q4K\"/>\n                    <constraint firstItem=\"296\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"McC-id-swD\"/>\n                    <constraint firstItem=\"tB2-1G-iBQ\" firstAttribute=\"top\" secondItem=\"298\" secondAttribute=\"bottom\" constant=\"16\" id=\"O6l-Qf-0og\"/>\n                    <constraint firstItem=\"298\" firstAttribute=\"leading\" secondItem=\"296\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"Qt2-Ua-ETG\"/>\n                    <constraint firstItem=\"sN8-a1-QLi\" firstAttribute=\"top\" secondItem=\"PQp-5W-SVj\" secondAttribute=\"bottom\" constant=\"16\" id=\"Xgm-Tr-9Cb\"/>\n                    <constraint firstItem=\"tB2-1G-iBQ\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"adg-sE-RqU\"/>\n                    <constraint firstItem=\"484\" firstAttribute=\"firstBaseline\" secondItem=\"485\" secondAttribute=\"firstBaseline\" id=\"aqO-uR-u6d\"/>\n                    <constraint firstItem=\"298\" firstAttribute=\"trailing\" secondItem=\"485\" secondAttribute=\"trailing\" id=\"bxU-xF-lBR\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"40\" id=\"esZ-o0-RHl\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"trailing\" secondItem=\"632\" secondAttribute=\"trailing\" id=\"gjC-px-aoO\"/>\n                    <constraint firstItem=\"485\" firstAttribute=\"leading\" secondItem=\"484\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"mS5-dx-ZOx\"/>\n                    <constraint firstItem=\"314\" firstAttribute=\"centerX\" secondItem=\"PQp-5W-SVj\" secondAttribute=\"centerX\" id=\"nPX-HQ-cMb\"/>\n                    <constraint firstItem=\"PQp-5W-SVj\" firstAttribute=\"top\" secondItem=\"314\" secondAttribute=\"bottom\" constant=\"18\" id=\"rKO-vO-flK\"/>\n                    <constraint firstItem=\"tB2-1G-iBQ\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"76\" id=\"rvq-sb-noz\"/>\n                    <constraint firstItem=\"296\" firstAttribute=\"firstBaseline\" secondItem=\"298\" secondAttribute=\"firstBaseline\" id=\"sfL-xB-9s5\"/>\n                    <constraint firstItem=\"sN8-a1-QLi\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"89\" id=\"wlH-Qf-TGy\"/>\n                    <constraint firstItem=\"sN8-a1-QLi\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"xnp-RT-Ft6\"/>\n                    <constraint firstItem=\"298\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"ylj-Fi-hHc\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"228\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"321\" y=\"286\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelBanListSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelBanListSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"18\" id=\"48\"/>\n                <outlet property=\"entryTable\" destination=\"6\" id=\"boK-hb-qnc\"/>\n                <outlet property=\"entryTableController\" destination=\"hp8-ig-5aL\" id=\"Lcu-2A-0jE\"/>\n                <outlet property=\"headerTitleTextField\" destination=\"33\" id=\"5Dp-6r-9Ig\"/>\n                <outlet property=\"okButton\" destination=\"18\" id=\"51\"/>\n                <outlet property=\"sheet\" destination=\"1\" id=\"52\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <arrayController objectClassName=\"TDCChannelBanListSheet\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"hp8-ig-5aL\">\n            <declaredKeys>\n                <string>entryMask</string>\n                <string>entryAuthor</string>\n                <string>entryCreationDate</string>\n                <string>entryCreationDateString</string>\n            </declaredKeys>\n        </arrayController>\n        <window allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"1\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"160\" width=\"600\" height=\"312\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <value key=\"minSize\" type=\"size\" width=\"600\" height=\"312\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"1024\" height=\"720\"/>\n            <view key=\"contentView\" id=\"2\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"312\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <scrollView wantsLayer=\"YES\" autohidesScrollers=\"YES\" horizontalLineScroll=\"18\" horizontalPageScroll=\"10\" verticalLineScroll=\"18\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"40\" width=\"600\" height=\"230\"/>\n                        <clipView key=\"contentView\" id=\"i0a-Kb-TOE\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"598\" height=\"228\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" autosaveColumns=\"NO\" rowHeight=\"16\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" headerView=\"yZO-FU-7oR\" viewBased=\"YES\" floatsGroupRows=\"NO\" id=\"6\" customClass=\"TVCBasicTableView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"598\" height=\"200\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn editable=\"NO\" width=\"335.5\" minWidth=\"40\" maxWidth=\"1000\" id=\"8\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Hostmask\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"11\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Exception Mask\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"entryMask\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8at-zo-TEe\">\n                                                    <rect key=\"frame\" x=\"11\" y=\"1\" width=\"341\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vB7-5n-Ybk\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"341\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"NwW-Wt-A8j\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"8at-zo-TEe\" name=\"value\" keyPath=\"objectValue.entryMask\" id=\"dup-ry-c3C\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"vB7-5n-Ybk\" secondAttribute=\"trailing\" constant=\"2\" id=\"Mlw-3a-pLz\"/>\n                                                        <constraint firstItem=\"vB7-5n-Ybk\" firstAttribute=\"top\" secondItem=\"8at-zo-TEe\" secondAttribute=\"top\" id=\"Vjn-gv-6Mh\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"vB7-5n-Ybk\" secondAttribute=\"bottom\" id=\"cZh-tx-Atu\"/>\n                                                        <constraint firstItem=\"vB7-5n-Ybk\" firstAttribute=\"leading\" secondItem=\"8at-zo-TEe\" secondAttribute=\"leading\" constant=\"2\" id=\"wLy-v8-JgT\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"vB7-5n-Ybk\" id=\"qOA-RJ-ogZ\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn editable=\"NO\" width=\"69.860992431640625\" minWidth=\"40\" maxWidth=\"1000\" id=\"9\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Added By\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"10\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Exception Author\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"entryAuthor\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MuH-mx-n4O\">\n                                                    <rect key=\"frame\" x=\"354.5\" y=\"1\" width=\"70\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uPS-JP-px9\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"70\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"sO7-UT-E2w\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"MuH-mx-n4O\" name=\"value\" keyPath=\"objectValue.entryAuthor\" id=\"Ae1-zG-9lR\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"uPS-JP-px9\" secondAttribute=\"trailing\" constant=\"2\" id=\"Ps6-lW-BdF\"/>\n                                                        <constraint firstItem=\"uPS-JP-px9\" firstAttribute=\"leading\" secondItem=\"MuH-mx-n4O\" secondAttribute=\"leading\" constant=\"2\" id=\"gis-hq-5jm\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"uPS-JP-px9\" secondAttribute=\"bottom\" id=\"i87-Aq-26S\"/>\n                                                        <constraint firstItem=\"uPS-JP-px9\" firstAttribute=\"top\" secondItem=\"MuH-mx-n4O\" secondAttribute=\"top\" id=\"oKZ-Qu-BjG\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"uPS-JP-px9\" id=\"G2G-1r-WWP\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn editable=\"NO\" width=\"146.95846557617188\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"12\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Date Added\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"13\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Date Added\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"entryCreationDate\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iDS-Kx-r1t\">\n                                                    <rect key=\"frame\" x=\"427.5\" y=\"1\" width=\"151\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lWl-sU-LRh\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"151\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"FIa-a0-68K\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"iDS-Kx-r1t\" name=\"value\" keyPath=\"objectValue.entryCreationDateString\" id=\"bRe-3u-Fd1\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"lWl-sU-LRh\" secondAttribute=\"trailing\" constant=\"2\" id=\"Cjc-r6-6Ri\"/>\n                                                        <constraint firstItem=\"lWl-sU-LRh\" firstAttribute=\"leading\" secondItem=\"iDS-Kx-r1t\" secondAttribute=\"leading\" constant=\"2\" id=\"IxS-uN-Gxz\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"lWl-sU-LRh\" secondAttribute=\"bottom\" id=\"Rie-3l-ltm\"/>\n                                                        <constraint firstItem=\"lWl-sU-LRh\" firstAttribute=\"top\" secondItem=\"iDS-Kx-r1t\" secondAttribute=\"top\" id=\"jAe-QO-rbs\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"lWl-sU-LRh\" id=\"Tvg-di-aBu\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <binding destination=\"hp8-ig-5aL\" name=\"content\" keyPath=\"arrangedObjects\" id=\"rEK-bW-Q17\"/>\n                                        <binding destination=\"hp8-ig-5aL\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"rEK-bW-Q17\" id=\"K2K-rN-2tG\"/>\n                                        <binding destination=\"hp8-ig-5aL\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"K2K-rN-2tG\" id=\"f8Y-fK-lUy\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"Rrg-ul-4c1\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"Rfd-3M-py9\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"5\">\n                            <rect key=\"frame\" x=\"1\" y=\"213\" width=\"598\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"4\">\n                            <rect key=\"frame\" x=\"764\" y=\"16\" width=\"15\" height=\"230\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"yZO-FU-7oR\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"598\" height=\"28\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                        <accessibility description=\"Ban Exception List\"/>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"14\">\n                        <rect key=\"frame\" x=\"13\" y=\"3\" width=\"176\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Remove Selected Items\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"15\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Remove Selected Items\"/>\n                        <connections>\n                            <action selector=\"onRemoveEntry:\" target=\"-2\" id=\"Kq0-za-W1O\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"18\">\n                        <rect key=\"frame\" x=\"518\" y=\"3\" width=\"69\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"19\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Close\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"53\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"16\">\n                        <rect key=\"frame\" x=\"416\" y=\"3\" width=\"104\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Update List\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"17\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Update List\"/>\n                        <connections>\n                            <action selector=\"onUpdate:\" target=\"-2\" id=\"55\"/>\n                        </connections>\n                    </button>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"33\">\n                        <rect key=\"frame\" x=\"18\" y=\"283\" width=\"87\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Bans for %@\" id=\"34\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mxf-43-RTj\">\n                        <rect key=\"frame\" x=\"547\" y=\"282\" width=\"35\" height=\"17\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"BjX-hz-9vr\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"1234\" id=\"VEA-PK-9MZ\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                        <connections>\n                            <binding destination=\"-2\" name=\"displayPatternValue1\" keyPath=\"self.entryCount\" id=\"KPz-a9-t0f\">\n                                <dictionary key=\"options\">\n                                    <string key=\"NSDisplayPattern\">%{value1}@ entries</string>\n                                </dictionary>\n                            </binding>\n                        </connections>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"mxf-43-RTj\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"33\" secondAttribute=\"trailing\" constant=\"20\" id=\"1iZ-r9-Lbu\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"centerX\" secondItem=\"2\" secondAttribute=\"centerX\" id=\"2Bd-76-9yw\"/>\n                    <constraint firstItem=\"14\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" constant=\"20\" id=\"6qs-wk-hLa\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" id=\"6zy-UX-gxj\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"mxf-43-RTj\" secondAttribute=\"trailing\" constant=\"20\" id=\"AZG-85-OZC\"/>\n                    <constraint firstItem=\"33\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" constant=\"20\" id=\"DZF-cq-xo9\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"top\" secondItem=\"33\" secondAttribute=\"bottom\" constant=\"13\" id=\"JB7-OU-2sj\"/>\n                    <constraint firstItem=\"18\" firstAttribute=\"top\" secondItem=\"3\" secondAttribute=\"bottom\" constant=\"10\" id=\"Shh-hn-QfD\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"18\" secondAttribute=\"bottom\" constant=\"10\" id=\"SjZ-AW-WWE\"/>\n                    <constraint firstItem=\"18\" firstAttribute=\"leading\" secondItem=\"16\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"WcY-ms-GlP\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"18\" secondAttribute=\"trailing\" constant=\"20\" id=\"iLu-la-jhn\"/>\n                    <constraint firstItem=\"16\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"14\" secondAttribute=\"trailing\" constant=\"20\" id=\"izk-DV-J5e\"/>\n                    <constraint firstItem=\"33\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" constant=\"13\" id=\"k9D-3a-TlO\"/>\n                    <constraint firstItem=\"16\" firstAttribute=\"firstBaseline\" secondItem=\"14\" secondAttribute=\"firstBaseline\" id=\"nCU-Yl-GOk\"/>\n                    <constraint firstItem=\"mxf-43-RTj\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" constant=\"13\" id=\"tLU-s9-vhb\"/>\n                    <constraint firstItem=\"18\" firstAttribute=\"firstBaseline\" secondItem=\"16\" secondAttribute=\"firstBaseline\" id=\"ulH-EH-VR5\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"47\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"573\" y=\"414\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelInviteSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelInviteSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"10\" id=\"jMs-mJ-IVv\"/>\n                <outlet property=\"channelListPopup\" destination=\"31\" id=\"44\"/>\n                <outlet property=\"headerTitleTextField\" destination=\"37\" id=\"62k-Xx-UjI\"/>\n                <outlet property=\"okButton\" destination=\"9\" id=\"45\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"22\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Sheet\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"593\" y=\"397\" width=\"300\" height=\"135\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"300\" height=\"132\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9\">\n                        <rect key=\"frame\" x=\"219\" y=\"13\" width=\"68\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Invite\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"20\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"46\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"10\">\n                        <rect key=\"frame\" x=\"145\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"21\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"30\"/>\n                        </connections>\n                    </button>\n                    <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"31\">\n                        <rect key=\"frame\" x=\"47\" y=\"55\" width=\"207\" height=\"25\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"lessThanOrEqual\" constant=\"400\" id=\"Fat-NW-5Ah\"/>\n                        </constraints>\n                        <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"32\">\n                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"menu\"/>\n                            <menu key=\"menu\" title=\"OtherViews\" id=\"33\"/>\n                        </popUpButtonCell>\n                        <accessibility description=\"Channel to Invite User(s) To\"/>\n                    </popUpButton>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"37\">\n                        <rect key=\"frame\" x=\"18\" y=\"96\" width=\"85\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Invite nick to:\" id=\"38\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"37\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"4Xv-fs-dmU\"/>\n                    <constraint firstItem=\"31\" firstAttribute=\"leading\" relation=\"lessThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"50\" id=\"5mO-rc-d5D\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"9\" secondAttribute=\"bottom\" constant=\"20\" id=\"70k-TY-70s\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"9\" secondAttribute=\"trailing\" constant=\"20\" id=\"78K-U6-aYs\"/>\n                    <constraint firstItem=\"31\" firstAttribute=\"top\" secondItem=\"37\" secondAttribute=\"bottom\" constant=\"17\" id=\"TtU-d5-tss\"/>\n                    <constraint firstItem=\"9\" firstAttribute=\"leading\" secondItem=\"10\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"TzH-YV-af9\"/>\n                    <constraint firstItem=\"31\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"b8J-9V-5ih\"/>\n                    <constraint firstItem=\"37\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"c6r-Y1-R31\"/>\n                    <constraint firstItem=\"31\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"cSI-GJ-jdQ\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"37\" secondAttribute=\"trailing\" constant=\"20\" id=\"db7-i8-IdW\"/>\n                    <constraint firstItem=\"10\" firstAttribute=\"firstBaseline\" secondItem=\"9\" secondAttribute=\"firstBaseline\" id=\"jax-td-VGr\"/>\n                    <constraint firstItem=\"10\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"utG-2r-VA0\"/>\n                    <constraint firstItem=\"9\" firstAttribute=\"top\" secondItem=\"31\" secondAttribute=\"bottom\" constant=\"19\" id=\"wxE-Vs-PUq\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"42\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"393\" y=\"153\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelModifyModesSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelModifyModesSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"64\" id=\"231\"/>\n                <outlet property=\"iCheck\" destination=\"195\" id=\"207\"/>\n                <outlet property=\"kCheck\" destination=\"82\" id=\"229\"/>\n                <outlet property=\"kText\" destination=\"62\" id=\"232\"/>\n                <outlet property=\"lCheck\" destination=\"83\" id=\"209\"/>\n                <outlet property=\"lText\" destination=\"63\" id=\"233\"/>\n                <outlet property=\"mCheck\" destination=\"197\" id=\"210\"/>\n                <outlet property=\"nCheck\" destination=\"192\" id=\"204\"/>\n                <outlet property=\"okButton\" destination=\"65\" id=\"230\"/>\n                <outlet property=\"pCheck\" destination=\"172\" id=\"203\"/>\n                <outlet property=\"sCheck\" destination=\"171\" id=\"202\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"243\"/>\n                <outlet property=\"tCheck\" destination=\"194\" id=\"205\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"639\" y=\"553\" width=\"103\" height=\"94\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"287\" height=\"320\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"62\">\n                        <rect key=\"frame\" x=\"143\" y=\"106\" width=\"124\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"5It-6s-7uW\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"213\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <allowedInputSourceLocales>\n                                <string>ti_ER</string>\n                                <string>ar_LY</string>\n                                <string>kok_IN</string>\n                                <string>mk_MK</string>\n                                <string>eo</string>\n                                <string>fr_CH</string>\n                                <string>sw</string>\n                                <string>so_ET</string>\n                                <string>gv</string>\n                                <string>ar_BH</string>\n                                <string>hy_AM_REVISED</string>\n                                <string>it_IT</string>\n                                <string>bg_BG</string>\n                                <string>ro</string>\n                                <string>es_HN</string>\n                                <string>en_BE</string>\n                                <string>is</string>\n                                <string>kw_GB</string>\n                                <string>kl</string>\n                                <string>ga_IE</string>\n                                <string>nl_NL</string>\n                                <string>uk</string>\n                                <string>fr_CA</string>\n                                <string>sk_SK</string>\n                                <string>es_AR</string>\n                                <string>en_MT</string>\n                                <string>fr_BE</string>\n                                <string>ca</string>\n                                <string>cs_CZ</string>\n                                <string>fr_FR</string>\n                                <string>en_ZA</string>\n                                <string>sl</string>\n                                <string>fa</string>\n                                <string>so</string>\n                                <string>pt</string>\n                                <string>et_EE</string>\n                                <string>eu_ES</string>\n                                <string>fi</string>\n                                <string>de_CH</string>\n                                <string>or</string>\n                                <string>gu_IN</string>\n                                <string>mt_MT</string>\n                                <string>nb</string>\n                                <string>ms</string>\n                                <string>es_CR</string>\n                                <string>as_IN</string>\n                                <string>ar_SA</string>\n                                <string>am</string>\n                                <string>pl</string>\n                                <string>hu</string>\n                                <string>lv</string>\n                                <string>ar_DZ</string>\n                                <string>ur</string>\n                                <string>pt_PT</string>\n                                <string>eu</string>\n                                <string>so_DJ</string>\n                                <string>de</string>\n                                <string>en_IN</string>\n                                <string>hr_HR</string>\n                                <string>ar_AE</string>\n                                <string>gu</string>\n                                <string>lt</string>\n                                <string>te_IN</string>\n                                <string>ar_KW</string>\n                                <string>sr_Latn</string>\n                                <string>de_AT</string>\n                                <string>en_US</string>\n                                <string>es_PR</string>\n                                <string>pl_PL</string>\n                                <string>uz_Cyrl_UZ</string>\n                                <string>ar_EG</string>\n                                <string>it_CH</string>\n                                <string>nl</string>\n                                <string>haw_US</string>\n                                <string>is_IS</string>\n                                <string>en_IE</string>\n                                <string>kl_GL</string>\n                                <string>ps</string>\n                                <string>zh_Hans_CN</string>\n                                <string>ar</string>\n                                <string>ru_UA</string>\n                                <string>th_TH</string>\n                                <string>fr_LU</string>\n                                <string>uz_Latn_UZ</string>\n                                <string>az</string>\n                                <string>bn_IN</string>\n                                <string>es_MX</string>\n                                <string>kk_KZ</string>\n                                <string>en_US_POSIX</string>\n                                <string>el_GR</string>\n                                <string>he</string>\n                                <string>es_UY</string>\n                                <string>nn_NO</string>\n                                <string>sr</string>\n                                <string>sk</string>\n                                <string>ur_PK</string>\n                                <string>es_PA</string>\n                                <string>sv_FI</string>\n                                <string>zh</string>\n                                <string>es_DO</string>\n                                <string>en_CA</string>\n                                <string>en_BW</string>\n                                <string>de_DE</string>\n                                <string>haw</string>\n                                <string>pa_IN</string>\n                                <string>sq</string>\n                                <string>kw</string>\n                                <string>ga</string>\n                                <string>ml</string>\n                                <string>mt</string>\n                                <string>af_ZA</string>\n                                <string>az_Latn</string>\n                                <string>ko_KR</string>\n                                <string>fa_AF</string>\n                                <string>ps_AF</string>\n                                <string>be_BY</string>\n                                <string>bn</string>\n                                <string>it</string>\n                                <string>sr_Latn_CS</string>\n                                <string>zh_Hans</string>\n                                <string>as</string>\n                                <string>ms_MY</string>\n                                <string>be</string>\n                                <string>sl_SI</string>\n                                <string>fa_IR</string>\n                                <string>es_EC</string>\n                                <string>kok</string>\n                                <string>es_PY</string>\n                                <string>ta_IN</string>\n                                <string>am_ET</string>\n                                <string>es_CO</string>\n                                <string>uz_Latn</string>\n                                <string>el</string>\n                                <string>zh_Hant_MO</string>\n                                <string>kk</string>\n                                <string>kn</string>\n                                <string>zh_Hant</string>\n                                <string>en</string>\n                                <string>es_PE</string>\n                                <string>pt_BR</string>\n                                <string>ar_LB</string>\n                                <string>en_NZ</string>\n                                <string>es_ES</string>\n                                <string>en_HK</string>\n                                <string>es_BO</string>\n                                <string>hu_HU</string>\n                                <string>sr_Cyrl</string>\n                                <string>nb_NO</string>\n                                <string>sv</string>\n                                <string>vi</string>\n                                <string>ti_ET</string>\n                                <string>bg</string>\n                                <string>om</string>\n                                <string>de_LU</string>\n                                <string>en_SG</string>\n                                <string>id_ID</string>\n                                <string>ur_IN</string>\n                                <string>uz</string>\n                                <string>da</string>\n                                <string>ru_RU</string>\n                                <string>es_US</string>\n                                <string>es_VE</string>\n                                <string>ko</string>\n                                <string>ja</string>\n                                <string>af</string>\n                                <string>ar_YE</string>\n                                <string>lt_LT</string>\n                                <string>om_KE</string>\n                                <string>zh_Hans_SG</string>\n                                <string>es_NI</string>\n                                <string>he_IL</string>\n                                <string>en_PK</string>\n                                <string>en_PH</string>\n                                <string>az_Cyrl_AZ</string>\n                                <string>en_AU</string>\n                                <string>az_Cyrl</string>\n                                <string>ta</string>\n                                <string>ar_MA</string>\n                                <string>sw_KE</string>\n                                <string>tr_TR</string>\n                                <string>zh_Hant_HK</string>\n                                <string>en_ZW</string>\n                                <string>de_BE</string>\n                                <string>mk</string>\n                                <string>pa</string>\n                                <string>da_DK</string>\n                                <string>es_GT</string>\n                                <string>es</string>\n                                <string>ar_IQ</string>\n                                <string>az_Latn_AZ</string>\n                                <string>so_SO</string>\n                                <string>lv_LV</string>\n                                <string>mr</string>\n                                <string>te</string>\n                                <string>sq_AL</string>\n                                <string>ml_IN</string>\n                                <string>uk_UA</string>\n                                <string>hi_IN</string>\n                                <string>ca_ES</string>\n                                <string>ar_TN</string>\n                                <string>id</string>\n                                <string>om_ET</string>\n                                <string>cs</string>\n                                <string>fo_FO</string>\n                                <string>hy_AM</string>\n                                <string>en_GB</string>\n                                <string>sr_Cyrl_CS</string>\n                                <string>gl_ES</string>\n                                <string>sw_TZ</string>\n                                <string>ro_RO</string>\n                                <string>cy</string>\n                                <string>fr</string>\n                                <string>ms_BN</string>\n                                <string>so_KE</string>\n                                <string>tr</string>\n                                <string>gl</string>\n                                <string>cy_GB</string>\n                                <string>ar_OM</string>\n                                <string>fo</string>\n                                <string>es_CL</string>\n                                <string>sv_SE</string>\n                                <string>ar_JO</string>\n                                <string>uz_Cyrl</string>\n                                <string>zh_Hant_TW</string>\n                                <string>et</string>\n                                <string>hi</string>\n                                <string>fi_FI</string>\n                                <string>nn</string>\n                                <string>th</string>\n                                <string>ar_SY</string>\n                                <string>ja_JP</string>\n                                <string>gv_GB</string>\n                                <string>hy</string>\n                                <string>en_VI</string>\n                                <string>kn_IN</string>\n                                <string>ti</string>\n                                <string>ar_QA</string>\n                                <string>es_SV</string>\n                                <string>hr</string>\n                                <string>ru</string>\n                                <string>ar_SD</string>\n                                <string>mr_IN</string>\n                                <string>vi_VN</string>\n                                <string>nl_BE</string>\n                                <string>or_IN</string>\n                            </allowedInputSourceLocales>\n                        </textFieldCell>\n                        <connections>\n                            <accessibilityConnection property=\"title\" destination=\"82\" id=\"92W-GN-JbE\"/>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"ZCm-p5-p2G\"/>\n                        </connections>\n                    </textField>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"82\">\n                        <rect key=\"frame\" x=\"18\" y=\"109\" width=\"117\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Password (+k):\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"217\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\">k</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"onChangeCheck:\" target=\"-2\" id=\"239\"/>\n                        </connections>\n                    </button>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"83\">\n                        <rect key=\"frame\" x=\"18\" y=\"80\" width=\"187\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Limit number of users (+l):\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"218\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\">l</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"onChangeCheck:\" target=\"-2\" id=\"240\"/>\n                        </connections>\n                    </button>\n                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"13\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ao3-gh-ieE\">\n                        <rect key=\"frame\" x=\"20\" y=\"139\" width=\"247\" height=\"161\"/>\n                        <subviews>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"171\">\n                                <rect key=\"frame\" x=\"-2\" y=\"144\" width=\"145\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"Secret channel (+s)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"219\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">s</string>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"onChangeCheck:\" target=\"-2\" id=\"242\"/>\n                                </connections>\n                            </button>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"172\">\n                                <rect key=\"frame\" x=\"-2\" y=\"115\" width=\"149\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"Private channel (+p)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"220\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">p</string>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"onChangeCheck:\" target=\"-2\" id=\"241\"/>\n                                </connections>\n                            </button>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"192\">\n                                <rect key=\"frame\" x=\"-2\" y=\"86\" width=\"240\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"No external channel messages (+n)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"221\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">n</string>\n                                </buttonCell>\n                            </button>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"194\">\n                                <rect key=\"frame\" x=\"-2\" y=\"57\" width=\"249\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"Only operators can change topic (+t)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"222\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">t</string>\n                                </buttonCell>\n                            </button>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"195\">\n                                <rect key=\"frame\" x=\"-2\" y=\"28\" width=\"166\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"Invite-only channel (+i)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"223\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">i</string>\n                                </buttonCell>\n                            </button>\n                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"197\">\n                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"176\" height=\"18\"/>\n                                <buttonCell key=\"cell\" type=\"check\" title=\"Moderated channel (+m)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"224\">\n                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"keyEquivalent\">m</string>\n                                </buttonCell>\n                            </button>\n                        </subviews>\n                        <visibilityPriorities>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                        </visibilityPriorities>\n                        <customSpacing>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                        </customSpacing>\n                    </stackView>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"244\">\n                        <rect key=\"frame\" x=\"12\" y=\"58\" width=\"263\" height=\"5\"/>\n                    </box>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"64\">\n                        <rect key=\"frame\" x=\"136\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"215\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"235\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"65\">\n                        <rect key=\"frame\" x=\"210\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"216\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"236\"/>\n                        </connections>\n                    </button>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"63\">\n                        <rect key=\"frame\" x=\"213\" y=\"77\" width=\"54\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"bw9-zM-uph\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"right\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"214\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <allowedInputSourceLocales>\n                                <string>NSAllRomanInputSourcesLocaleIdentifier</string>\n                            </allowedInputSourceLocales>\n                        </textFieldCell>\n                        <connections>\n                            <accessibilityConnection property=\"title\" destination=\"83\" id=\"1mD-ow-koR\"/>\n                            <binding destination=\"-2\" name=\"value\" keyPath=\"self.channelUserLimitMode\" id=\"H6I-sV-jvk\">\n                                <dictionary key=\"options\">\n                                    <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                </dictionary>\n                            </binding>\n                        </connections>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"63\" firstAttribute=\"firstBaseline\" secondItem=\"83\" secondAttribute=\"firstBaseline\" id=\"0C5-7Z-38q\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"65\" secondAttribute=\"trailing\" constant=\"20\" id=\"31b-Tn-1aA\"/>\n                    <constraint firstItem=\"244\" firstAttribute=\"top\" secondItem=\"83\" secondAttribute=\"bottom\" constant=\"20\" id=\"AKK-dp-QmC\"/>\n                    <constraint firstItem=\"244\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"C9c-gD-HOc\"/>\n                    <constraint firstItem=\"ao3-gh-ieE\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"DEA-mF-Jzl\"/>\n                    <constraint firstItem=\"83\" firstAttribute=\"top\" secondItem=\"82\" secondAttribute=\"bottom\" constant=\"13\" id=\"EMN-iM-a42\"/>\n                    <constraint firstItem=\"83\" firstAttribute=\"leading\" secondItem=\"82\" secondAttribute=\"leading\" id=\"H0x-iM-6B1\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"63\" secondAttribute=\"trailing\" constant=\"20\" id=\"KTJ-36-fEU\"/>\n                    <constraint firstItem=\"244\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"12\" symbolic=\"YES\" id=\"Qjj-SA-Lqj\"/>\n                    <constraint firstItem=\"ao3-gh-ieE\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" id=\"TAp-9o-hkK\"/>\n                    <constraint firstItem=\"65\" firstAttribute=\"leading\" secondItem=\"64\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"Xqq-v8-bP3\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"62\" secondAttribute=\"trailing\" constant=\"20\" id=\"cFu-C9-88M\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ao3-gh-ieE\" secondAttribute=\"trailing\" constant=\"20\" id=\"fOh-6F-xiO\"/>\n                    <constraint firstItem=\"65\" firstAttribute=\"top\" secondItem=\"244\" secondAttribute=\"bottom\" constant=\"20\" id=\"gI8-GJ-9Bp\"/>\n                    <constraint firstItem=\"64\" firstAttribute=\"firstBaseline\" secondItem=\"65\" secondAttribute=\"firstBaseline\" id=\"gs0-4M-cEK\"/>\n                    <constraint firstItem=\"62\" firstAttribute=\"leading\" secondItem=\"82\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"hAU-RL-wdH\"/>\n                    <constraint firstItem=\"82\" firstAttribute=\"top\" secondItem=\"ao3-gh-ieE\" secondAttribute=\"bottom\" constant=\"13\" id=\"m3F-Pc-yT5\"/>\n                    <constraint firstItem=\"63\" firstAttribute=\"leading\" secondItem=\"83\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"nAp-bh-dih\"/>\n                    <constraint firstItem=\"62\" firstAttribute=\"firstBaseline\" secondItem=\"82\" secondAttribute=\"firstBaseline\" id=\"oa6-fn-qic\"/>\n                    <constraint firstItem=\"82\" firstAttribute=\"leading\" secondItem=\"ao3-gh-ieE\" secondAttribute=\"leading\" id=\"qQL-jv-Xcw\"/>\n                    <constraint firstItem=\"64\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"rhT-tV-2Bz\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"65\" secondAttribute=\"bottom\" constant=\"20\" id=\"tiR-Gc-7EK\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"228\"/>\n                <outlet property=\"initialFirstResponder\" destination=\"65\" id=\"246\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"221\" y=\"360\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelModifyTopicSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelModifyTopicSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"10\" id=\"48\"/>\n                <outlet property=\"headerTitleTextField\" destination=\"26\" id=\"ewf-vi-fnG\"/>\n                <outlet property=\"okButton\" destination=\"9\" id=\"47\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"46\"/>\n                <outlet property=\"topicValueTextField\" destination=\"40\" id=\"OZL-ug-Nin\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Sheet\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"593\" y=\"374\" width=\"600\" height=\"201\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"201\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"26\">\n                        <rect key=\"frame\" x=\"19\" y=\"165\" width=\"89\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Topic for %@:\" id=\"27\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"37\">\n                        <rect key=\"frame\" x=\"20\" y=\"63\" width=\"560\" height=\"94\"/>\n                        <clipView key=\"contentView\" id=\"KLN-Zi-fYz\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"558\" height=\"92\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView importsGraphics=\"NO\" verticallyResizable=\"YES\" continuousSpellChecking=\"YES\" allowsUndo=\"YES\" allowsNonContiguousLayout=\"YES\" smartInsertDelete=\"YES\" id=\"40\" customClass=\"TVCTextViewWithIRCFormatter\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"558\" height=\"92\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"558\" height=\"92\"/>\n                                    <size key=\"maxSize\" width=\"560\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"1bI-Ag-KTX\"/>\n                                    </connections>\n                                </textView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"94\" id=\"hRn-mc-ROH\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"39\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"38\">\n                            <rect key=\"frame\" x=\"543\" y=\"1\" width=\"16\" height=\"92\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <connections>\n                            <accessibilityConnection property=\"title\" destination=\"26\" id=\"ow9-Js-qRF\"/>\n                        </connections>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9\">\n                        <rect key=\"frame\" x=\"470\" y=\"13\" width=\"117\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Change Topic\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"20\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Change Topic\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"50\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"10\">\n                        <rect key=\"frame\" x=\"396\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"21\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"49\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"9\" secondAttribute=\"trailing\" constant=\"20\" id=\"59a-dd-1Rf\"/>\n                    <constraint firstItem=\"26\" firstAttribute=\"leading\" secondItem=\"40\" secondAttribute=\"leading\" id=\"5M7-hO-UUf\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"37\" secondAttribute=\"trailing\" constant=\"20\" id=\"No7-Wc-km1\"/>\n                    <constraint firstItem=\"26\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"40\" secondAttribute=\"trailing\" id=\"SvT-gc-Mhc\"/>\n                    <constraint firstItem=\"37\" firstAttribute=\"top\" secondItem=\"26\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"UxQ-Tf-Kqm\"/>\n                    <constraint firstItem=\"9\" firstAttribute=\"top\" secondItem=\"37\" secondAttribute=\"bottom\" constant=\"23\" id=\"Y5U-NX-EYF\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"9\" secondAttribute=\"bottom\" constant=\"20\" id=\"eem-Dd-aGC\"/>\n                    <constraint firstItem=\"10\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"hrc-7X-pfb\"/>\n                    <constraint firstItem=\"26\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"kkM-IF-4TV\"/>\n                    <constraint firstItem=\"37\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"lWD-lj-Riz\"/>\n                    <constraint firstItem=\"10\" firstAttribute=\"firstBaseline\" secondItem=\"9\" secondAttribute=\"firstBaseline\" id=\"ofe-J5-e16\"/>\n                    <constraint firstItem=\"9\" firstAttribute=\"leading\" secondItem=\"10\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"ttT-T7-e4m\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"23\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-751\" y=\"-1\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelPropertiesSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelPropertiesSheet\">\n            <connections>\n                <outlet property=\"autoJoinCheck\" destination=\"122\" id=\"332\"/>\n                <outlet property=\"cancelButton\" destination=\"p4S-DM-ZI2\" id=\"K9w-go-0a6\"/>\n                <outlet property=\"channelNameTextField\" destination=\"123\" id=\"JwL-9r-szt\"/>\n                <outlet property=\"contentView\" destination=\"187\" id=\"330\"/>\n                <outlet property=\"contentViewDefaultsView\" destination=\"243\" id=\"8M0-FU-10I\"/>\n                <outlet property=\"contentViewGeneralView\" destination=\"109\" id=\"kgV-mp-d6m\"/>\n                <outlet property=\"contentViewNotifications\" destination=\"oPK-zd-8TW\" id=\"M71-k5-KKM\"/>\n                <outlet property=\"contentViewNotificationsHost\" destination=\"khR-IQ-WtF\" id=\"cIR-2S-QWs\"/>\n                <outlet property=\"contentViewTabView\" destination=\"185\" id=\"329\"/>\n                <outlet property=\"defaultModesTextField\" destination=\"251\" id=\"kwe-lU-JDc\"/>\n                <outlet property=\"defaultTopicTextField\" destination=\"250\" id=\"Hda-fW-5nU\"/>\n                <outlet property=\"disableInlineMediaCheck\" destination=\"279\" id=\"7I7-HB-2wf\"/>\n                <outlet property=\"enableInlineMediaCheck\" destination=\"HBZ-KH-HBg\" id=\"7cz-Ws-kfR\"/>\n                <outlet property=\"ignoreGeneralEventMessagesCheck\" destination=\"281\" id=\"Nmo-db-2KD\"/>\n                <outlet property=\"ignoreHighlightsCheck\" destination=\"111\" id=\"334\"/>\n                <outlet property=\"labelTextField\" destination=\"I2R-pI-UwU\" id=\"DsP-pg-0gA\"/>\n                <outlet property=\"notificationsController\" destination=\"9qT-tK-TGk\" id=\"xgI-Z3-Unm\"/>\n                <outlet property=\"okButton\" destination=\"RKI-lY-4zM\" id=\"gk7-vj-fV9\"/>\n                <outlet property=\"pushNotificationsCheck\" destination=\"112\" id=\"333\"/>\n                <outlet property=\"secretKeyTextField\" destination=\"124\" id=\"heJ-2E-yYH\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"331\"/>\n                <outlet property=\"showTreeBadgeCountCheck\" destination=\"356\" id=\"358\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Channel Properties\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"1103\" y=\"493\" width=\"325\" height=\"496\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"325\" height=\"496\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"187\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"61\" width=\"325\" height=\"397\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"325\" id=\"Jl0-cX-I4F\"/>\n                        </constraints>\n                    </customView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RKI-lY-4zM\">\n                        <rect key=\"frame\" x=\"245\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"vut-UU-V9o\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"hND-Ui-7Ux\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p4S-DM-ZI2\">\n                        <rect key=\"frame\" x=\"174\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"3uS-Ah-Kpg\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"z8V-Ah-QUU\"/>\n                        </connections>\n                    </button>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4TH-0i-MkY\">\n                        <rect key=\"frame\" x=\"12\" y=\"58\" width=\"301\" height=\"5\"/>\n                    </box>\n                    <segmentedControl verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"185\">\n                        <rect key=\"frame\" x=\"52\" y=\"457\" width=\"222\" height=\"20\"/>\n                        <segmentedCell key=\"cell\" borderStyle=\"border\" alignment=\"left\" style=\"roundRect\" trackingMode=\"selectOne\" id=\"186\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <segments>\n                                <segment label=\"General\" selected=\"YES\"/>\n                                <segment label=\"Defaults\" tag=\"1\"/>\n                                <segment label=\"Notifications\" tag=\"2\"/>\n                            </segments>\n                        </segmentedCell>\n                        <accessibility description=\"Navigation Bar\"/>\n                        <connections>\n                            <action selector=\"onMenuBarItemChanged:\" target=\"-2\" id=\"353\"/>\n                        </connections>\n                    </segmentedControl>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"185\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"4ZR-DQ-oOY\"/>\n                    <constraint firstItem=\"187\" firstAttribute=\"top\" secondItem=\"185\" secondAttribute=\"bottom\" id=\"5AD-mn-qgo\"/>\n                    <constraint firstItem=\"185\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" id=\"8vf-wM-e5J\"/>\n                    <constraint firstItem=\"RKI-lY-4zM\" firstAttribute=\"leading\" secondItem=\"p4S-DM-ZI2\" secondAttribute=\"trailing\" constant=\"9\" id=\"Equ-64-l9C\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"185\" secondAttribute=\"trailing\" constant=\"20\" id=\"HC8-5R-AMN\"/>\n                    <constraint firstItem=\"RKI-lY-4zM\" firstAttribute=\"top\" secondItem=\"4TH-0i-MkY\" secondAttribute=\"bottom\" constant=\"20\" id=\"IbY-Qw-l7n\"/>\n                    <constraint firstItem=\"185\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"OEB-cH-fn5\"/>\n                    <constraint firstItem=\"4TH-0i-MkY\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"Q7c-g2-WTK\"/>\n                    <constraint firstItem=\"p4S-DM-ZI2\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"Ut7-4f-SlF\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"4TH-0i-MkY\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"Wid-BE-cAq\"/>\n                    <constraint firstItem=\"187\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" id=\"dqx-Ws-uBR\"/>\n                    <constraint firstItem=\"4TH-0i-MkY\" firstAttribute=\"top\" secondItem=\"187\" secondAttribute=\"bottom\" id=\"h5f-YL-65X\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"RKI-lY-4zM\" secondAttribute=\"trailing\" constant=\"23\" id=\"irU-vt-YTa\"/>\n                    <constraint firstItem=\"p4S-DM-ZI2\" firstAttribute=\"firstBaseline\" secondItem=\"RKI-lY-4zM\" secondAttribute=\"firstBaseline\" id=\"jcV-FW-iKd\"/>\n                    <constraint firstItem=\"4TH-0i-MkY\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"12\" symbolic=\"YES\" id=\"lBU-aA-TQC\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"187\" secondAttribute=\"trailing\" id=\"ryd-02-ZcK\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"RKI-lY-4zM\" secondAttribute=\"bottom\" constant=\"20\" id=\"v4F-ey-NcZ\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"354\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-303.5\" y=\"312\"/>\n        </window>\n        <view translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"109\" userLabel=\"General\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"325\" height=\"397\"/>\n            <subviews>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"122\">\n                    <rect key=\"frame\" x=\"18\" y=\"163\" width=\"123\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Join on connect\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"131\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"112\">\n                    <rect key=\"frame\" x=\"18\" y=\"133\" width=\"209\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Show notifications for channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"141\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onPushNotificationsCheckChanged:\" target=\"-2\" id=\"0C6-Nq-ny7\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"279\">\n                    <rect key=\"frame\" x=\"18\" y=\"75\" width=\"147\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Disable inline media\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"280\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"nwg-0t-IZ6\" name=\"hidden\" keyPath=\"values.DisplayEventInLogView -&gt; Inline Media\" id=\"Xat-24-Xpi\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HBZ-KH-HBg\">\n                    <rect key=\"frame\" x=\"18\" y=\"75\" width=\"135\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Show inline media\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"K3N-Px-fl5\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onInlineMediaCheckChanged:\" target=\"-2\" id=\"sZf-FM-EAV\"/>\n                        <binding destination=\"nwg-0t-IZ6\" name=\"hidden\" keyPath=\"values.DisplayEventInLogView -&gt; Inline Media\" id=\"hta-DL-5Yo\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"281\">\n                    <rect key=\"frame\" x=\"18\" y=\"46\" width=\"222\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Disable general event messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"282\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"nwg-0t-IZ6\" name=\"enabled\" keyPath=\"values.DisplayEventInLogView -&gt; Join, Part, Quit\" id=\"N9c-1s-IKF\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"312\">\n                    <rect key=\"frame\" x=\"20\" y=\"196\" width=\"285\" height=\"5\"/>\n                </box>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"356\">\n                    <rect key=\"frame\" x=\"18\" y=\"104\" width=\"230\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Show unread count in channel list\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"357\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"111\">\n                    <rect key=\"frame\" x=\"18\" y=\"17\" width=\"134\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Disable highlights\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"142\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <gridView xPlacement=\"fill\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"H9C-8w-CEX\">\n                    <rect key=\"frame\" x=\"20\" y=\"327\" width=\"285\" height=\"52\"/>\n                    <rows>\n                        <gridRow id=\"1FA-OV-nfx\"/>\n                        <gridRow id=\"oat-Nr-CCb\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"Fmr-uR-9WM\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"VpE-fp-4Wj\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"1FA-OV-nfx\" column=\"Fmr-uR-9WM\" id=\"DWR-8L-Bip\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"119\">\n                                <rect key=\"frame\" x=\"-2\" y=\"34\" width=\"66\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Name:\" id=\"134\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"1FA-OV-nfx\" column=\"VpE-fp-4Wj\" id=\"3cV-Yk-wO6\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"123\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"70\" y=\"30\" width=\"215\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"ZKF-H7-c7z\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"#example\" usesSingleLineMode=\"YES\" id=\"130\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <accessibility description=\"Channel Name\"/>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"oat-Nr-CCb\" column=\"Fmr-uR-9WM\" id=\"jrg-hM-4Y7\">\n                            <textField key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"118\">\n                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"66\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Password:\" id=\"135\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"oat-Nr-CCb\" column=\"VpE-fp-4Wj\" id=\"bK3-aF-kGN\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"124\" customClass=\"NSSecureTextField\">\n                                <rect key=\"frame\" x=\"70\" y=\"0.0\" width=\"215\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"uj9-Xy-y6u\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"129\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <accessibility description=\"Optional Channel Password\"/>\n                                <connections>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"8gk-n9-xLD\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mTi-kP-NmV\">\n                    <rect key=\"frame\" x=\"20\" y=\"306\" width=\"285\" height=\"5\"/>\n                </box>\n                <textField horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"03P-aP-ZU8\">\n                    <rect key=\"frame\" x=\"43\" y=\"274\" width=\"41\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Label:\" id=\"mot-Qn-Rih\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I2R-pI-UwU\" customClass=\"TVCValidatedTextField\">\n                    <rect key=\"frame\" x=\"90\" y=\"270\" width=\"215\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"8xO-XU-5mB\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" usesSingleLineMode=\"YES\" id=\"fvI-0j-4a5\" customClass=\"TVCValidatedTextFieldCell\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <accessibility description=\"Channel Name\"/>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PXi-i0-aN1\">\n                    <rect key=\"frame\" x=\"88\" y=\"217\" width=\"219\" height=\"45\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"When you give a channel a label, that label will appear in the Server List in lieu of the channel name.\" id=\"F9e-qw-7tY\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"PXi-i0-aN1\" firstAttribute=\"top\" secondItem=\"I2R-pI-UwU\" secondAttribute=\"bottom\" constant=\"8\" id=\"0en-XW-oHu\"/>\n                <constraint firstItem=\"281\" firstAttribute=\"top\" secondItem=\"279\" secondAttribute=\"bottom\" constant=\"13\" id=\"1hy-4M-El2\"/>\n                <constraint firstItem=\"111\" firstAttribute=\"top\" secondItem=\"281\" secondAttribute=\"bottom\" constant=\"13\" id=\"47N-xX-dHF\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"HBZ-KH-HBg\" secondAttribute=\"trailing\" constant=\"20\" id=\"6J6-r7-ohM\"/>\n                <constraint firstItem=\"279\" firstAttribute=\"leading\" secondItem=\"HBZ-KH-HBg\" secondAttribute=\"leading\" id=\"7BH-07-dda\"/>\n                <constraint firstItem=\"mTi-kP-NmV\" firstAttribute=\"leading\" secondItem=\"109\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"9gf-Ef-XZ7\"/>\n                <constraint firstItem=\"312\" firstAttribute=\"top\" secondItem=\"PXi-i0-aN1\" secondAttribute=\"bottom\" constant=\"18\" id=\"9gm-pk-kgw\"/>\n                <constraint firstItem=\"I2R-pI-UwU\" firstAttribute=\"leading\" secondItem=\"03P-aP-ZU8\" secondAttribute=\"trailing\" constant=\"8\" id=\"BlG-wo-eG6\"/>\n                <constraint firstItem=\"HBZ-KH-HBg\" firstAttribute=\"top\" secondItem=\"356\" secondAttribute=\"bottom\" constant=\"13\" id=\"DRL-ai-fSd\"/>\n                <constraint firstItem=\"mTi-kP-NmV\" firstAttribute=\"top\" secondItem=\"H9C-8w-CEX\" secondAttribute=\"bottom\" constant=\"18\" id=\"ErL-Q2-TIH\"/>\n                <constraint firstItem=\"356\" firstAttribute=\"leading\" secondItem=\"112\" secondAttribute=\"leading\" id=\"HSd-eJ-SGU\"/>\n                <constraint firstItem=\"mTi-kP-NmV\" firstAttribute=\"centerX\" secondItem=\"109\" secondAttribute=\"centerX\" id=\"I5o-hF-pWD\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"281\" secondAttribute=\"trailing\" constant=\"20\" id=\"KFT-6R-hb3\"/>\n                <constraint firstItem=\"H9C-8w-CEX\" firstAttribute=\"leading\" secondItem=\"109\" secondAttribute=\"leading\" constant=\"20\" id=\"KK8-pv-GNL\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"111\" secondAttribute=\"bottom\" constant=\"18\" id=\"NzL-uL-fla\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"356\" secondAttribute=\"trailing\" constant=\"20\" id=\"O5T-ex-QX7\"/>\n                <constraint firstItem=\"312\" firstAttribute=\"leading\" secondItem=\"mTi-kP-NmV\" secondAttribute=\"leading\" id=\"PBF-nw-WHa\"/>\n                <constraint firstItem=\"H9C-8w-CEX\" firstAttribute=\"top\" secondItem=\"109\" secondAttribute=\"top\" constant=\"18\" id=\"QOs-5X-jJd\"/>\n                <constraint firstItem=\"281\" firstAttribute=\"leading\" secondItem=\"111\" secondAttribute=\"leading\" id=\"QS5-S7-alR\"/>\n                <constraint firstItem=\"03P-aP-ZU8\" firstAttribute=\"firstBaseline\" secondItem=\"I2R-pI-UwU\" secondAttribute=\"firstBaseline\" id=\"Qd7-sb-rGN\"/>\n                <constraint firstItem=\"122\" firstAttribute=\"leading\" secondItem=\"109\" secondAttribute=\"leading\" constant=\"20\" id=\"RjM-wl-Arc\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"112\" secondAttribute=\"trailing\" constant=\"20\" id=\"SUI-An-ryT\"/>\n                <constraint firstItem=\"281\" firstAttribute=\"top\" secondItem=\"HBZ-KH-HBg\" secondAttribute=\"bottom\" constant=\"13\" id=\"TZD-aY-3pG\"/>\n                <constraint firstItem=\"PXi-i0-aN1\" firstAttribute=\"leading\" secondItem=\"I2R-pI-UwU\" secondAttribute=\"leading\" id=\"VKU-4C-RG1\"/>\n                <constraint firstItem=\"PXi-i0-aN1\" firstAttribute=\"trailing\" secondItem=\"I2R-pI-UwU\" secondAttribute=\"trailing\" id=\"Vfn-5M-c7k\"/>\n                <constraint firstItem=\"122\" firstAttribute=\"top\" secondItem=\"312\" secondAttribute=\"bottom\" constant=\"18\" id=\"Xj3-Tb-rNf\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"122\" secondAttribute=\"trailing\" constant=\"20\" id=\"Xvq-dV-1iC\"/>\n                <constraint firstItem=\"I2R-pI-UwU\" firstAttribute=\"trailing\" secondItem=\"124\" secondAttribute=\"trailing\" id=\"Z4B-Sv-pRG\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"279\" secondAttribute=\"trailing\" constant=\"20\" id=\"ZkY-cQ-hdW\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"H9C-8w-CEX\" secondAttribute=\"trailing\" constant=\"20\" id=\"cR5-mB-m9A\"/>\n                <constraint firstItem=\"112\" firstAttribute=\"top\" secondItem=\"122\" secondAttribute=\"bottom\" constant=\"14\" id=\"fG0-mc-qqN\"/>\n                <constraint firstItem=\"03P-aP-ZU8\" firstAttribute=\"trailing\" secondItem=\"118\" secondAttribute=\"trailing\" id=\"gKE-9s-5sh\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"111\" secondAttribute=\"trailing\" constant=\"20\" id=\"gwo-p9-ehm\"/>\n                <constraint firstItem=\"356\" firstAttribute=\"top\" secondItem=\"112\" secondAttribute=\"bottom\" constant=\"13\" id=\"kfe-08-tUI\"/>\n                <constraint firstItem=\"122\" firstAttribute=\"leading\" secondItem=\"112\" secondAttribute=\"leading\" id=\"luf-gJ-OyQ\"/>\n                <constraint firstItem=\"279\" firstAttribute=\"firstBaseline\" secondItem=\"HBZ-KH-HBg\" secondAttribute=\"firstBaseline\" id=\"mlP-Ky-Nmo\"/>\n                <constraint firstItem=\"279\" firstAttribute=\"leading\" secondItem=\"356\" secondAttribute=\"leading\" id=\"oAT-iQ-EKT\"/>\n                <constraint firstItem=\"03P-aP-ZU8\" firstAttribute=\"top\" secondItem=\"mTi-kP-NmV\" secondAttribute=\"bottom\" constant=\"18\" id=\"ok8-jg-8Wk\"/>\n                <constraint firstItem=\"111\" firstAttribute=\"leading\" secondItem=\"HBZ-KH-HBg\" secondAttribute=\"leading\" id=\"p1d-mW-YmE\"/>\n                <constraint firstItem=\"312\" firstAttribute=\"trailing\" secondItem=\"mTi-kP-NmV\" secondAttribute=\"trailing\" id=\"qx1-Oa-MPt\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"312\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"uPs-eG-R5D\"/>\n                <constraint firstItem=\"03P-aP-ZU8\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"109\" secondAttribute=\"leading\" constant=\"45\" id=\"umm-gE-ATw\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"74.5\" y=\"334\"/>\n        </view>\n        <view translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"243\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"325\" height=\"164\"/>\n            <subviews>\n                <gridView xPlacement=\"fill\" yPlacement=\"top\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xga-3d-zc9\">\n                    <rect key=\"frame\" x=\"24\" y=\"18\" width=\"281\" height=\"96\"/>\n                    <rows>\n                        <gridRow height=\"66\" id=\"6eM-nD-721\"/>\n                        <gridRow yPlacement=\"fill\" id=\"TU4-pw-zLI\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"bJh-ah-Qfa\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"qYY-96-IW2\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"6eM-nD-721\" column=\"bJh-ah-Qfa\" id=\"Hp6-AD-kAP\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"252\">\n                                <rect key=\"frame\" x=\"-2\" y=\"78\" width=\"49\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Topic:\" id=\"268\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"6eM-nD-721\" column=\"qYY-96-IW2\" id=\"htL-Ku-gs0\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"250\">\n                                <rect key=\"frame\" x=\"53\" y=\"30\" width=\"228\" height=\"66\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"66\" id=\"jhC-2M-Ecm\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" placeholderString=\"Optional\" drawsBackground=\"YES\" id=\"270\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <accessibility description=\"Default topic to set if channel is empty when joined.\"/>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"TU4-pw-zLI\" column=\"bJh-ah-Qfa\" id=\"jT5-tW-PDR\">\n                            <textField key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"253\">\n                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"49\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Modes:\" id=\"267\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"TU4-pw-zLI\" column=\"qYY-96-IW2\" id=\"10T-VW-vYB\">\n                            <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"251\">\n                                <rect key=\"frame\" x=\"53\" y=\"0.0\" width=\"228\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"eHf-67-hLF\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"269\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <accessibility description=\"Default set of modes to apply if channel is empty when joined.\"/>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"S13-Uc-xNq\">\n                    <rect key=\"frame\" x=\"18\" y=\"130\" width=\"241\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Values to apply if the channel is empty:\" id=\"Yvg-62-eMH\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"S13-Uc-xNq\" firstAttribute=\"leading\" secondItem=\"243\" secondAttribute=\"leading\" constant=\"20\" id=\"3V6-3T-AUc\"/>\n                <constraint firstItem=\"S13-Uc-xNq\" firstAttribute=\"top\" secondItem=\"243\" secondAttribute=\"top\" constant=\"18\" id=\"8Wp-GX-mJx\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"S13-Uc-xNq\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ppc-Ua-z6s\"/>\n                <constraint firstItem=\"xga-3d-zc9\" firstAttribute=\"leading\" secondItem=\"243\" secondAttribute=\"leading\" constant=\"24\" id=\"bOb-ob-dKc\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"xga-3d-zc9\" secondAttribute=\"trailing\" constant=\"20\" id=\"cBQ-u6-fHf\"/>\n                <constraint firstItem=\"xga-3d-zc9\" firstAttribute=\"top\" secondItem=\"S13-Uc-xNq\" secondAttribute=\"bottom\" constant=\"16\" id=\"iph-fJ-4cd\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"xga-3d-zc9\" secondAttribute=\"bottom\" constant=\"18\" id=\"zr4-Np-bYr\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"75\" y=\"691\"/>\n        </view>\n        <userDefaultsController id=\"nwg-0t-IZ6\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oPK-zd-8TW\" userLabel=\"Notifications\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"545\" height=\"314\"/>\n            <subviews>\n                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"khR-IQ-WtF\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"55\" width=\"545\" height=\"259\"/>\n                </customView>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lHS-Xe-fvm\">\n                    <rect key=\"frame\" x=\"20\" y=\"52\" width=\"505\" height=\"5\"/>\n                </box>\n                <stackView distribution=\"equalSpacing\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"4\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dMy-To-qeW\">\n                    <rect key=\"frame\" x=\"45\" y=\"20\" width=\"455\" height=\"16\"/>\n                    <subviews>\n                        <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"whp-z2-95l\">\n                            <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"211\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\"Change checkbox to mixed state (\" id=\"xfF-kd-SbM\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9Vn-4a-s97\">\n                            <rect key=\"frame\" x=\"209\" y=\"-1\" width=\"18\" height=\"18\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" secondItem=\"9Vn-4a-s97\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"49a-Ri-ybr\"/>\n                                <constraint firstAttribute=\"width\" constant=\"14\" id=\"u49-1H-oLY\"/>\n                            </constraints>\n                            <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"mixed\" allowsMixedState=\"YES\" inset=\"2\" id=\"2LJ-Lb-6HF\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                        <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aOB-2n-eI7\">\n                            <rect key=\"frame\" x=\"227\" y=\"0.0\" width=\"230\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" title=\") to revert to default, app-wide value.\" id=\"pqH-JA-zfn\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"khR-IQ-WtF\" firstAttribute=\"top\" secondItem=\"oPK-zd-8TW\" secondAttribute=\"top\" id=\"1xh-cE-SsD\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"khR-IQ-WtF\" secondAttribute=\"trailing\" id=\"CVe-jA-Bi0\"/>\n                <constraint firstItem=\"lHS-Xe-fvm\" firstAttribute=\"centerX\" secondItem=\"oPK-zd-8TW\" secondAttribute=\"centerX\" id=\"JJa-Qz-BKh\"/>\n                <constraint firstItem=\"khR-IQ-WtF\" firstAttribute=\"leading\" secondItem=\"oPK-zd-8TW\" secondAttribute=\"leading\" id=\"JpE-Eb-zee\"/>\n                <constraint firstItem=\"dMy-To-qeW\" firstAttribute=\"centerX\" secondItem=\"oPK-zd-8TW\" secondAttribute=\"centerX\" id=\"LfA-an-I6M\"/>\n                <constraint firstItem=\"lHS-Xe-fvm\" firstAttribute=\"top\" secondItem=\"khR-IQ-WtF\" secondAttribute=\"bottom\" id=\"Qyg-QX-hI9\"/>\n                <constraint firstItem=\"lHS-Xe-fvm\" firstAttribute=\"leading\" secondItem=\"oPK-zd-8TW\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"dUC-AB-VY8\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"dMy-To-qeW\" secondAttribute=\"bottom\" constant=\"20\" symbolic=\"YES\" id=\"fGW-Ml-Uv8\"/>\n                <constraint firstItem=\"dMy-To-qeW\" firstAttribute=\"top\" secondItem=\"lHS-Xe-fvm\" secondAttribute=\"bottom\" constant=\"18\" id=\"u0c-fF-T8D\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"602.5\" y=\"304\"/>\n        </customView>\n        <customObject id=\"9qT-tK-TGk\" customClass=\"TVCNotificationConfigurationViewController\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCChannelSpotlightController.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCChannelSpotlightController\">\n            <connections>\n                <outlet property=\"noResultsLabel\" destination=\"Gag-Uy-6zA\" id=\"hU8-te-kTl\"/>\n                <outlet property=\"searchField\" destination=\"1E4-kg-4iF\" id=\"bZT-CB-oym\"/>\n                <outlet property=\"searchResultsController\" destination=\"fxa-x1-fZ7\" id=\"xfS-1h-r9R\"/>\n                <outlet property=\"searchResultsTable\" destination=\"tt4-3F-bvy\" id=\"x3U-fE-QVn\"/>\n                <outlet property=\"searchResultsView\" destination=\"bUM-jd-4A3\" id=\"MHg-3d-1uU\"/>\n                <outlet property=\"searchResultsViewHeightConstraint\" destination=\"Cw6-e1-FPi\" id=\"FxS-bL-7wh\"/>\n                <outlet property=\"visualEffectView\" destination=\"OYV-WK-xFr\" id=\"0g0-4g-GG9\"/>\n                <outlet property=\"window\" destination=\"BfF-sG-KJr\" id=\"OOD-cl-eiC\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <arrayController objectClassName=\"TDCChannelSpotlightSearchResult\" editable=\"NO\" selectsInsertedObjects=\"NO\" clearsFilterPredicateOnInsertion=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"fxa-x1-fZ7\" userLabel=\"Spotlight Array Controller\">\n            <declaredKeys>\n                <string>channelName</string>\n                <string>keyboardShortcut</string>\n                <string>unreadCountDescription</string>\n            </declaredKeys>\n            <metadata>\n                <string key=\"libraryAssetSourceID\">Xcode.InterfaceBuilderKit.ClassDescriptions.Cocoa:IBLibrary-ArrayController</string>\n            </metadata>\n        </arrayController>\n        <window title=\"Channel Spotlight\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"BfF-sG-KJr\" customClass=\"TDCChannelSpotlightPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"272\" y=\"172\" width=\"600\" height=\"194\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"ibD-GT-hsB\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"194\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <visualEffectView blendingMode=\"behindWindow\" material=\"underWindowBackground\" state=\"followsWindowActiveState\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OYV-WK-xFr\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"194\"/>\n                        <subviews>\n                            <textField wantsLayer=\"YES\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1E4-kg-4iF\" customClass=\"TDCChannelSpotlightTextField\">\n                                <rect key=\"frame\" x=\"51\" y=\"150\" width=\"490\" height=\"32\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"32\" id=\"twL-Dm-bZc\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" focusRingType=\"none\" placeholderString=\"Search for channel\" usesSingleLineMode=\"YES\" id=\"xLW-8e-ask\">\n                                    <font key=\"font\" metaFont=\"systemLight\" size=\"26\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"qhU-a5-YhW\"/>\n                                </connections>\n                            </textField>\n                            <imageView wantsLayer=\"YES\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Diu-wk-ZgA\" customClass=\"TDCChannelSpotlightImageView\">\n                                <rect key=\"frame\" x=\"14\" y=\"153\" width=\"25\" height=\"25\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"25\" id=\"5AB-sj-ZrA\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"25\" id=\"r7j-gN-RHB\"/>\n                                </constraints>\n                                <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" image=\"MainWindowSpotlightIconTemplate\" id=\"p4S-0R-m2Y\"/>\n                            </imageView>\n                            <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bUM-jd-4A3\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"138\"/>\n                                <subviews>\n                                    <scrollView wantsLayer=\"YES\" borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"46\" horizontalPageScroll=\"10\" verticalLineScroll=\"46\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DH2-Zr-hDS\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"137\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"42o-5K-A7n\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"137\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" tableStyle=\"fullWidth\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" emptySelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"46\" rowSizeStyle=\"automatic\" viewBased=\"YES\" floatsGroupRows=\"NO\" id=\"tt4-3F-bvy\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"137\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedRGB\"/>\n                                                    <color key=\"gridColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedRGB\"/>\n                                                    <tableColumns>\n                                                        <tableColumn width=\"588\" minWidth=\"40\" maxWidth=\"1000\" id=\"5Rr-IZ-SKM\">\n                                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\">\n                                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </tableHeaderCell>\n                                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"Aby-dt-awg\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                            <prototypeCellViews>\n                                                                <tableCellView id=\"G8b-ye-mjd\" customClass=\"TDCChannelSpotlightSearchResultCellView\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"46\"/>\n                                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                                    <subviews>\n                                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"d8V-0z-qfJ\">\n                                                                            <rect key=\"frame\" x=\"8\" y=\"21\" width=\"255\" height=\"19\"/>\n                                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"#channel on freenode IRC network\" id=\"KNo-4X-COi\">\n                                                                                <font key=\"font\" metaFont=\"system\" size=\"16\"/>\n                                                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                            <connections>\n                                                                                <binding destination=\"G8b-ye-mjd\" name=\"value\" keyPath=\"self.channelName\" id=\"1l0-Lg-xo1\"/>\n                                                                            </connections>\n                                                                        </textField>\n                                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Js1-ti-O0L\">\n                                                                            <rect key=\"frame\" x=\"8\" y=\"7\" width=\"172\" height=\"15\"/>\n                                                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"1 unread message, 1 highlight\" id=\"P1U-vp-d2N\">\n                                                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                            <connections>\n                                                                                <binding destination=\"G8b-ye-mjd\" name=\"value\" keyPath=\"self.unreadCountDescription\" id=\"F6Q-hG-sKu\"/>\n                                                                            </connections>\n                                                                        </textField>\n                                                                        <textField verticalHuggingPriority=\"750\" verticalCompressionResistancePriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ipN-YI-lSG\">\n                                                                            <rect key=\"frame\" x=\"561\" y=\"11\" width=\"31\" height=\"24\"/>\n                                                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"⌘1\" id=\"wPt-pE-DBY\">\n                                                                                <font key=\"font\" metaFont=\"system\" size=\"20\"/>\n                                                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                            <connections>\n                                                                                <binding destination=\"G8b-ye-mjd\" name=\"value\" keyPath=\"self.keyboardShortcut\" id=\"p58-66-TYl\"/>\n                                                                            </connections>\n                                                                        </textField>\n                                                                    </subviews>\n                                                                    <constraints>\n                                                                        <constraint firstAttribute=\"trailing\" secondItem=\"ipN-YI-lSG\" secondAttribute=\"trailing\" constant=\"10\" id=\"GR1-o1-WxB\"/>\n                                                                        <constraint firstItem=\"Js1-ti-O0L\" firstAttribute=\"leading\" secondItem=\"d8V-0z-qfJ\" secondAttribute=\"leading\" id=\"HsT-0R-vWV\"/>\n                                                                        <constraint firstItem=\"d8V-0z-qfJ\" firstAttribute=\"top\" secondItem=\"G8b-ye-mjd\" secondAttribute=\"top\" constant=\"6\" id=\"Pez-e3-n1I\"/>\n                                                                        <constraint firstItem=\"ipN-YI-lSG\" firstAttribute=\"centerY\" secondItem=\"G8b-ye-mjd\" secondAttribute=\"centerY\" id=\"Q3k-vf-D5a\"/>\n                                                                        <constraint firstItem=\"ipN-YI-lSG\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Js1-ti-O0L\" secondAttribute=\"trailing\" constant=\"15\" id=\"RDu-yd-Q5y\"/>\n                                                                        <constraint firstItem=\"Js1-ti-O0L\" firstAttribute=\"top\" secondItem=\"d8V-0z-qfJ\" secondAttribute=\"bottom\" constant=\"-1\" id=\"bds-0C-hYT\"/>\n                                                                        <constraint firstItem=\"d8V-0z-qfJ\" firstAttribute=\"leading\" secondItem=\"G8b-ye-mjd\" secondAttribute=\"leading\" constant=\"10\" id=\"jsX-oK-3kx\"/>\n                                                                        <constraint firstItem=\"ipN-YI-lSG\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"d8V-0z-qfJ\" secondAttribute=\"trailing\" constant=\"15\" id=\"vNH-SU-jCE\"/>\n                                                                    </constraints>\n                                                                    <connections>\n                                                                        <outlet property=\"channelNameField\" destination=\"d8V-0z-qfJ\" id=\"i8T-hL-mg0\"/>\n                                                                        <outlet property=\"keyboardShortcutField\" destination=\"ipN-YI-lSG\" id=\"BAV-73-MA1\"/>\n                                                                        <outlet property=\"keyboardShortcutFieldOffsetConstraint\" destination=\"Q3k-vf-D5a\" id=\"cDK-tH-Pwo\"/>\n                                                                        <outlet property=\"unreadCountDescriptionField\" destination=\"Js1-ti-O0L\" id=\"NEB-2g-9vh\"/>\n                                                                    </connections>\n                                                                </tableCellView>\n                                                            </prototypeCellViews>\n                                                        </tableColumn>\n                                                    </tableColumns>\n                                                    <accessibility description=\"List of channels\"/>\n                                                    <connections>\n                                                        <binding destination=\"fxa-x1-fZ7\" name=\"content\" keyPath=\"arrangedObjects\" id=\"YXr-4Y-eSX\"/>\n                                                        <binding destination=\"fxa-x1-fZ7\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"YXr-4Y-eSX\" id=\"yHd-km-35x\"/>\n                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"S2O-kY-KVM\"/>\n                                                    </connections>\n                                                </tableView>\n                                            </subviews>\n                                            <nil key=\"backgroundColor\"/>\n                                        </clipView>\n                                        <edgeInsets key=\"contentInsets\" left=\"0.0\" right=\"0.0\" top=\"0.0\" bottom=\"0.0\"/>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"qYn-h9-uou\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"121\" width=\"600\" height=\"16\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"nKw-Rg-zxU\">\n                                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eKu-PE-56L\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"135\" width=\"600\" height=\"5\"/>\n                                    </box>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"138\" id=\"Cw6-e1-FPi\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"DH2-Zr-hDS\" secondAttribute=\"bottom\" id=\"KVE-3A-wD9\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"eKu-PE-56L\" secondAttribute=\"trailing\" id=\"Kco-5g-pnb\"/>\n                                    <constraint firstItem=\"eKu-PE-56L\" firstAttribute=\"leading\" secondItem=\"bUM-jd-4A3\" secondAttribute=\"leading\" id=\"Oly-I7-X0w\"/>\n                                    <constraint firstItem=\"eKu-PE-56L\" firstAttribute=\"top\" secondItem=\"bUM-jd-4A3\" secondAttribute=\"top\" id=\"Q9y-Sf-BKQ\"/>\n                                    <constraint firstItem=\"DH2-Zr-hDS\" firstAttribute=\"top\" secondItem=\"eKu-PE-56L\" secondAttribute=\"bottom\" id=\"Use-O7-GBR\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"DH2-Zr-hDS\" secondAttribute=\"trailing\" id=\"rcC-Qs-LUd\"/>\n                                    <constraint firstItem=\"DH2-Zr-hDS\" firstAttribute=\"leading\" secondItem=\"bUM-jd-4A3\" secondAttribute=\"leading\" id=\"vok-8D-7qu\"/>\n                                </constraints>\n                            </customView>\n                            <textField wantsLayer=\"YES\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gag-Uy-6zA\" customClass=\"TDCChannelSpotlightTextField\">\n                                <rect key=\"frame\" x=\"551\" y=\"158\" width=\"37\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Label\" id=\"hR8-rl-k0H\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"bUM-jd-4A3\" secondAttribute=\"bottom\" id=\"0I1-hx-BY2\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"bUM-jd-4A3\" secondAttribute=\"trailing\" id=\"7gC-Ny-6OU\"/>\n                            <constraint firstItem=\"1E4-kg-4iF\" firstAttribute=\"leading\" secondItem=\"Diu-wk-ZgA\" secondAttribute=\"trailing\" constant=\"14\" id=\"9Bu-lx-Js9\"/>\n                            <constraint firstItem=\"bUM-jd-4A3\" firstAttribute=\"top\" secondItem=\"1E4-kg-4iF\" secondAttribute=\"bottom\" constant=\"12\" id=\"Eda-ho-Uej\"/>\n                            <constraint firstItem=\"1E4-kg-4iF\" firstAttribute=\"top\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"top\" constant=\"12\" id=\"Syt-uA-Div\"/>\n                            <constraint firstAttribute=\"width\" constant=\"600\" id=\"bXM-cm-Q46\"/>\n                            <constraint firstItem=\"Gag-Uy-6zA\" firstAttribute=\"leading\" secondItem=\"1E4-kg-4iF\" secondAttribute=\"trailing\" constant=\"14\" id=\"mSk-dR-BZk\"/>\n                            <constraint firstItem=\"Gag-Uy-6zA\" firstAttribute=\"top\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"top\" constant=\"20\" id=\"nlm-fg-QMS\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Gag-Uy-6zA\" secondAttribute=\"trailing\" constant=\"14\" id=\"qFg-Ax-Qlz\"/>\n                            <constraint firstItem=\"Diu-wk-ZgA\" firstAttribute=\"leading\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"leading\" constant=\"14\" id=\"qcB-VV-GRh\"/>\n                            <constraint firstItem=\"Diu-wk-ZgA\" firstAttribute=\"top\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"top\" constant=\"16\" id=\"ri0-PZ-1Dy\"/>\n                            <constraint firstItem=\"bUM-jd-4A3\" firstAttribute=\"leading\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"leading\" id=\"vxM-fX-gmC\"/>\n                        </constraints>\n                    </visualEffectView>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"trailing\" id=\"7dm-VO-PBn\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"OYV-WK-xFr\" secondAttribute=\"bottom\" id=\"GgR-H0-uaP\"/>\n                    <constraint firstItem=\"OYV-WK-xFr\" firstAttribute=\"leading\" secondItem=\"ibD-GT-hsB\" secondAttribute=\"leading\" id=\"Q6P-45-9sU\"/>\n                    <constraint firstItem=\"OYV-WK-xFr\" firstAttribute=\"top\" secondItem=\"ibD-GT-hsB\" secondAttribute=\"top\" id=\"mEp-td-LO6\"/>\n                </constraints>\n                <accessibility description=\"Enter a channel name to search for, to browse to\"/>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"lBg-04-Pyt\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"217\" y=\"198\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"MainWindowSpotlightIconTemplate\" width=\"1180\" height=\"1178\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCFileTransferDialog.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23077.2\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23077.2\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCFileTransferDialog\">\n            <connections>\n                <outlet property=\"clearButton\" destination=\"117\" id=\"KoN-Uc-Nhi\"/>\n                <outlet property=\"fileTransferTable\" destination=\"xso-Ti-Pvf\" id=\"qiD-QC-Rrt\"/>\n                <outlet property=\"fileTransfersController\" destination=\"5qZ-cx-fmP\" id=\"muB-vK-w9U\"/>\n                <outlet property=\"navigationControllerCell\" destination=\"nY8-F3-7sa\" id=\"LNN-nZ-NGY\"/>\n                <outlet property=\"window\" destination=\"5\" id=\"oY6-kl-EqU\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"File Transfers\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" toolbarStyle=\"unified\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"560\" y=\"234\" width=\"550\" height=\"297\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <value key=\"minSize\" type=\"size\" width=\"515\" height=\"297\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"800\" height=\"800\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"297\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <scrollView borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"66\" horizontalPageScroll=\"10\" verticalLineScroll=\"66\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jdf-Fe-O7N\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"31\" width=\"550\" height=\"266\"/>\n                        <clipView key=\"contentView\" id=\"LgH-Ka-LaD\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"266\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" columnAutoresizingStyle=\"lastColumnOnly\" tableStyle=\"fullWidth\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowHeight=\"64\" viewBased=\"YES\" id=\"xso-Ti-Pvf\" customClass=\"TVCBasicTableView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"266\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"_sourceListBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn editable=\"NO\" width=\"538\" minWidth=\"40\" maxWidth=\"1000\" id=\"rMl-gp-lCO\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"7Ku-ts-PpG\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <customView identifier=\"GroupView\" id=\"rFe-Pm-QDv\" customClass=\"TDCFileTransferDialogTableCell\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"547\" height=\"64\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                                                    <subviews>\n                                                        <progressIndicator wantsLayer=\"YES\" maxValue=\"100\" indeterminate=\"YES\" controlSize=\"small\" style=\"bar\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fkg-tB-oW2\">\n                                                            <rect key=\"frame\" x=\"72\" y=\"25\" width=\"455\" height=\"12\"/>\n                                                        </progressIndicator>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"749\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tvE-ly-KOo\">\n                                                            <rect key=\"frame\" x=\"70\" y=\"44\" width=\"94\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"dummyfile.png\" id=\"5dv-pa-ldM\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"22V-bc-ITj\">\n                                                            <rect key=\"frame\" x=\"70\" y=\"6\" width=\"288\" height=\"14\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"10 MB of 100 MB (100 KB/sec) — 2 seconds reamining\" id=\"VVN-xJ-iKJ\">\n                                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NYx-LB-DAM\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"64\" height=\"64\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"width\" secondItem=\"NYx-LB-DAM\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"W1B-VM-yBq\"/>\n                                                                <constraint firstAttribute=\"height\" constant=\"64\" id=\"WBp-LA-De2\"/>\n                                                            </constraints>\n                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" id=\"yRx-w7-oXd\"/>\n                                                        </imageView>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qsO-pI-cPd\">\n                                                            <rect key=\"frame\" x=\"492\" y=\"44\" width=\"37\" height=\"14\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"width\" relation=\"lessThanOrEqual\" constant=\"70\" id=\"fDX-u0-Cff\"/>\n                                                            </constraints>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"10 MB\" id=\"PAR-0R-j9A\">\n                                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"tvE-ly-KOo\" firstAttribute=\"firstBaseline\" secondItem=\"qsO-pI-cPd\" secondAttribute=\"firstBaseline\" id=\"2ex-Th-hxI\"/>\n                                                        <constraint firstItem=\"tvE-ly-KOo\" firstAttribute=\"leading\" secondItem=\"NYx-LB-DAM\" secondAttribute=\"trailing\" constant=\"8\" id=\"7o2-gu-oax\"/>\n                                                        <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"22V-bc-ITj\" secondAttribute=\"trailing\" constant=\"20\" id=\"AES-tc-3mu\"/>\n                                                        <constraint firstItem=\"NYx-LB-DAM\" firstAttribute=\"leading\" secondItem=\"rFe-Pm-QDv\" secondAttribute=\"leading\" id=\"Aks-Nu-Q9F\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"qsO-pI-cPd\" secondAttribute=\"trailing\" constant=\"20\" id=\"Cwc-na-g2p\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"fkg-tB-oW2\" secondAttribute=\"trailing\" constant=\"20\" id=\"F6I-RK-DFp\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"NYx-LB-DAM\" secondAttribute=\"bottom\" id=\"MRx-7c-RFt\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"22V-bc-ITj\" secondAttribute=\"bottom\" constant=\"6\" id=\"NgU-gF-1BD\"/>\n                                                        <constraint firstItem=\"fkg-tB-oW2\" firstAttribute=\"top\" secondItem=\"rFe-Pm-QDv\" secondAttribute=\"top\" constant=\"27\" id=\"Skz-Lf-LFX\"/>\n                                                        <constraint firstItem=\"qsO-pI-cPd\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"tvE-ly-KOo\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ugx-DI-HCB\"/>\n                                                        <constraint firstItem=\"fkg-tB-oW2\" firstAttribute=\"leading\" secondItem=\"tvE-ly-KOo\" secondAttribute=\"leading\" id=\"bOT-h1-9yG\"/>\n                                                        <constraint firstItem=\"tvE-ly-KOo\" firstAttribute=\"top\" secondItem=\"rFe-Pm-QDv\" secondAttribute=\"top\" constant=\"4\" id=\"fE3-Pt-GL0\"/>\n                                                        <constraint firstItem=\"22V-bc-ITj\" firstAttribute=\"leading\" secondItem=\"fkg-tB-oW2\" secondAttribute=\"leading\" id=\"xtB-1N-wsd\"/>\n                                                        <constraint firstItem=\"NYx-LB-DAM\" firstAttribute=\"top\" secondItem=\"rFe-Pm-QDv\" secondAttribute=\"top\" id=\"ztW-h6-oiN\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"fileIconView\" destination=\"NYx-LB-DAM\" id=\"LdH-bC-6lX\"/>\n                                                        <outlet property=\"filenameTextField\" destination=\"tvE-ly-KOo\" id=\"Pab-WA-74U\"/>\n                                                        <outlet property=\"filenameTextFieldConstraint\" destination=\"fE3-Pt-GL0\" id=\"r4s-tI-YtY\"/>\n                                                        <outlet property=\"filesizeTextField\" destination=\"qsO-pI-cPd\" id=\"IiF-Gf-fxE\"/>\n                                                        <outlet property=\"progressIndicator\" destination=\"fkg-tB-oW2\" id=\"XOS-4k-5hk\"/>\n                                                        <outlet property=\"transferProgressTextField\" destination=\"22V-bc-ITj\" id=\"rVa-ge-ak4\"/>\n                                                        <outlet property=\"transferProgressTextFieldConstraint\" destination=\"NgU-gF-1BD\" id=\"PHo-nf-cXn\"/>\n                                                    </connections>\n                                                </customView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <binding destination=\"5qZ-cx-fmP\" name=\"content\" keyPath=\"arrangedObjects\" id=\"Twb-iu-nDP\"/>\n                                        <binding destination=\"5qZ-cx-fmP\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"Twb-iu-nDP\" id=\"S8O-8l-LA3\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"l7d-fh-IVr\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"Lbq-dF-k8b\"/>\n                                        <outlet property=\"menu\" destination=\"34\" id=\"EY2-ub-icM\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"jCb-ZR-rm0\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"223\" height=\"15\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"e1W-F5-jSi\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"117\">\n                        <rect key=\"frame\" x=\"9\" y=\"3\" width=\"182\" height=\"23\"/>\n                        <buttonCell key=\"cell\" type=\"roundTextured\" title=\"Clear All Stopped Transfers\" bezelStyle=\"texturedRounded\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"118\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"clear:\" target=\"-2\" id=\"T9p-oR-2hf\"/>\n                        </connections>\n                    </button>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"S61-G4-yuP\">\n                        <rect key=\"frame\" x=\"550\" y=\"0.0\" width=\"0.0\" height=\"0.0\"/>\n                        <buttonCell key=\"cell\" type=\"bevel\" bezelStyle=\"regularSquare\" alignment=\"center\" state=\"on\" transparent=\"YES\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"SeN-Yp-yzc\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" id=\"aoA-YK-tQA\"/>\n                            <constraint firstAttribute=\"width\" id=\"vYB-Pl-5GN\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"hideWindow:\" target=\"-2\" id=\"8Rp-dV-5Ye\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"Jdf-Fe-O7N\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" id=\"013-kX-aEM\"/>\n                    <constraint firstItem=\"Jdf-Fe-O7N\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" id=\"I9I-e4-KC6\"/>\n                    <constraint firstAttribute=\"right\" secondItem=\"S61-G4-yuP\" secondAttribute=\"right\" id=\"OHO-Y9-5gc\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"S61-G4-yuP\" secondAttribute=\"bottom\" id=\"SOp-rS-gkY\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"117\" secondAttribute=\"trailing\" constant=\"10\" id=\"T4G-fr-nGn\"/>\n                    <constraint firstItem=\"117\" firstAttribute=\"top\" secondItem=\"Jdf-Fe-O7N\" secondAttribute=\"bottom\" constant=\"6\" id=\"X30-Wz-Xwz\"/>\n                    <constraint firstItem=\"117\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"10\" id=\"ZUf-Ec-p4G\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"117\" secondAttribute=\"bottom\" constant=\"5\" id=\"uVj-fq-PFp\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Jdf-Fe-O7N\" secondAttribute=\"trailing\" id=\"yBR-gX-R1n\"/>\n                </constraints>\n            </view>\n            <toolbar key=\"toolbar\" implicitIdentifier=\"F9BA2FE0-3285-45B9-A261-616E8F0B841D\" autosavesConfiguration=\"NO\" allowsUserCustomization=\"NO\" showsBaselineSeparator=\"NO\" displayMode=\"iconOnly\" sizeMode=\"regular\" id=\"U41-vi-dWL\">\n                <allowedToolbarItems>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarFlexibleSpaceItem\" id=\"SXF-Hk-P3u\"/>\n                    <toolbarItem implicitItemIdentifier=\"A5FD6FCE-F1A6-4A68-8AC9-7AA413120875\" label=\"\" paletteLabel=\"\" sizingBehavior=\"auto\" id=\"snS-Lz-UGq\">\n                        <nil key=\"toolTip\"/>\n                        <segmentedControl key=\"view\" verticalHuggingPriority=\"750\" id=\"fj7-Wr-P1f\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"14\" width=\"192\" height=\"25\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                            <segmentedCell key=\"cell\" borderStyle=\"border\" alignment=\"left\" style=\"texturedSquare\" trackingMode=\"selectOne\" id=\"nY8-F3-7sa\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <segments>\n                                    <segment label=\"All\" selected=\"YES\" tag=\"100\"/>\n                                    <segment label=\"Sending\" tag=\"101\"/>\n                                    <segment label=\"Receiving\" tag=\"102\"/>\n                                </segments>\n                            </segmentedCell>\n                        </segmentedControl>\n                        <connections>\n                            <action selector=\"navigationSelectionDidChange:\" target=\"-2\" id=\"yQL-Fm-EZy\"/>\n                        </connections>\n                    </toolbarItem>\n                </allowedToolbarItems>\n                <defaultToolbarItems>\n                    <toolbarItem reference=\"SXF-Hk-P3u\"/>\n                    <toolbarItem reference=\"snS-Lz-UGq\"/>\n                    <toolbarItem reference=\"SXF-Hk-P3u\"/>\n                </defaultToolbarItems>\n            </toolbar>\n            <contentBorderThickness minY=\"33\"/>\n            <point key=\"canvasLocation\" x=\"236\" y=\"289.5\"/>\n        </window>\n        <arrayController objectClassName=\"TDCFileTransferDialogTransferController\" editable=\"NO\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" clearsFilterPredicateOnInsertion=\"NO\" id=\"5qZ-cx-fmP\">\n            <classReference key=\"objectClass\" className=\"TDCFileTransferDialogTransferController\"/>\n        </arrayController>\n        <menu title=\"Menu\" id=\"34\" userLabel=\"TableMenu\">\n            <items>\n                <menuItem title=\"Start Transfer\" tag=\"3001\" id=\"35\">\n                    <connections>\n                        <action selector=\"startTransferOfFile:\" target=\"-2\" id=\"Z4r-Um-xMm\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Cancel Transfer\" tag=\"3003\" id=\"36\">\n                    <connections>\n                        <action selector=\"stopTransferOfFile:\" target=\"-2\" id=\"QQg-yO-uo8\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"41\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Reveal in Finder\" tag=\"3006\" id=\"84\">\n                    <connections>\n                        <action selector=\"revealReceivedFileInFinder:\" target=\"-2\" id=\"uJy-RJ-Ljo\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Open File\" tag=\"3005\" id=\"72\">\n                    <connections>\n                        <action selector=\"openReceivedFile:\" target=\"-2\" id=\"P4t-qZ-hhL\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" id=\"73\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Remove From List\" tag=\"3004\" id=\"42\">\n                    <connections>\n                        <action selector=\"removeTransferFromList:\" target=\"-2\" id=\"pPs-w3-h5f\"/>\n                    </connections>\n                </menuItem>\n            </items>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCHighlightEntrySheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCHighlightEntrySheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"323\" id=\"327\"/>\n                <outlet property=\"matchChannelPopupButton\" destination=\"316\" id=\"338\"/>\n                <outlet property=\"matchKeywordTextField\" destination=\"310\" id=\"339\"/>\n                <outlet property=\"matchTypePopupButton\" destination=\"304\" id=\"331\"/>\n                <outlet property=\"okButton\" destination=\"325\" id=\"332\"/>\n                <outlet property=\"sheet\" destination=\"302\" id=\"333\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"302\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"434\" height=\"40\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"303\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"434\" height=\"129\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"7\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pG1-Fd-QYW\">\n                        <rect key=\"frame\" x=\"20\" y=\"60\" width=\"394\" height=\"49\"/>\n                        <subviews>\n                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Umb-lT-yZS\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"27\" width=\"394\" height=\"22\"/>\n                                <subviews>\n                                    <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"304\">\n                                        <rect key=\"frame\" x=\"-3\" y=\"-3\" width=\"102\" height=\"25\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"95\" id=\"nPm-5S-cdY\"/>\n                                        </constraints>\n                                        <popUpButtonCell key=\"cell\" type=\"push\" title=\"Match\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"1\" imageScaling=\"proportionallyDown\" inset=\"2\" autoenablesItems=\"NO\" selectedItem=\"307\" id=\"305\">\n                                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"menu\"/>\n                                            <menu key=\"menu\" title=\"OtherViews\" autoenablesItems=\"NO\" id=\"306\">\n                                                <items>\n                                                    <menuItem title=\"Match\" state=\"on\" tag=\"1\" id=\"307\"/>\n                                                    <menuItem title=\"Exclude\" tag=\"2\" id=\"308\"/>\n                                                </items>\n                                            </menu>\n                                        </popUpButtonCell>\n                                        <accessibility description=\"Highlight Match Type\"/>\n                                    </popUpButton>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"312\">\n                                        <rect key=\"frame\" x=\"101\" y=\"3\" width=\"78\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"the keyword\" id=\"313\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"310\" customClass=\"TVCValidatedTextField\">\n                                        <rect key=\"frame\" x=\"185\" y=\"0.0\" width=\"209\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"EpS-gd-fY4\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" usesSingleLineMode=\"YES\" id=\"311\" customClass=\"TVCValidatedTextFieldCell\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <accessibility description=\"Highlight Match Keyword\"/>\n                                        <connections>\n                                            <outlet property=\"delegate\" destination=\"-2\" id=\"337\"/>\n                                        </connections>\n                                    </textField>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"m7Y-06-lQs\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"394\" height=\"20\"/>\n                                <subviews>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"314\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"89\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"in the channel\" id=\"315\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <popUpButton horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"316\">\n                                        <rect key=\"frame\" x=\"90\" y=\"-4\" width=\"308\" height=\"25\"/>\n                                        <popUpButtonCell key=\"cell\" type=\"push\" title=\"All Channels\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"319\" id=\"317\">\n                                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"menu\"/>\n                                            <menu key=\"menu\" title=\"OtherViews\" id=\"318\">\n                                                <items>\n                                                    <menuItem title=\"All Channels\" state=\"on\" id=\"319\"/>\n                                                    <menuItem isSeparatorItem=\"YES\" id=\"322\"/>\n                                                </items>\n                                            </menu>\n                                        </popUpButtonCell>\n                                        <accessibility description=\"Limit Highlight to Channel\"/>\n                                    </popUpButton>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                        </subviews>\n                        <visibilityPriorities>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                        </visibilityPriorities>\n                        <customSpacing>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                        </customSpacing>\n                    </stackView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"323\">\n                        <rect key=\"frame\" x=\"283\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"324\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"334\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"325\">\n                        <rect key=\"frame\" x=\"357\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"326\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"335\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"323\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"303\" secondAttribute=\"leading\" constant=\"20\" id=\"E01-G7-a1g\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"325\" secondAttribute=\"bottom\" constant=\"20\" id=\"EbJ-bz-64h\"/>\n                    <constraint firstItem=\"325\" firstAttribute=\"top\" secondItem=\"pG1-Fd-QYW\" secondAttribute=\"bottom\" constant=\"20\" id=\"PfQ-cl-hFU\"/>\n                    <constraint firstItem=\"325\" firstAttribute=\"firstBaseline\" secondItem=\"323\" secondAttribute=\"firstBaseline\" id=\"Vh4-nG-WCx\"/>\n                    <constraint firstItem=\"325\" firstAttribute=\"leading\" secondItem=\"323\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"dTA-9e-Cmz\"/>\n                    <constraint firstItem=\"pG1-Fd-QYW\" firstAttribute=\"leading\" secondItem=\"303\" secondAttribute=\"leading\" constant=\"20\" id=\"fY3-0R-tBm\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"pG1-Fd-QYW\" secondAttribute=\"trailing\" constant=\"20\" id=\"jIR-zs-8q5\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"325\" secondAttribute=\"trailing\" constant=\"20\" id=\"jnh-KQ-Qch\"/>\n                    <constraint firstItem=\"pG1-Fd-QYW\" firstAttribute=\"top\" secondItem=\"303\" secondAttribute=\"top\" constant=\"20\" id=\"mHh-rB-ZCx\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"336\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"196\" y=\"209\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseManagerDialog.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23727\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23727\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseManagerDialog\">\n            <connections>\n                <outlet property=\"contentViewRegisteredTextualView\" destination=\"JQ9-UV-o9c\" id=\"q9J-K6-S1I\"/>\n                <outlet property=\"contentViewUnregisteredTextualView\" destination=\"bea-Wk-5YZ\" id=\"eQ1-yJ-C44\"/>\n                <outlet property=\"registeredViewDeactivateTextualButton\" destination=\"o0O-rL-T0z\" id=\"Tdv-fR-Qgf\"/>\n                <outlet property=\"registeredViewLicenseKeyTextField\" destination=\"Aic-wa-hxg\" id=\"8Q8-w8-hZ6\"/>\n                <outlet property=\"registeredViewLicenseOwnerTextField\" destination=\"3dT-zX-85e\" id=\"TdF-Rz-oJW\"/>\n                <outlet property=\"registeredViewLicensePurchaseDateTextField\" destination=\"g5a-3T-fft\" id=\"oiK-Ta-kGv\"/>\n                <outlet property=\"unregisteredViewActivateTextualButton\" destination=\"c0t-Vn-Ofk\" id=\"1lB-yf-GaZ\"/>\n                <outlet property=\"unregisteredViewCancelButton\" destination=\"yZF-Hy-PrY\" id=\"L9r-Xa-FVj\"/>\n                <outlet property=\"unregisteredViewLicenseKeyTextField\" destination=\"kAU-WO-mIJ\" id=\"gPM-eo-qVs\"/>\n                <outlet property=\"unregisteredViewMacAppStoreIconImageView\" destination=\"jg7-PN-SWb\" id=\"aAC-aI-s3O\"/>\n                <outlet property=\"unregisteredViewRecoveryLostLicenseButton\" destination=\"V4s-Va-UFF\" id=\"Pbt-eH-4EM\"/>\n                <outlet property=\"unregisteredViewTrialInformationTextField\" destination=\"Pho-XN-fdp\" id=\"C9I-YH-Meg\"/>\n                <outlet property=\"window\" destination=\"tBl-Uw-jZv\" id=\"VoY-RM-rJQ\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Manage License\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" tabbingMode=\"disallowed\" id=\"tBl-Uw-jZv\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"591\" height=\"341\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"FoU-2F-dJN\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"591\" height=\"341\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"8r8-0s-Y4L\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"1284\" y=\"-88\"/>\n        </window>\n        <view translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bea-Wk-5YZ\" userLabel=\"Content View Unregistered Textual View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"590\" height=\"357\"/>\n            <subviews>\n                <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xaT-du-Hgo\">\n                    <rect key=\"frame\" x=\"20\" y=\"221\" width=\"75\" height=\"75\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" secondItem=\"xaT-du-Hgo\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"DWq-cB-ykc\"/>\n                        <constraint firstAttribute=\"width\" constant=\"75\" id=\"qg9-Zg-6ln\"/>\n                    </constraints>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"9c6-9f-bCg\"/>\n                    <accessibility description=\"Textual Logo\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Uu0-L6-ebd\">\n                    <rect key=\"frame\" x=\"109\" y=\"280\" width=\"316\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"To activate Textual, enter your license key below\" id=\"6U9-rS-tAa\">\n                        <font key=\"font\" metaFont=\"systemBold\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SKZ-Sh-8aW\">\n                    <rect key=\"frame\" x=\"109\" y=\"209\" width=\"81\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"License Key:\" id=\"iji-CW-RF2\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nxy-E2-Vas\">\n                    <rect key=\"frame\" x=\"109\" y=\"240\" width=\"463\" height=\"32\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Your license key can be found in the e-mail that was sent to you after completing your purchase.\" id=\"9WE-Gi-yuN\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kAU-WO-mIJ\">\n                    <rect key=\"frame\" x=\"196\" y=\"206\" width=\"374\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"vbh-eP-CmJ\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"\" drawsBackground=\"YES\" id=\"gYL-gB-e0X\">\n                        <font key=\"font\" size=\"13\" name=\"Courier\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"SKZ-Sh-8aW\" id=\"zdg-zh-VsH\"/>\n                        <outlet property=\"delegate\" destination=\"-2\" id=\"zgj-VN-7dM\"/>\n                    </connections>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c0t-Vn-Ofk\">\n                    <rect key=\"frame\" x=\"447\" y=\"159\" width=\"130\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Activate Textual\" bezelStyle=\"rounded\" alignment=\"center\" enabled=\"NO\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"THe-1N-yO3\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Activate Textual\"/>\n                    <connections>\n                        <action selector=\"unregisteredViewActivateTextual:\" target=\"-2\" id=\"kRg-rx-FHU\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"20p-td-tPI\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"143\" width=\"590\" height=\"5\"/>\n                </box>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WHr-3v-nQP\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"314\" width=\"590\" height=\"5\"/>\n                </box>\n                <box boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NPe-61-R0Z\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"316\" width=\"590\" height=\"41\"/>\n                    <view key=\"contentView\" id=\"Y04-Ui-XYn\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"590\" height=\"41\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pho-XN-fdp\">\n                                <rect key=\"frame\" x=\"14\" y=\"11\" width=\"249\" height=\"19\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Your trial of Textual expires in %@\" id=\"b62-vg-HHg\">\n                                    <font key=\"font\" metaFont=\"system\" size=\"16\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UK4-RN-UQO\">\n                                <rect key=\"frame\" x=\"490\" y=\"4\" width=\"91\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Purchase\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"gdC-Sd-aWH\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Purchase Textual\"/>\n                                <connections>\n                                    <action selector=\"unregisteredViewPurchaseTextual:\" target=\"-2\" id=\"d2I-v9-B1X\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <constraints>\n                            <constraint firstItem=\"UK4-RN-UQO\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Pho-XN-fdp\" secondAttribute=\"trailing\" constant=\"20\" id=\"ob1-UO-aGU\"/>\n                        </constraints>\n                    </view>\n                    <constraints>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"UK4-RN-UQO\" secondAttribute=\"trailing\" constant=\"16\" id=\"3jM-9g-0Bt\"/>\n                        <constraint firstItem=\"Pho-XN-fdp\" firstAttribute=\"centerY\" secondItem=\"NPe-61-R0Z\" secondAttribute=\"centerY\" id=\"bqB-AJ-x5k\"/>\n                        <constraint firstItem=\"Pho-XN-fdp\" firstAttribute=\"centerY\" secondItem=\"UK4-RN-UQO\" secondAttribute=\"centerY\" id=\"eH6-k4-3Nx\"/>\n                        <constraint firstItem=\"Pho-XN-fdp\" firstAttribute=\"leading\" secondItem=\"NPe-61-R0Z\" secondAttribute=\"leading\" constant=\"16\" id=\"rdC-hX-TsX\"/>\n                    </constraints>\n                    <color key=\"borderColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <color key=\"fillColor\" white=\"0.0\" alpha=\"0.040000000000000001\" colorSpace=\"calibratedWhite\"/>\n                </box>\n                <box boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gvB-hL-TZu\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"590\" height=\"145\"/>\n                    <view key=\"contentView\" id=\"kNO-08-Kd4\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"590\" height=\"145\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jg7-PN-SWb\">\n                                <rect key=\"frame\" x=\"16\" y=\"53\" width=\"75\" height=\"75\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"75\" id=\"AlM-ow-021\"/>\n                                    <constraint firstAttribute=\"width\" secondItem=\"jg7-PN-SWb\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"JfS-YS-1rG\"/>\n                                </constraints>\n                                <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"Nw3-hE-vWZ\"/>\n                                <accessibility description=\"Mac App Store Logo\"/>\n                            </imageView>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"x6V-ip-XZY\">\n                                <rect key=\"frame\" x=\"105\" y=\"112\" width=\"210\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Migrate from the Mac App Store\" id=\"UVC-M1-5Bi\">\n                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LBa-p3-Krv\">\n                                <rect key=\"frame\" x=\"105\" y=\"56\" width=\"467\" height=\"48\"/>\n                                <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"QVB-9e-QPb\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <string key=\"title\">You can request a license key if you already own Textual 5 or a newer version in the Mac App Store. To download a new copy of Textual from the Mac App Store, click on your name in the store to access your purchases.</string>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fil-u7-1Jf\">\n                                <rect key=\"frame\" x=\"228\" y=\"13\" width=\"134\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Request License\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Ciz-0p-zdv\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Request Free License\"/>\n                                <connections>\n                                    <action selector=\"unregisteredViewMigrateMacAppStorePurchase:\" target=\"-2\" id=\"WB2-rx-giw\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"x6V-ip-XZY\" secondAttribute=\"trailing\" constant=\"20\" id=\"Nwo-Or-cQj\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"LBa-p3-Krv\" secondAttribute=\"trailing\" constant=\"20\" id=\"fj8-J6-ha6\"/>\n                            <constraint firstItem=\"jg7-PN-SWb\" firstAttribute=\"top\" secondItem=\"kNO-08-Kd4\" secondAttribute=\"top\" constant=\"17\" id=\"x1L-a1-usE\"/>\n                        </constraints>\n                    </view>\n                    <constraints>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"Fil-u7-1Jf\" secondAttribute=\"bottom\" constant=\"20\" id=\"5c5-ki-HMU\"/>\n                        <constraint firstItem=\"x6V-ip-XZY\" firstAttribute=\"leading\" secondItem=\"LBa-p3-Krv\" secondAttribute=\"leading\" id=\"62f-c0-Fc8\"/>\n                        <constraint firstItem=\"x6V-ip-XZY\" firstAttribute=\"leading\" secondItem=\"jg7-PN-SWb\" secondAttribute=\"trailing\" constant=\"16\" id=\"NvY-3q-sG6\"/>\n                        <constraint firstItem=\"Fil-u7-1Jf\" firstAttribute=\"top\" secondItem=\"LBa-p3-Krv\" secondAttribute=\"bottom\" constant=\"16\" id=\"OvJ-sO-527\"/>\n                        <constraint firstItem=\"Fil-u7-1Jf\" firstAttribute=\"centerX\" secondItem=\"gvB-hL-TZu\" secondAttribute=\"centerX\" id=\"XkE-Wd-GJe\"/>\n                        <constraint firstItem=\"jg7-PN-SWb\" firstAttribute=\"top\" secondItem=\"x6V-ip-XZY\" secondAttribute=\"top\" id=\"qBW-QX-lr9\"/>\n                        <constraint firstItem=\"LBa-p3-Krv\" firstAttribute=\"top\" secondItem=\"x6V-ip-XZY\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"uOi-oU-frx\"/>\n                        <constraint firstItem=\"jg7-PN-SWb\" firstAttribute=\"leading\" secondItem=\"gvB-hL-TZu\" secondAttribute=\"leading\" constant=\"16\" id=\"wlr-5r-uAu\"/>\n                    </constraints>\n                    <color key=\"borderColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <color key=\"fillColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                </box>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yZF-Hy-PrY\">\n                    <rect key=\"frame\" x=\"373\" y=\"159\" width=\"76\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"XhH-Zr-ZZE\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"unregisteredViewCancel:\" target=\"-2\" id=\"Lxl-cB-V14\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"V4s-Va-UFF\">\n                    <rect key=\"frame\" x=\"13\" y=\"159\" width=\"163\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Recover Lost License\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"YAm-hP-iFo\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"unregisteredViewRecoveryLostLicense:\" target=\"-2\" id=\"hGo-Wn-dgt\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"c0t-Vn-Ofk\" firstAttribute=\"top\" secondItem=\"kAU-WO-mIJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"2LX-FV-NHO\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"gvB-hL-TZu\" secondAttribute=\"trailing\" id=\"3eB-Ai-ZDH\"/>\n                <constraint firstItem=\"Uu0-L6-ebd\" firstAttribute=\"leading\" secondItem=\"xaT-du-Hgo\" secondAttribute=\"trailing\" constant=\"16\" id=\"4dT-Sh-CmE\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"NPe-61-R0Z\" secondAttribute=\"trailing\" id=\"AvQ-oD-rSH\"/>\n                <constraint firstItem=\"WHr-3v-nQP\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" id=\"Bf0-iQ-DO6\"/>\n                <constraint firstItem=\"V4s-Va-UFF\" firstAttribute=\"firstBaseline\" secondItem=\"yZF-Hy-PrY\" secondAttribute=\"firstBaseline\" id=\"Bqh-3c-eFp\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"nxy-E2-Vas\" secondAttribute=\"trailing\" constant=\"20\" id=\"CTG-f6-lZj\"/>\n                <constraint firstItem=\"c0t-Vn-Ofk\" firstAttribute=\"leading\" secondItem=\"yZF-Hy-PrY\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"DGm-Ny-ZD2\"/>\n                <constraint firstItem=\"SKZ-Sh-8aW\" firstAttribute=\"leading\" secondItem=\"nxy-E2-Vas\" secondAttribute=\"leading\" id=\"ISl-Xl-OM7\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"gvB-hL-TZu\" secondAttribute=\"bottom\" id=\"Krt-Ch-a1I\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Uu0-L6-ebd\" secondAttribute=\"trailing\" constant=\"20\" id=\"M26-tj-ycC\"/>\n                <constraint firstItem=\"gvB-hL-TZu\" firstAttribute=\"top\" secondItem=\"20p-td-tPI\" secondAttribute=\"bottom\" id=\"M3m-m4-fBd\"/>\n                <constraint firstItem=\"yZF-Hy-PrY\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"V4s-Va-UFF\" secondAttribute=\"trailing\" constant=\"20\" id=\"N9B-1Z-M8k\"/>\n                <constraint firstItem=\"NPe-61-R0Z\" firstAttribute=\"bottom\" secondItem=\"WHr-3v-nQP\" secondAttribute=\"bottom\" id=\"NS4-DK-Ivp\"/>\n                <constraint firstItem=\"WHr-3v-nQP\" firstAttribute=\"top\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"top\" constant=\"40\" id=\"Nb7-pd-Xoy\"/>\n                <constraint firstItem=\"WHr-3v-nQP\" firstAttribute=\"top\" secondItem=\"NPe-61-R0Z\" secondAttribute=\"bottom\" constant=\"-1\" id=\"VsM-Tp-XTV\"/>\n                <constraint firstItem=\"nxy-E2-Vas\" firstAttribute=\"top\" secondItem=\"Uu0-L6-ebd\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"aTu-cc-fXr\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"c0t-Vn-Ofk\" secondAttribute=\"trailing\" constant=\"20\" id=\"bHf-3U-2OR\"/>\n                <constraint firstItem=\"xaT-du-Hgo\" firstAttribute=\"top\" secondItem=\"WHr-3v-nQP\" secondAttribute=\"bottom\" constant=\"20\" id=\"ba6-RB-oLJ\"/>\n                <constraint firstItem=\"SKZ-Sh-8aW\" firstAttribute=\"firstBaseline\" secondItem=\"kAU-WO-mIJ\" secondAttribute=\"firstBaseline\" id=\"cav-JB-faN\"/>\n                <constraint firstItem=\"xaT-du-Hgo\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"fE3-mv-pey\"/>\n                <constraint firstItem=\"NPe-61-R0Z\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" id=\"iQ3-op-Sdu\"/>\n                <constraint firstItem=\"kAU-WO-mIJ\" firstAttribute=\"top\" secondItem=\"nxy-E2-Vas\" secondAttribute=\"bottom\" constant=\"12\" id=\"mwz-Lh-Rjn\"/>\n                <constraint firstItem=\"kAU-WO-mIJ\" firstAttribute=\"leading\" secondItem=\"SKZ-Sh-8aW\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"n9A-hR-ML4\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"20p-td-tPI\" secondAttribute=\"trailing\" id=\"pBu-8J-TUu\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"kAU-WO-mIJ\" secondAttribute=\"trailing\" constant=\"20\" id=\"pEs-Q0-88O\"/>\n                <constraint firstItem=\"Uu0-L6-ebd\" firstAttribute=\"leading\" secondItem=\"nxy-E2-Vas\" secondAttribute=\"leading\" id=\"pdl-jy-0fG\"/>\n                <constraint firstItem=\"NPe-61-R0Z\" firstAttribute=\"top\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"top\" id=\"rV5-ZZ-B14\"/>\n                <constraint firstItem=\"V4s-Va-UFF\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"rjh-UP-5mT\"/>\n                <constraint firstItem=\"20p-td-tPI\" firstAttribute=\"top\" secondItem=\"c0t-Vn-Ofk\" secondAttribute=\"bottom\" constant=\"20\" id=\"tD0-Zj-qYk\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"WHr-3v-nQP\" secondAttribute=\"trailing\" id=\"v2B-ou-eRA\"/>\n                <constraint firstItem=\"xaT-du-Hgo\" firstAttribute=\"top\" secondItem=\"Uu0-L6-ebd\" secondAttribute=\"top\" id=\"wCz-TR-OL4\"/>\n                <constraint firstItem=\"gvB-hL-TZu\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" id=\"x4P-Tu-UJv\"/>\n                <constraint firstItem=\"yZF-Hy-PrY\" firstAttribute=\"firstBaseline\" secondItem=\"c0t-Vn-Ofk\" secondAttribute=\"firstBaseline\" id=\"xYO-QU-LGS\"/>\n                <constraint firstItem=\"20p-td-tPI\" firstAttribute=\"leading\" secondItem=\"bea-Wk-5YZ\" secondAttribute=\"leading\" id=\"xwh-az-hal\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"629\" y=\"-87\"/>\n        </view>\n        <view translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JQ9-UV-o9c\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"560\" height=\"194\"/>\n            <subviews>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Tjp-KZ-IkI\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"50\" width=\"560\" height=\"5\"/>\n                </box>\n                <box boxType=\"custom\" borderType=\"none\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3oo-eQ-fra\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"560\" height=\"52\"/>\n                    <view key=\"contentView\" id=\"zKM-uE-oT6\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"560\" height=\"52\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"o0O-rL-T0z\">\n                                <rect key=\"frame\" x=\"207\" y=\"9\" width=\"146\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Deactivate Textual\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"dsD-zn-k24\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <connections>\n                                    <action selector=\"registeredViewDeactivateTextual:\" target=\"-2\" id=\"xkt-N8-hEc\"/>\n                                </connections>\n                            </button>\n                        </subviews>\n                        <constraints>\n                            <constraint firstItem=\"o0O-rL-T0z\" firstAttribute=\"top\" secondItem=\"zKM-uE-oT6\" secondAttribute=\"top\" constant=\"16\" id=\"Ryb-hR-D9h\"/>\n                        </constraints>\n                    </view>\n                    <constraints>\n                        <constraint firstItem=\"o0O-rL-T0z\" firstAttribute=\"centerX\" secondItem=\"3oo-eQ-fra\" secondAttribute=\"centerX\" id=\"3WG-7N-TQT\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"o0O-rL-T0z\" secondAttribute=\"bottom\" constant=\"16\" id=\"fmb-ZL-eth\"/>\n                    </constraints>\n                    <color key=\"borderColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                    <color key=\"fillColor\" white=\"0.0\" alpha=\"0.0241231274\" colorSpace=\"calibratedWhite\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6ov-Tb-DrN\">\n                    <rect key=\"frame\" x=\"91\" y=\"150\" width=\"379\" height=\"24\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Thank you for your purchase of Textual!\" id=\"VEa-9u-paw\">\n                        <font key=\"font\" metaFont=\"systemBold\" size=\"20\"/>\n                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <gridView xPlacement=\"fill\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LJE-eb-I2N\">\n                    <rect key=\"frame\" x=\"65\" y=\"73\" width=\"430\" height=\"64\"/>\n                    <rows>\n                        <gridRow id=\"WQq-cq-5bc\"/>\n                        <gridRow id=\"0ed-nt-dpf\"/>\n                        <gridRow id=\"vAa-8C-0kw\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"trailing\" id=\"Wnb-a3-qTo\"/>\n                        <gridColumn xPlacement=\"leading\" id=\"utI-Eu-ITn\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"WQq-cq-5bc\" column=\"Wnb-a3-qTo\" id=\"ADu-eE-3FZ\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cfn-IY-dQv\">\n                                <rect key=\"frame\" x=\"15\" y=\"48\" width=\"86\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"License Key:\" id=\"Sqv-hD-I9t\">\n                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"WQq-cq-5bc\" column=\"utI-Eu-ITn\" id=\"xWP-M7-eRK\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Aic-wa-hxg\">\n                                <rect key=\"frame\" x=\"105\" y=\"48\" width=\"327\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" state=\"on\" alignment=\"left\" title=\"relieved-red-mallard-100000000000000000000000\" placeholderString=\"\" id=\"tRu-b8-URm\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"0ed-nt-dpf\" column=\"Wnb-a3-qTo\" id=\"To6-Fl-r4z\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6Kl-eO-RdC\">\n                                <rect key=\"frame\" x=\"17\" y=\"24\" width=\"84\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Licensed to:\" id=\"6ME-D8-5PB\">\n                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"0ed-nt-dpf\" column=\"utI-Eu-ITn\" id=\"Hs3-cg-Ku2\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3dT-zX-85e\">\n                                <rect key=\"frame\" x=\"105\" y=\"24\" width=\"72\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"John Smith\" id=\"xuy-7G-Mgt\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"vAa-8C-0kw\" column=\"Wnb-a3-qTo\" id=\"Pnr-0o-kf9\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KTA-04-hF9\">\n                                <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"103\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Purchase Date:\" id=\"ZkA-LE-wVS\">\n                                    <font key=\"font\" metaFont=\"systemBold\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"vAa-8C-0kw\" column=\"utI-Eu-ITn\" id=\"kEJ-eR-7ce\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g5a-3T-fft\">\n                                <rect key=\"frame\" x=\"105\" y=\"0.0\" width=\"53\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Monday\" id=\"CVk-zh-eEN\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"3oo-eQ-fra\" secondAttribute=\"trailing\" id=\"2kw-XE-B37\"/>\n                <constraint firstItem=\"LJE-eb-I2N\" firstAttribute=\"top\" secondItem=\"6ov-Tb-DrN\" secondAttribute=\"bottom\" constant=\"13\" id=\"44z-qW-FRK\"/>\n                <constraint firstItem=\"3oo-eQ-fra\" firstAttribute=\"top\" secondItem=\"Tjp-KZ-IkI\" secondAttribute=\"bottom\" id=\"AGd-Wa-XpJ\"/>\n                <constraint firstItem=\"LJE-eb-I2N\" firstAttribute=\"centerX\" secondItem=\"JQ9-UV-o9c\" secondAttribute=\"centerX\" id=\"Aty-2P-VFC\"/>\n                <constraint firstItem=\"3oo-eQ-fra\" firstAttribute=\"leading\" secondItem=\"JQ9-UV-o9c\" secondAttribute=\"leading\" id=\"IWK-LF-kmN\"/>\n                <constraint firstItem=\"6ov-Tb-DrN\" firstAttribute=\"centerX\" secondItem=\"Tjp-KZ-IkI\" secondAttribute=\"centerX\" id=\"TKS-to-Yg5\"/>\n                <constraint firstItem=\"6ov-Tb-DrN\" firstAttribute=\"top\" secondItem=\"JQ9-UV-o9c\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"b7k-0Y-EQH\"/>\n                <constraint firstItem=\"Tjp-KZ-IkI\" firstAttribute=\"trailing\" secondItem=\"3oo-eQ-fra\" secondAttribute=\"trailing\" id=\"cmp-ZZ-ABF\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"3oo-eQ-fra\" secondAttribute=\"bottom\" id=\"nkJ-be-Udb\"/>\n                <constraint firstItem=\"Tjp-KZ-IkI\" firstAttribute=\"top\" secondItem=\"LJE-eb-I2N\" secondAttribute=\"bottom\" constant=\"20\" id=\"osM-9z-RWW\"/>\n                <constraint firstItem=\"3oo-eQ-fra\" firstAttribute=\"leading\" secondItem=\"Tjp-KZ-IkI\" secondAttribute=\"leading\" id=\"tqW-cK-DhK\"/>\n                <constraint firstItem=\"LJE-eb-I2N\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"JQ9-UV-o9c\" secondAttribute=\"leading\" constant=\"60\" id=\"zvD-6W-1MQ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"609\" y=\"230\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseManagerMigrateAppStoreSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseManagerMigrateAppStoreSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"caz-XB-TnX\" id=\"shL-8g-QMc\"/>\n                <outlet property=\"licenseOwnerContactAddressTextField\" destination=\"rVI-TX-GRu\" id=\"6tg-8x-ZLg\"/>\n                <outlet property=\"licenseOwnerNameTextField\" destination=\"JL9-wh-1Zp\" id=\"F9Y-Xv-Gpb\"/>\n                <outlet property=\"okButton\" destination=\"Jam-O7-WoM\" id=\"rxB-Xk-HYE\"/>\n                <outlet property=\"sheet\" destination=\"puk-fp-XeX\" id=\"gEl-Ps-yt6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"puk-fp-XeX\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"765\" y=\"571\" width=\"370\" height=\"179\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"gBo-7N-KkR\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"370\" height=\"178\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"F12-H0-P9Z\">\n                        <rect key=\"frame\" x=\"18\" y=\"126\" width=\"334\" height=\"32\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Enter the name and e-mail address that you would llike associated with your license key. \" id=\"fYJ-sf-Wdh\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jam-O7-WoM\">\n                        <rect key=\"frame\" x=\"197\" y=\"13\" width=\"160\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Request License Key\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"cOF-4q-haH\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Request License Key\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"ybn-O3-2hr\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"caz-XB-TnX\">\n                        <rect key=\"frame\" x=\"123\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"KYK-L5-DFY\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"qaw-bq-7JX\"/>\n                        </connections>\n                    </button>\n                    <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1RR-lW-kgH\">\n                        <rect key=\"frame\" x=\"20\" y=\"60\" width=\"330\" height=\"52\"/>\n                        <rows>\n                            <gridRow id=\"FI3-Nv-ghm\"/>\n                            <gridRow id=\"XNp-Sk-9kP\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn xPlacement=\"fill\" id=\"ch8-dk-ArO\"/>\n                            <gridColumn xPlacement=\"fill\" id=\"phr-gg-3df\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"FI3-Nv-ghm\" column=\"ch8-dk-ArO\" id=\"xGS-xL-AnN\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jNw-4C-0KS\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"34\" width=\"100\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Name:\" id=\"1zk-IO-jS5\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"FI3-Nv-ghm\" column=\"phr-gg-3df\" id=\"rKv-D0-vOb\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JL9-wh-1Zp\" customClass=\"TVCValidatedTextField\">\n                                    <rect key=\"frame\" x=\"104\" y=\"30\" width=\"226\" height=\"22\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"eeN-U6-o6Q\"/>\n                                    </constraints>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"cjP-El-bvn\" customClass=\"TVCValidatedTextFieldCell\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                    </textFieldCell>\n                                    <accessibility description=\"Name to assosicate with license key\"/>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"XNp-Sk-9kP\" column=\"ch8-dk-ArO\" id=\"VVe-lM-08F\">\n                                <textField key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NZa-CW-72p\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"100\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"E-mail Address:\" id=\"Vhu-bj-bYq\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"XNp-Sk-9kP\" column=\"phr-gg-3df\" id=\"ELo-tV-WtX\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rVI-TX-GRu\" customClass=\"TVCValidatedTextField\">\n                                    <rect key=\"frame\" x=\"104\" y=\"0.0\" width=\"226\" height=\"22\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"riT-8a-GoU\"/>\n                                    </constraints>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"Fsp-5h-Da6\" customClass=\"TVCValidatedTextFieldCell\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                    </textFieldCell>\n                                    <accessibility description=\"E-mail address to associate with license key\"/>\n                                </textField>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"Jam-O7-WoM\" firstAttribute=\"leading\" secondItem=\"caz-XB-TnX\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"2SD-mE-6cd\"/>\n                    <constraint firstItem=\"F12-H0-P9Z\" firstAttribute=\"top\" secondItem=\"gBo-7N-KkR\" secondAttribute=\"top\" constant=\"20\" symbolic=\"YES\" id=\"2VN-NF-6OU\"/>\n                    <constraint firstItem=\"Jam-O7-WoM\" firstAttribute=\"firstBaseline\" secondItem=\"caz-XB-TnX\" secondAttribute=\"firstBaseline\" id=\"6Rq-7H-NUS\"/>\n                    <constraint firstItem=\"1RR-lW-kgH\" firstAttribute=\"leading\" secondItem=\"gBo-7N-KkR\" secondAttribute=\"leading\" constant=\"20\" id=\"BK9-gX-Em5\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"1RR-lW-kgH\" secondAttribute=\"trailing\" constant=\"20\" id=\"CLC-PE-fHv\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Jam-O7-WoM\" secondAttribute=\"trailing\" constant=\"20\" id=\"Csy-gA-e4q\"/>\n                    <constraint firstItem=\"caz-XB-TnX\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"gBo-7N-KkR\" secondAttribute=\"leading\" constant=\"20\" id=\"KPZ-1u-jhI\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"F12-H0-P9Z\" secondAttribute=\"trailing\" constant=\"20\" id=\"KwJ-66-7q0\"/>\n                    <constraint firstItem=\"Jam-O7-WoM\" firstAttribute=\"top\" secondItem=\"1RR-lW-kgH\" secondAttribute=\"bottom\" constant=\"20\" id=\"V69-xp-ohJ\"/>\n                    <constraint firstItem=\"F12-H0-P9Z\" firstAttribute=\"leading\" secondItem=\"gBo-7N-KkR\" secondAttribute=\"leading\" constant=\"20\" id=\"Y0u-1y-hv1\"/>\n                    <constraint firstItem=\"1RR-lW-kgH\" firstAttribute=\"top\" secondItem=\"F12-H0-P9Z\" secondAttribute=\"bottom\" constant=\"14\" id=\"hhC-ha-xtQ\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Jam-O7-WoM\" secondAttribute=\"bottom\" constant=\"20\" id=\"yOO-X1-aCZ\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"ALC-xI-Yqc\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"278\" y=\"270\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseManagerRecoverLostLicenseSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseManagerRecoverLostLicenseSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"GuT-8v-aNV\" id=\"lbg-ky-mm4\"/>\n                <outlet property=\"contactAddressTextField\" destination=\"RLC-SX-HOX\" id=\"vWD-ue-UZM\"/>\n                <outlet property=\"okButton\" destination=\"3wc-zV-dNO\" id=\"3iY-Q8-Pjz\"/>\n                <outlet property=\"sheet\" destination=\"gIn-WG-UO6\" id=\"dbm-eR-wEi\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"gIn-WG-UO6\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"765\" y=\"571\" width=\"370\" height=\"149\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"Lpx-CQ-7HY\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"370\" height=\"148\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BdN-s0-jEO\">\n                        <rect key=\"frame\" x=\"18\" y=\"96\" width=\"334\" height=\"32\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Enter the e-mail address used when purchasing Textual to recover your license key(s).\" id=\"v6x-ej-Sxw\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RLC-SX-HOX\" customClass=\"TVCValidatedTextField\">\n                        <rect key=\"frame\" x=\"124\" y=\"60\" width=\"226\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"tER-gy-61J\"/>\n                        </constraints>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"PKO-ZT-PPs\" customClass=\"TVCValidatedTextFieldCell\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                        </textFieldCell>\n                        <accessibility description=\"E-mail address associated with order\"/>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"N64-jt-SMG\"/>\n                        </connections>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l4F-Hq-LJS\">\n                        <rect key=\"frame\" x=\"18\" y=\"64\" width=\"100\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"E-mail Address:\" id=\"Cbk-SL-qTh\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3wc-zV-dNO\">\n                        <rect key=\"frame\" x=\"193\" y=\"13\" width=\"164\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Recover Lost License\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"N4b-7q-PPZ\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Recover Lost License\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"HJy-bC-hmd\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GuT-8v-aNV\">\n                        <rect key=\"frame\" x=\"119\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"KNw-Jq-eAB\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"mpA-Xl-LMf\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"3wc-zV-dNO\" firstAttribute=\"leading\" secondItem=\"GuT-8v-aNV\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"15w-2z-PZq\"/>\n                    <constraint firstItem=\"3wc-zV-dNO\" firstAttribute=\"firstBaseline\" secondItem=\"GuT-8v-aNV\" secondAttribute=\"firstBaseline\" id=\"65z-on-n1I\"/>\n                    <constraint firstItem=\"GuT-8v-aNV\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Lpx-CQ-7HY\" secondAttribute=\"leading\" constant=\"20\" id=\"HpO-8h-3zq\"/>\n                    <constraint firstItem=\"BdN-s0-jEO\" firstAttribute=\"top\" secondItem=\"Lpx-CQ-7HY\" secondAttribute=\"top\" constant=\"20\" id=\"Mu4-N2-5yu\"/>\n                    <constraint firstItem=\"RLC-SX-HOX\" firstAttribute=\"top\" secondItem=\"BdN-s0-jEO\" secondAttribute=\"bottom\" constant=\"14\" id=\"Prg-Eg-dBB\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"3wc-zV-dNO\" secondAttribute=\"bottom\" constant=\"20\" id=\"TSC-y7-KMc\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"RLC-SX-HOX\" secondAttribute=\"trailing\" constant=\"20\" id=\"WLR-Lc-YFZ\"/>\n                    <constraint firstItem=\"BdN-s0-jEO\" firstAttribute=\"leading\" secondItem=\"Lpx-CQ-7HY\" secondAttribute=\"leading\" constant=\"20\" id=\"ad4-im-3Ms\"/>\n                    <constraint firstItem=\"3wc-zV-dNO\" firstAttribute=\"top\" secondItem=\"RLC-SX-HOX\" secondAttribute=\"bottom\" constant=\"20\" id=\"bag-pO-WBU\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"BdN-s0-jEO\" secondAttribute=\"trailing\" constant=\"20\" id=\"eXU-6q-6vF\"/>\n                    <constraint firstItem=\"l4F-Hq-LJS\" firstAttribute=\"leading\" secondItem=\"Lpx-CQ-7HY\" secondAttribute=\"leading\" constant=\"20\" id=\"jEZ-Fz-CFl\"/>\n                    <constraint firstItem=\"RLC-SX-HOX\" firstAttribute=\"leading\" secondItem=\"l4F-Hq-LJS\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"oYP-Lh-Ux1\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"3wc-zV-dNO\" secondAttribute=\"trailing\" constant=\"20\" id=\"pmf-YU-mb7\"/>\n                    <constraint firstItem=\"l4F-Hq-LJS\" firstAttribute=\"firstBaseline\" secondItem=\"RLC-SX-HOX\" secondAttribute=\"firstBaseline\" id=\"uKe-BV-qlt\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"aWb-MA-zaG\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"345.5\" y=\"408\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseUpgradeActivateSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseUpgradeActivateSheet\">\n            <connections>\n                <outlet property=\"sheetEligibleDiscount\" destination=\"5MA-QY-tCu\" id=\"YhW-GO-SA1\"/>\n                <outlet property=\"sheetEligibleDiscountSuppressionButton\" destination=\"2SF-Ht-d5j\" id=\"ivY-A8-fVn\"/>\n                <outlet property=\"sheetEligibleDiscountTitleTextField\" destination=\"Nyv-md-SOc\" id=\"gx8-mh-RRX\"/>\n                <outlet property=\"sheetEligibleFree\" destination=\"W7a-9a-xd5\" id=\"4vY-4E-qTY\"/>\n                <outlet property=\"sheetEligibleFreeSuppressionButton\" destination=\"0o9-2E-KZX\" id=\"k5P-hv-Pjg\"/>\n                <outlet property=\"sheetEligibleFreeTitleTextField\" destination=\"9DC-Cm-7Ox\" id=\"1Wf-1k-t7v\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"W7a-9a-xd5\" userLabel=\"Activate Reduced License Sheet\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"550\" height=\"180\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"720\"/>\n            <view key=\"contentView\" id=\"SB9-Q0-CzN\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"180\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9DC-Cm-7Ox\">\n                        <rect key=\"frame\" x=\"103\" y=\"114\" width=\"429\" height=\"48\"/>\n                        <textFieldCell key=\"cell\" controlSize=\"mini\" sendsActionOnEndEditing=\"YES\" id=\"agn-ju-nqr\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <string key=\"title\">You recently checked the upgrade eligibility for the license key “%@“ and it was determined that you are eligible for a free upgrade.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cK1-OF-8hQ\">\n                        <rect key=\"frame\" x=\"20\" y=\"97\" width=\"65\" height=\"65\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" secondItem=\"cK1-OF-8hQ\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"2dY-id-p8I\"/>\n                            <constraint firstAttribute=\"width\" constant=\"65\" id=\"6DE-IJ-9J1\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"c9J-Ve-qDK\"/>\n                        <accessibility description=\"Textual Logo\"/>\n                    </imageView>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JWM-xV-yeI\">\n                        <rect key=\"frame\" x=\"103\" y=\"90\" width=\"429\" height=\"14\"/>\n                        <textFieldCell key=\"cell\" controlSize=\"mini\" sendsActionOnEndEditing=\"YES\" title=\"Click “Activate Textual“ button to activate this license.\" id=\"rv5-Cc-yyP\">\n                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0o9-2E-KZX\">\n                        <rect key=\"frame\" x=\"103\" y=\"57\" width=\"222\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Do not show this message again\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"kZv-2K-5bI\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Q4Q-Jx-jim\">\n                        <rect key=\"frame\" x=\"407\" y=\"11\" width=\"130\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Activate Textual\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"qrA-X1-UYV\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionActivateLicense:\" target=\"-2\" id=\"uxP-LI-z7K\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JZc-k5-pGr\">\n                        <rect key=\"frame\" x=\"283\" y=\"11\" width=\"126\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close Message\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"afW-I7-Zd6\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionCancel:\" target=\"-2\" id=\"tmf-SC-buC\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"9DC-Cm-7Ox\" secondAttribute=\"trailing\" constant=\"20\" id=\"0CD-4F-VLA\"/>\n                    <constraint firstItem=\"0o9-2E-KZX\" firstAttribute=\"leading\" secondItem=\"JWM-xV-yeI\" secondAttribute=\"leading\" id=\"0nC-WK-Fis\"/>\n                    <constraint firstItem=\"JZc-k5-pGr\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"SB9-Q0-CzN\" secondAttribute=\"leading\" constant=\"105\" id=\"2QL-en-iGK\"/>\n                    <constraint firstItem=\"9DC-Cm-7Ox\" firstAttribute=\"top\" secondItem=\"SB9-Q0-CzN\" secondAttribute=\"top\" constant=\"18\" id=\"4zM-Pe-BH9\"/>\n                    <constraint firstItem=\"JWM-xV-yeI\" firstAttribute=\"top\" secondItem=\"9DC-Cm-7Ox\" secondAttribute=\"bottom\" constant=\"10\" id=\"BU4-4J-0bZ\"/>\n                    <constraint firstItem=\"0o9-2E-KZX\" firstAttribute=\"top\" secondItem=\"JWM-xV-yeI\" secondAttribute=\"bottom\" constant=\"16\" id=\"HqP-Qg-Chv\"/>\n                    <constraint firstItem=\"Q4Q-Jx-jim\" firstAttribute=\"leading\" secondItem=\"JZc-k5-pGr\" secondAttribute=\"trailing\" constant=\"12\" id=\"R8f-Ef-3q8\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Q4Q-Jx-jim\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ump-nI-P01\"/>\n                    <constraint firstItem=\"Q4Q-Jx-jim\" firstAttribute=\"top\" secondItem=\"0o9-2E-KZX\" secondAttribute=\"bottom\" constant=\"20\" id=\"Y1N-go-jhE\"/>\n                    <constraint firstItem=\"JZc-k5-pGr\" firstAttribute=\"firstBaseline\" secondItem=\"Q4Q-Jx-jim\" secondAttribute=\"firstBaseline\" id=\"Y5P-yA-Rjb\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"JWM-xV-yeI\" secondAttribute=\"trailing\" constant=\"20\" id=\"bvT-DZ-Pp5\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"Q4Q-Jx-jim\" secondAttribute=\"bottom\" constant=\"18\" id=\"cf3-47-kxv\"/>\n                    <constraint firstItem=\"9DC-Cm-7Ox\" firstAttribute=\"leading\" secondItem=\"cK1-OF-8hQ\" secondAttribute=\"trailing\" constant=\"20\" id=\"ev9-Fo-UKw\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"0o9-2E-KZX\" secondAttribute=\"trailing\" constant=\"20\" id=\"hTt-Ba-AtZ\"/>\n                    <constraint firstItem=\"cK1-OF-8hQ\" firstAttribute=\"leading\" secondItem=\"SB9-Q0-CzN\" secondAttribute=\"leading\" constant=\"20\" id=\"kVE-ie-dyJ\"/>\n                    <constraint firstItem=\"cK1-OF-8hQ\" firstAttribute=\"top\" secondItem=\"SB9-Q0-CzN\" secondAttribute=\"top\" constant=\"18\" id=\"s4Y-Bj-ooI\"/>\n                    <constraint firstItem=\"JWM-xV-yeI\" firstAttribute=\"leading\" secondItem=\"9DC-Cm-7Ox\" secondAttribute=\"leading\" id=\"t0k-H1-gh0\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"9pT-TM-GLY\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"367\" y=\"202\"/>\n        </window>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"5MA-QY-tCu\" userLabel=\"Activate Free License Sheet\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"550\" height=\"208\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"720\"/>\n            <view key=\"contentView\" id=\"U5i-TO-XPF\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"208\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nyv-md-SOc\">\n                        <rect key=\"frame\" x=\"103\" y=\"142\" width=\"429\" height=\"48\"/>\n                        <textFieldCell key=\"cell\" controlSize=\"mini\" sendsActionOnEndEditing=\"YES\" id=\"cKq-oq-zBz\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <string key=\"title\">You recently checked the upgrade eligibility for the license key “%@“ and it was determined that you are eligible for a discounted upgrade.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aXS-Qj-RLk\">\n                        <rect key=\"frame\" x=\"20\" y=\"125\" width=\"65\" height=\"65\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"65\" id=\"SKK-db-McA\"/>\n                            <constraint firstAttribute=\"width\" secondItem=\"aXS-Qj-RLk\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"wPf-3n-hCN\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"rq0-Lj-paJ\"/>\n                        <accessibility description=\"Textual Logo\"/>\n                    </imageView>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"o0n-HD-iWG\">\n                        <rect key=\"frame\" x=\"103\" y=\"90\" width=\"429\" height=\"42\"/>\n                        <textFieldCell key=\"cell\" controlSize=\"mini\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" id=\"64r-7V-Omc\">\n                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                            <string key=\"title\">Click “Purchase Upgrade“ button to purchase the upgrade.\n\nClick “Activate Textual“ button to activate this license.</string>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2SF-Ht-d5j\">\n                        <rect key=\"frame\" x=\"103\" y=\"57\" width=\"222\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Do not show this message again\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"6UQ-dP-l0Z\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EfF-Qd-ylO\">\n                        <rect key=\"frame\" x=\"98\" y=\"11\" width=\"126\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close Message\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"oAZ-QL-JtH\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionCancel:\" target=\"-2\" id=\"Kwp-FW-0xV\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HF7-u3-fmP\">\n                        <rect key=\"frame\" x=\"407\" y=\"11\" width=\"130\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Activate Textual\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"lW4-c3-Bi6\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionActivateLicense:\" target=\"-2\" id=\"XKc-ms-bBu\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zze-6B-XGM\">\n                        <rect key=\"frame\" x=\"262\" y=\"11\" width=\"147\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Purchase Upgrade\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"OHW-Bn-Wo5\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionPurchaseUpgrade:\" target=\"-2\" id=\"Ozi-p9-UH1\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"EfF-Qd-ylO\" firstAttribute=\"firstBaseline\" secondItem=\"Zze-6B-XGM\" secondAttribute=\"firstBaseline\" id=\"1sU-7s-lvt\"/>\n                    <constraint firstItem=\"HF7-u3-fmP\" firstAttribute=\"top\" secondItem=\"2SF-Ht-d5j\" secondAttribute=\"bottom\" constant=\"20\" id=\"BJT-wo-GWU\"/>\n                    <constraint firstItem=\"aXS-Qj-RLk\" firstAttribute=\"leading\" secondItem=\"U5i-TO-XPF\" secondAttribute=\"leading\" constant=\"20\" id=\"CY5-7i-Bvl\"/>\n                    <constraint firstItem=\"Nyv-md-SOc\" firstAttribute=\"top\" secondItem=\"U5i-TO-XPF\" secondAttribute=\"top\" constant=\"18\" id=\"EFL-45-o4J\"/>\n                    <constraint firstItem=\"Zze-6B-XGM\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"EfF-Qd-ylO\" secondAttribute=\"trailing\" constant=\"25\" id=\"FUI-3Z-c3e\"/>\n                    <constraint firstItem=\"aXS-Qj-RLk\" firstAttribute=\"top\" secondItem=\"U5i-TO-XPF\" secondAttribute=\"top\" constant=\"18\" id=\"GcM-FX-qpA\"/>\n                    <constraint firstItem=\"2SF-Ht-d5j\" firstAttribute=\"leading\" secondItem=\"o0n-HD-iWG\" secondAttribute=\"leading\" id=\"UI7-4w-0ZF\"/>\n                    <constraint firstItem=\"Zze-6B-XGM\" firstAttribute=\"firstBaseline\" secondItem=\"HF7-u3-fmP\" secondAttribute=\"firstBaseline\" id=\"W8C-BG-lol\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"o0n-HD-iWG\" secondAttribute=\"trailing\" constant=\"20\" id=\"XdF-uB-blQ\"/>\n                    <constraint firstItem=\"HF7-u3-fmP\" firstAttribute=\"leading\" secondItem=\"Zze-6B-XGM\" secondAttribute=\"trailing\" constant=\"12\" id=\"YFg-HT-QBG\"/>\n                    <constraint firstItem=\"o0n-HD-iWG\" firstAttribute=\"top\" secondItem=\"Nyv-md-SOc\" secondAttribute=\"bottom\" constant=\"10\" id=\"YwO-Zl-me2\"/>\n                    <constraint firstItem=\"o0n-HD-iWG\" firstAttribute=\"leading\" secondItem=\"Nyv-md-SOc\" secondAttribute=\"leading\" id=\"Zer-Fw-IWR\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"2SF-Ht-d5j\" secondAttribute=\"trailing\" constant=\"20\" id=\"eDO-eP-7EX\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"HF7-u3-fmP\" secondAttribute=\"trailing\" constant=\"20\" id=\"ikv-7B-Azm\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Nyv-md-SOc\" secondAttribute=\"trailing\" constant=\"20\" id=\"lew-Li-vff\"/>\n                    <constraint firstItem=\"Nyv-md-SOc\" firstAttribute=\"leading\" secondItem=\"aXS-Qj-RLk\" secondAttribute=\"trailing\" constant=\"20\" id=\"mjk-z9-gVO\"/>\n                    <constraint firstItem=\"2SF-Ht-d5j\" firstAttribute=\"top\" secondItem=\"o0n-HD-iWG\" secondAttribute=\"bottom\" constant=\"16\" id=\"t8s-gG-DrC\"/>\n                    <constraint firstItem=\"EfF-Qd-ylO\" firstAttribute=\"leading\" secondItem=\"U5i-TO-XPF\" secondAttribute=\"leading\" constant=\"105\" id=\"uMN-ky-CmI\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"HF7-u3-fmP\" secondAttribute=\"bottom\" constant=\"18\" id=\"v58-Hu-03X\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"flr-gX-buN\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"367\" y=\"-79\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseUpgradeDialog.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseUpgradeDialog\">\n            <connections>\n                <outlet property=\"upgradeDialogContinueTrialButton\" destination=\"a7n-39-cGg\" id=\"VeP-aW-tfe\"/>\n                <outlet property=\"upgradeDialogTrialPeriodTextField\" destination=\"ucd-Qu-Uhy\" id=\"ogM-Wh-9Oy\"/>\n                <outlet property=\"window\" destination=\"M9l-C7-U7y\" id=\"bc6-Bb-yid\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Welcome to Textual 7\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" id=\"M9l-C7-U7y\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"128\" y=\"143\" width=\"450\" height=\"484\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"500\" height=\"484\"/>\n            <view key=\"contentView\" id=\"EoC-tq-z8D\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"450\" height=\"505\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ns3-OP-zFx\">\n                        <rect key=\"frame\" x=\"116\" y=\"458\" width=\"219\" height=\"27\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Welcome to Textual 7\" id=\"lbE-e4-Mr5\">\n                            <font key=\"font\" metaFont=\"system\" size=\"23\"/>\n                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7kB-e4-GqC\">\n                        <rect key=\"frame\" x=\"133\" y=\"288\" width=\"184\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Textual 7 is a paid upgrade.\" id=\"plM-2e-3wr\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SNs-UD-Sff\">\n                        <rect key=\"frame\" x=\"160\" y=\"320\" width=\"130\" height=\"130\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"130\" id=\"Pdt-yO-ZwO\"/>\n                            <constraint firstAttribute=\"width\" secondItem=\"SNs-UD-Sff\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"Uz7-Ap-c3m\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" image=\"applicationIcon\" id=\"8U9-th-Azn\"/>\n                    </imageView>\n                    <gridView xPlacement=\"fill\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p5z-Y7-2Ym\">\n                        <rect key=\"frame\" x=\"61\" y=\"56\" width=\"329\" height=\"68\"/>\n                        <rows>\n                            <gridRow id=\"8xF-Em-ygn\"/>\n                            <gridRow id=\"TPf-9X-Efr\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn width=\"160\" id=\"XAm-Kg-c1c\"/>\n                            <gridColumn width=\"160\" id=\"UuM-Xg-zo6\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"8xF-Em-ygn\" column=\"XAm-Kg-c1c\" id=\"3VX-FF-mzc\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6lE-Ff-tpp\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"37\" width=\"160\" height=\"32\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"30\" id=\"cEl-Jl-ZIs\"/>\n                                    </constraints>\n                                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Learn More\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"8Pq-ts-x6c\">\n                                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\" size=\"14\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"actionLearnMore:\" target=\"-2\" id=\"vgY-D8-n6Y\"/>\n                                    </connections>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"8xF-Em-ygn\" column=\"UuM-Xg-zo6\" id=\"HAQ-4o-0sB\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"a7n-39-cGg\">\n                                    <rect key=\"frame\" x=\"169\" y=\"37\" width=\"160\" height=\"32\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"30\" id=\"nau-b9-7UQ\"/>\n                                    </constraints>\n                                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Continue Trial\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"PfC-oF-FOO\">\n                                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\" size=\"14\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"actionContinueTrial:\" target=\"-2\" id=\"PdV-FF-27X\"/>\n                                    </connections>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"TPf-9X-Efr\" column=\"XAm-Kg-c1c\" id=\"VBN-tz-JgA\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"og8-aK-73S\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"-1\" width=\"160\" height=\"32\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"30\" id=\"eTh-Hi-wxZ\"/>\n                                    </constraints>\n                                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Remind Me Later\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"EQn-K5-OPg\">\n                                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\" size=\"14\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"actionRemindMeLater:\" target=\"-2\" id=\"DoP-ve-42V\"/>\n                                    </connections>\n                                </button>\n                            </gridCell>\n                            <gridCell row=\"TPf-9X-Efr\" column=\"UuM-Xg-zo6\" id=\"u0x-Vb-JdE\">\n                                <button key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qVP-j2-o1D\">\n                                    <rect key=\"frame\" x=\"169\" y=\"-1\" width=\"160\" height=\"32\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"30\" id=\"alR-Ib-O7a\"/>\n                                    </constraints>\n                                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Check Eligibility\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"aew-ZV-7Gj\">\n                                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\" size=\"14\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"actionPurchaseUpgrade:\" target=\"-2\" id=\"uaa-bq-XNJ\"/>\n                                    </connections>\n                                </button>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uTn-LK-xYI\">\n                        <rect key=\"frame\" x=\"18\" y=\"144\" width=\"414\" height=\"128\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" id=\"eQe-9k-nZa\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">Textual 7, the next generation of the app, is now available as a paid upgrade.\n\nTo make this upgrade as smooth as possible, you may be eligible for a free or discounted upgrade; depending on when you purchased the app. \n\nClick “Check Eligibility\" to find out which you are eligible for.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ucd-Qu-Uhy\">\n                        <rect key=\"frame\" x=\"91\" y=\"20\" width=\"268\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Your trial of Textual will expire in 30 days\" id=\"u8E-ij-xBX\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"ucd-Qu-Uhy\" secondAttribute=\"bottom\" constant=\"20\" id=\"1PP-KO-e6m\"/>\n                    <constraint firstItem=\"ns3-OP-zFx\" firstAttribute=\"top\" secondItem=\"EoC-tq-z8D\" secondAttribute=\"top\" constant=\"20\" id=\"8f7-cx-T75\"/>\n                    <constraint firstItem=\"7kB-e4-GqC\" firstAttribute=\"top\" secondItem=\"SNs-UD-Sff\" secondAttribute=\"bottom\" constant=\"16\" id=\"8jh-v4-ZsQ\"/>\n                    <constraint firstItem=\"uTn-LK-xYI\" firstAttribute=\"top\" secondItem=\"7kB-e4-GqC\" secondAttribute=\"bottom\" constant=\"16\" id=\"LDl-kl-bnc\"/>\n                    <constraint firstItem=\"ucd-Qu-Uhy\" firstAttribute=\"centerX\" secondItem=\"7kB-e4-GqC\" secondAttribute=\"centerX\" id=\"TjB-pe-YLy\"/>\n                    <constraint firstItem=\"7kB-e4-GqC\" firstAttribute=\"centerX\" secondItem=\"SNs-UD-Sff\" secondAttribute=\"centerX\" id=\"XFO-GH-9ej\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"uTn-LK-xYI\" secondAttribute=\"trailing\" constant=\"20\" id=\"ZsR-N9-1gP\"/>\n                    <constraint firstItem=\"p5z-Y7-2Ym\" firstAttribute=\"top\" secondItem=\"uTn-LK-xYI\" secondAttribute=\"bottom\" constant=\"20\" id=\"cqm-4v-S8D\"/>\n                    <constraint firstItem=\"ucd-Qu-Uhy\" firstAttribute=\"top\" secondItem=\"p5z-Y7-2Ym\" secondAttribute=\"bottom\" constant=\"20\" id=\"ekC-0F-doz\"/>\n                    <constraint firstItem=\"uTn-LK-xYI\" firstAttribute=\"leading\" secondItem=\"EoC-tq-z8D\" secondAttribute=\"leading\" constant=\"20\" id=\"fLo-2g-QnJ\"/>\n                    <constraint firstItem=\"SNs-UD-Sff\" firstAttribute=\"centerX\" secondItem=\"ns3-OP-zFx\" secondAttribute=\"centerX\" id=\"nz3-1P-bKV\"/>\n                    <constraint firstItem=\"SNs-UD-Sff\" firstAttribute=\"top\" secondItem=\"ns3-OP-zFx\" secondAttribute=\"bottom\" constant=\"8\" id=\"oS2-i3-Vo8\"/>\n                    <constraint firstItem=\"ns3-OP-zFx\" firstAttribute=\"centerX\" secondItem=\"EoC-tq-z8D\" secondAttribute=\"centerX\" id=\"t2C-q5-pkp\"/>\n                    <constraint firstItem=\"p5z-Y7-2Ym\" firstAttribute=\"centerX\" secondItem=\"EoC-tq-z8D\" secondAttribute=\"centerX\" id=\"xXS-ls-WS6\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"l9H-wU-QXZ\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"69\" y=\"319.5\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCLicenseUpgradeEligibilitySheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23504\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23504\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCLicenseUpgradeEligibilitySheet\">\n            <connections>\n                <outlet property=\"sheetEligibleDiscount\" destination=\"Vqb-So-6Ho\" id=\"FcV-wg-1xZ\"/>\n                <outlet property=\"sheetEligibleFree\" destination=\"NMV-Qs-7lz\" id=\"ipU-V8-UQb\"/>\n                <outlet property=\"sheetNotEligible\" destination=\"s7V-Ks-YGu\" id=\"zCY-RA-d6f\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"s7V-Ks-YGu\" userLabel=\"Eligibility Check - Not\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <rect key=\"contentRect\" x=\"128\" y=\"143\" width=\"370\" height=\"260\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"zmB-R2-bXm\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"370\" height=\"209\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eX9-9T-nFn\">\n                        <rect key=\"frame\" x=\"91\" y=\"165\" width=\"188\" height=\"24\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"You are not eligible.\" id=\"oiB-Uh-16m\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"20\"/>\n                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"86o-pP-6Hi\">\n                        <rect key=\"frame\" x=\"42\" y=\"118\" width=\"286\" height=\"32\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Unfortunately, you are not eligible for a free or discounted upgrade.\" id=\"axq-6T-VR5\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Ln-qj-Yq8\">\n                        <rect key=\"frame\" x=\"40\" y=\"59\" width=\"290\" height=\"40\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Purchase in Codeux Software Store\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"cbV-gz-k63\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\" size=\"15\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"38\" id=\"95Y-b1-mQ6\"/>\n                            <constraint firstAttribute=\"width\" constant=\"290\" id=\"Qdg-yS-3I1\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"actionPurchaseStandalone:\" target=\"-2\" id=\"mAQ-mY-NVy\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aEw-pj-DLf\">\n                        <rect key=\"frame\" x=\"151\" y=\"13\" width=\"69\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"YZx-ou-Quq\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionClose:\" target=\"-2\" id=\"bUV-gQ-Jnd\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"86o-pP-6Hi\" firstAttribute=\"top\" secondItem=\"eX9-9T-nFn\" secondAttribute=\"bottom\" constant=\"15\" id=\"3Tz-Zv-TwS\"/>\n                    <constraint firstItem=\"aEw-pj-DLf\" firstAttribute=\"centerX\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"centerX\" id=\"Hwr-CQ-GPg\"/>\n                    <constraint firstItem=\"86o-pP-6Hi\" firstAttribute=\"leading\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"leading\" constant=\"44\" id=\"L2Y-de-Tvu\"/>\n                    <constraint firstItem=\"0Ln-qj-Yq8\" firstAttribute=\"top\" secondItem=\"86o-pP-6Hi\" secondAttribute=\"bottom\" constant=\"20\" id=\"MN6-ai-PDT\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"aEw-pj-DLf\" secondAttribute=\"bottom\" constant=\"20\" id=\"Qcu-ML-BJW\"/>\n                    <constraint firstItem=\"eX9-9T-nFn\" firstAttribute=\"centerX\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"centerX\" id=\"SlH-Zp-lew\"/>\n                    <constraint firstItem=\"eX9-9T-nFn\" firstAttribute=\"top\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"top\" constant=\"20\" id=\"ndK-Ox-HJg\"/>\n                    <constraint firstItem=\"aEw-pj-DLf\" firstAttribute=\"top\" secondItem=\"0Ln-qj-Yq8\" secondAttribute=\"bottom\" constant=\"20\" id=\"phM-Re-3vP\"/>\n                    <constraint firstItem=\"86o-pP-6Hi\" firstAttribute=\"centerX\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"centerX\" id=\"u7r-Br-f5x\"/>\n                    <constraint firstItem=\"0Ln-qj-Yq8\" firstAttribute=\"centerX\" secondItem=\"zmB-R2-bXm\" secondAttribute=\"centerX\" id=\"zox-Pc-vQa\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"A8Q-WT-FhN\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-49\" y=\"44\"/>\n        </window>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"Vqb-So-6Ho\" userLabel=\"Eligibility Check - Reduced\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <rect key=\"contentRect\" x=\"128\" y=\"143\" width=\"380\" height=\"298\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" misplaced=\"YES\" id=\"MHB-dt-yu8\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"380\" height=\"298\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Oi-4c-Yln\">\n                        <rect key=\"frame\" x=\"57\" y=\"246\" width=\"267\" height=\"24\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Your upgrade is discounted!\" id=\"4LA-tc-vdW\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"20\"/>\n                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"svY-JN-wRd\">\n                        <rect key=\"frame\" x=\"22\" y=\"119\" width=\"336\" height=\"112\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"1V5-vh-2id\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">Congratulations, you are eligible for a discount!\n\nClick the “Purchase Upgrade” button to view the price of the upgrade and to purchase it.\n\nWhen your order is finished being processed, click the “Activate Textual“ button to continue.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"W1h-Tu-uqZ\">\n                        <rect key=\"frame\" x=\"156\" y=\"13\" width=\"69\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"zYo-FM-XDl\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionClose:\" target=\"-2\" id=\"o0R-kX-dZA\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mIg-BY-n6R\">\n                        <rect key=\"frame\" x=\"20\" y=\"59\" width=\"168\" height=\"41\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Purchase Upgrade\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Psq-Ta-ai7\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\" size=\"15\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"168\" id=\"gpP-f5-X4S\"/>\n                            <constraint firstAttribute=\"height\" constant=\"39\" id=\"pmZ-lK-JMG\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"actionPurchaseUpgrade:\" target=\"-2\" id=\"fjD-RU-thi\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iK4-4C-6gn\">\n                        <rect key=\"frame\" x=\"192\" y=\"59\" width=\"168\" height=\"41\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Activate Textual\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"oDA-Wn-QrS\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\" size=\"15\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"39\" id=\"daB-pF-r0B\"/>\n                            <constraint firstAttribute=\"width\" constant=\"168\" id=\"rPj-Hi-kCN\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"actionActivateLicense:\" target=\"-2\" id=\"JQM-0j-h3l\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"svY-JN-wRd\" firstAttribute=\"centerX\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"centerX\" id=\"1NM-Ab-v65\"/>\n                    <constraint firstItem=\"mIg-BY-n6R\" firstAttribute=\"top\" secondItem=\"svY-JN-wRd\" secondAttribute=\"bottom\" constant=\"20\" id=\"9Re-oG-ZeM\"/>\n                    <constraint firstItem=\"0Oi-4c-Yln\" firstAttribute=\"centerX\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"centerX\" id=\"Edi-QM-hFh\"/>\n                    <constraint firstItem=\"svY-JN-wRd\" firstAttribute=\"top\" secondItem=\"0Oi-4c-Yln\" secondAttribute=\"bottom\" constant=\"15\" id=\"FRt-HK-aUa\"/>\n                    <constraint firstItem=\"svY-JN-wRd\" firstAttribute=\"leading\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"leading\" constant=\"24\" id=\"PLW-cY-1A0\"/>\n                    <constraint firstItem=\"W1h-Tu-uqZ\" firstAttribute=\"centerX\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"centerX\" id=\"QrT-Ou-HFi\"/>\n                    <constraint firstItem=\"mIg-BY-n6R\" firstAttribute=\"firstBaseline\" secondItem=\"iK4-4C-6gn\" secondAttribute=\"firstBaseline\" id=\"VZY-Dp-5tr\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"W1h-Tu-uqZ\" secondAttribute=\"bottom\" constant=\"20\" id=\"efG-Ly-JWX\"/>\n                    <constraint firstItem=\"W1h-Tu-uqZ\" firstAttribute=\"top\" secondItem=\"mIg-BY-n6R\" secondAttribute=\"bottom\" constant=\"20\" id=\"q2h-vJ-Hr4\"/>\n                    <constraint firstItem=\"0Oi-4c-Yln\" firstAttribute=\"top\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"top\" constant=\"20\" id=\"uCC-Hr-hsv\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"iK4-4C-6gn\" secondAttribute=\"trailing\" constant=\"20\" id=\"uMy-Mf-qvE\"/>\n                    <constraint firstItem=\"mIg-BY-n6R\" firstAttribute=\"leading\" secondItem=\"MHB-dt-yu8\" secondAttribute=\"leading\" constant=\"20\" id=\"w6l-a2-C1b\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"CWu-X2-HAd\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-515\" y=\"373\"/>\n        </window>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"NMV-Qs-7lz\" userLabel=\"Eligibility Check - Free\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <rect key=\"contentRect\" x=\"128\" y=\"143\" width=\"420\" height=\"230\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" misplaced=\"YES\" id=\"TsN-yE-dfp\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"420\" height=\"230\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"USW-SV-QEO\">\n                        <rect key=\"frame\" x=\"110\" y=\"181\" width=\"200\" height=\"24\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Your upgrade is free!\" id=\"swW-rG-FFU\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"20\"/>\n                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PUt-g1-NNM\">\n                        <rect key=\"frame\" x=\"49\" y=\"118\" width=\"322\" height=\"48\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"T1q-Ug-ZcD\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">Congratulations, you are eligible for a free upgrade!\n\nClick the “Activate Textual“ button to continue.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"X2Q-y1-pP6\">\n                        <rect key=\"frame\" x=\"176\" y=\"13\" width=\"69\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"IhF-mk-CHo\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"actionClose:\" target=\"-2\" id=\"BDY-Df-7gd\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VXG-Ri-gpe\">\n                        <rect key=\"frame\" x=\"128\" y=\"59\" width=\"165\" height=\"40\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Activate Textual\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"OZr-al-Gi8\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"15\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"38\" id=\"qmY-Qh-SWX\"/>\n                            <constraint firstAttribute=\"width\" constant=\"165\" id=\"uU3-fo-KWI\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"actionActivateLicense:\" target=\"-2\" id=\"ffc-z4-rzc\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"PUt-g1-NNM\" firstAttribute=\"centerX\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"centerX\" id=\"5ql-42-M2w\"/>\n                    <constraint firstItem=\"USW-SV-QEO\" firstAttribute=\"centerX\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"centerX\" id=\"BVd-J5-LXW\"/>\n                    <constraint firstItem=\"USW-SV-QEO\" firstAttribute=\"top\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"top\" constant=\"20\" id=\"Chb-ro-o6B\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"X2Q-y1-pP6\" secondAttribute=\"bottom\" constant=\"20\" id=\"EQ2-SQ-8Gw\"/>\n                    <constraint firstItem=\"PUt-g1-NNM\" firstAttribute=\"leading\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"leading\" constant=\"51\" id=\"RWQ-Gs-Fyt\"/>\n                    <constraint firstItem=\"PUt-g1-NNM\" firstAttribute=\"top\" secondItem=\"USW-SV-QEO\" secondAttribute=\"bottom\" constant=\"15\" id=\"deE-fa-0Qd\"/>\n                    <constraint firstItem=\"PUt-g1-NNM\" firstAttribute=\"centerX\" secondItem=\"USW-SV-QEO\" secondAttribute=\"centerX\" id=\"eP2-7w-RYK\"/>\n                    <constraint firstItem=\"X2Q-y1-pP6\" firstAttribute=\"centerX\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"centerX\" id=\"qD2-AI-x05\"/>\n                    <constraint firstItem=\"VXG-Ri-gpe\" firstAttribute=\"top\" secondItem=\"PUt-g1-NNM\" secondAttribute=\"bottom\" constant=\"20\" id=\"qby-bw-tpB\"/>\n                    <constraint firstItem=\"VXG-Ri-gpe\" firstAttribute=\"centerX\" secondItem=\"TsN-yE-dfp\" secondAttribute=\"centerX\" id=\"tTj-oi-NW1\"/>\n                    <constraint firstItem=\"X2Q-y1-pP6\" firstAttribute=\"top\" secondItem=\"VXG-Ri-gpe\" secondAttribute=\"bottom\" constant=\"20\" id=\"yw0-IO-2Xa\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"gBF-uB-lZl\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-498\" y=\"29\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCNicknameColorSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCNicknameColorSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"SNT-UD-yxI\" id=\"ODu-L7-TVF\"/>\n                <outlet property=\"nicknameColorWell\" destination=\"PRL-el-8JJ\" id=\"SGu-jV-1U5\"/>\n                <outlet property=\"okButton\" destination=\"bdT-W6-ebh\" id=\"E9i-tb-Zpc\"/>\n                <outlet property=\"sheet\" destination=\"gNj-W9-RE1\" id=\"9Bk-sY-lJ2\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"gNj-W9-RE1\" userLabel=\"Sheet\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"593\" y=\"397\" width=\"315\" height=\"101\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"720\"/>\n            <view key=\"contentView\" id=\"Cdd-Jy-aKw\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"315\" height=\"104\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fbs-59-BbJ\">\n                        <rect key=\"frame\" x=\"18\" y=\"64\" width=\"166\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Change nickname color to:\" id=\"Ril-X5-ce2\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <colorWell translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PRL-el-8JJ\">\n                        <rect key=\"frame\" x=\"190\" y=\"60\" width=\"48\" height=\"24\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"24\" id=\"hdn-qg-gfg\"/>\n                            <constraint firstAttribute=\"width\" constant=\"48\" id=\"jaK-L8-JRC\"/>\n                        </constraints>\n                        <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                    </colorWell>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Wi2-Ib-F3T\">\n                        <rect key=\"frame\" x=\"245\" y=\"60\" width=\"51\" height=\"23\"/>\n                        <buttonCell key=\"cell\" type=\"roundTextured\" title=\"Reset\" bezelStyle=\"texturedRounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"B0R-Mq-sMG\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Reset Color for Nickname\"/>\n                        <connections>\n                            <action selector=\"resetNicknameColor:\" target=\"-2\" id=\"l3S-g4-yfb\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bdT-W6-ebh\">\n                        <rect key=\"frame\" x=\"238\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"HVO-sY-mGM\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"nTK-Ys-UPw\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SNT-UD-yxI\">\n                        <rect key=\"frame\" x=\"164\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"u11-Xe-NNB\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"GB3-wv-mj2\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"bdT-W6-ebh\" firstAttribute=\"top\" secondItem=\"PRL-el-8JJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"1rb-8b-5dE\"/>\n                    <constraint firstItem=\"SNT-UD-yxI\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Cdd-Jy-aKw\" secondAttribute=\"leading\" constant=\"20\" id=\"HWw-Gn-3sa\"/>\n                    <constraint firstItem=\"SNT-UD-yxI\" firstAttribute=\"firstBaseline\" secondItem=\"bdT-W6-ebh\" secondAttribute=\"firstBaseline\" id=\"M1Z-we-XpM\"/>\n                    <constraint firstItem=\"bdT-W6-ebh\" firstAttribute=\"leading\" secondItem=\"SNT-UD-yxI\" secondAttribute=\"trailing\" constant=\"12\" id=\"QnB-rZ-NbI\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Wi2-Ib-F3T\" secondAttribute=\"trailing\" constant=\"20\" id=\"aVs-i1-n4V\"/>\n                    <constraint firstItem=\"Wi2-Ib-F3T\" firstAttribute=\"centerY\" secondItem=\"Fbs-59-BbJ\" secondAttribute=\"centerY\" id=\"cfk-V4-P8i\"/>\n                    <constraint firstItem=\"PRL-el-8JJ\" firstAttribute=\"top\" secondItem=\"Cdd-Jy-aKw\" secondAttribute=\"top\" constant=\"20\" id=\"dfr-gh-2dW\"/>\n                    <constraint firstItem=\"PRL-el-8JJ\" firstAttribute=\"leading\" secondItem=\"Fbs-59-BbJ\" secondAttribute=\"trailing\" constant=\"8\" id=\"iTo-HP-ueb\"/>\n                    <constraint firstItem=\"PRL-el-8JJ\" firstAttribute=\"centerY\" secondItem=\"Fbs-59-BbJ\" secondAttribute=\"centerY\" id=\"j5a-0O-h1H\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"bdT-W6-ebh\" secondAttribute=\"bottom\" constant=\"20\" id=\"qkj-TI-uqS\"/>\n                    <constraint firstItem=\"Wi2-Ib-F3T\" firstAttribute=\"leading\" secondItem=\"PRL-el-8JJ\" secondAttribute=\"trailing\" constant=\"8\" id=\"qnb-KV-iAB\"/>\n                    <constraint firstItem=\"Fbs-59-BbJ\" firstAttribute=\"leading\" secondItem=\"Cdd-Jy-aKw\" secondAttribute=\"leading\" constant=\"20\" id=\"vVn-zc-2tg\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"bdT-W6-ebh\" secondAttribute=\"trailing\" constant=\"20\" id=\"vfR-YI-gMj\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"HQC-jV-a1U\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"22.5\" y=\"233.5\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCPreferences.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23077.2\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23077.2\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCPreferencesController\">\n            <connections>\n                <outlet property=\"addExcludeKeywordButton\" destination=\"KgU-fm-1CL\" id=\"Yh1-uA-Lzy\"/>\n                <outlet property=\"checkForUpdatesAutomaticallyCheck\" destination=\"KM0-Vm-IZi\" id=\"R4h-yt-2DP\"/>\n                <outlet property=\"checkForUpdatesAutomaticallyDownload\" destination=\"rkY-hK-RL3\" id=\"5QO-sY-KiJ\"/>\n                <outlet property=\"checkForUpdatesDontCheck\" destination=\"eyl-gj-5fj\" id=\"K7p-w3-6hU\"/>\n                <outlet property=\"contentViewBehavior\" destination=\"Yrc-pc-3Zr\" id=\"tdC-pL-8hL\"/>\n                <outlet property=\"contentViewChannelManagement\" destination=\"kTM-XW-Yb5\" id=\"yM5-Ac-xep\"/>\n                <outlet property=\"contentViewCommandScope\" destination=\"1YF-k7-FrW\" id=\"cvJ-I0-CaK\"/>\n                <outlet property=\"contentViewCompatibility\" destination=\"e8Q-5b-yYH\" id=\"ydU-7E-b7E\"/>\n                <outlet property=\"contentViewControls\" destination=\"Fnm-DD-Hbc\" id=\"zeT-MV-IWQ\"/>\n                <outlet property=\"contentViewDefaultIRCopMessages\" destination=\"Pkr-Na-yb0\" id=\"lW6-WQ-FZ7\"/>\n                <outlet property=\"contentViewDefaultIdentity\" destination=\"d6J-SH-Xgl\" id=\"wDj-Vh-gXg\"/>\n                <outlet property=\"contentViewFileTransfers\" destination=\"4pD-W0-ghZ\" id=\"KMr-19-ETt\"/>\n                <outlet property=\"contentViewFloodControl\" destination=\"n4A-Pk-quE\" id=\"s0E-dS-fnf\"/>\n                <outlet property=\"contentViewGeneral\" destination=\"Eyz-5p-IkU\" id=\"lw2-bS-xCr\"/>\n                <outlet property=\"contentViewGeneralCheckForUpdatesView\" destination=\"Arz-w3-aT6\" id=\"wbU-Bl-g2b\"/>\n                <outlet property=\"contentViewGeneralStackView\" destination=\"lAf-Xj-H1K\" id=\"Eut-0s-Y13\"/>\n                <outlet property=\"contentViewHiddenPreferences\" destination=\"dAH-Sl-d77\" id=\"h2q-qj-Xb5\"/>\n                <outlet property=\"contentViewHighlights\" destination=\"Jdv-gk-kj9\" id=\"P9m-wf-sUb\"/>\n                <outlet property=\"contentViewIncomingData\" destination=\"KpN-mD-prv\" id=\"hWG-Eo-pZT\"/>\n                <outlet property=\"contentViewInlineMedia\" destination=\"c5A-lx-Ey9\" id=\"x6m-ve-3mh\"/>\n                <outlet property=\"contentViewInstalledAddons\" destination=\"4zD-VW-F1h\" id=\"U25-Vi-LNZ\"/>\n                <outlet property=\"contentViewInterface\" destination=\"2Th-u8-aIC\" id=\"Gix-Hj-gcJ\"/>\n                <outlet property=\"contentViewLogLocation\" destination=\"DPg-Nu-HcZ\" id=\"PDq-j6-Ndz\"/>\n                <outlet property=\"contentViewNotifications\" destination=\"09H-hp-iIC\" id=\"ElI-u9-xUk\"/>\n                <outlet property=\"contentViewOffRecordMessaging\" destination=\"ZYk-23-zvA\" id=\"mIu-XC-Dt6\"/>\n                <outlet property=\"contentViewStyle\" destination=\"oeR-nv-slx\" id=\"lWc-qc-sGt\"/>\n                <outlet property=\"excludeKeywordsArrayController\" destination=\"4313\" id=\"7351\"/>\n                <outlet property=\"excludeKeywordsTable\" destination=\"Vqz-0J-ajG\" id=\"Zh5-qx-YFn\"/>\n                <outlet property=\"fileTransferDownloadDestinationButton\" destination=\"wNd-qD-qDv\" id=\"af3-0V-JEt\"/>\n                <outlet property=\"fileTransferManuallyEnteredIPAddressTextField\" destination=\"gsf-QD-Vkr\" id=\"d3X-Uo-t0B\"/>\n                <outlet property=\"forwardNoticeToQueryButton\" destination=\"uum-Jf-eoo\" id=\"uC4-P1-IBK\"/>\n                <outlet property=\"forwardNoticeToSelectedChannelButton\" destination=\"IcT-S0-dsA\" id=\"FY1-ni-7In\"/>\n                <outlet property=\"forwardNoticeToServerConsoleButton\" destination=\"Fsx-cd-pY6\" id=\"DJW-aV-hhk\"/>\n                <outlet property=\"highlightKeywordsArrayController\" destination=\"4310\" id=\"Wre-n3-NQF\"/>\n                <outlet property=\"highlightKeywordsTable\" destination=\"nIO-jH-FEm\" id=\"rwr-Mr-P5g\"/>\n                <outlet property=\"highlightNicknameButton\" destination=\"IVv-zw-dDv\" id=\"5mn-VV-cM3\"/>\n                <outlet property=\"inlineMediaEnabledButton\" destination=\"Clr-Kc-72d\" id=\"l5P-Kw-58h\"/>\n                <outlet property=\"installedAddonsMenu\" destination=\"mgV-ad-4kQ\" id=\"ysw-NY-ZxI\"/>\n                <outlet property=\"installedScriptsController\" destination=\"92m-WJ-gkY\" id=\"Wsq-Rt-t4M\"/>\n                <outlet property=\"installedScriptsTable\" destination=\"rGf-Ih-C97\" id=\"v8k-0K-zxF\"/>\n                <outlet property=\"navigationToolbar\" destination=\"T7o-OY-4Q7\" id=\"4u5-Ls-XuU\"/>\n                <outlet property=\"notificationController\" destination=\"k8n-cT-p4s\" id=\"tFw-a3-9KL\"/>\n                <outlet property=\"notificationControllerHostView\" destination=\"KFW-OS-9of\" id=\"g3d-vm-Wv1\"/>\n                <outlet property=\"themeSelectionButton\" destination=\"ICa-wc-PBy\" id=\"QAx-VZ-qUR\"/>\n                <outlet property=\"transcriptFolderButton\" destination=\"H7x-dV-MZS\" id=\"uXJ-hj-ydF\"/>\n                <outlet property=\"window\" destination=\"4929\" id=\"4933\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <window title=\"Textual Preferences\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" toolbarStyle=\"preference\" id=\"4929\" userLabel=\"Toolbar Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"367\" y=\"318\" width=\"670\" height=\"240\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <value key=\"minSize\" type=\"size\" width=\"670\" height=\"240\"/>\n            <view key=\"contentView\" id=\"4930\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"240\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            </view>\n            <toolbar key=\"toolbar\" implicitIdentifier=\"25C855D8-AFA8-4FA8-B807-F4295AE35603\" autosavesConfiguration=\"NO\" allowsUserCustomization=\"NO\" showsBaselineSeparator=\"NO\" displayMode=\"iconAndLabel\" sizeMode=\"regular\" id=\"T7o-OY-4Q7\">\n                <allowedToolbarItems>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarSpaceItem\" id=\"QvU-QG-4EI\"/>\n                    <toolbarItem implicitItemIdentifier=\"NSToolbarFlexibleSpaceItem\" id=\"4tt-rO-NHB\"/>\n                    <toolbarItem implicitItemIdentifier=\"85E627A0-4579-4CC9-9CDD-932BB5A5C509\" explicitItemIdentifier=\"101\" label=\"General\" paletteLabel=\"General\" tag=\"101\" image=\"applicationIcon\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"ye6-2h-R4p\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"lUX-Dw-ox4\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"C0AAD6E0-A09C-4F71-A709-5BED1B6033AB\" explicitItemIdentifier=\"102\" label=\"Behavior\" paletteLabel=\"Behavior\" tag=\"102\" image=\"TPWTB_General\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"5Zi-85-Fdl\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"ZOs-3q-dwW\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"828F8CBE-4875-42F2-889B-44C7ABC0A505\" explicitItemIdentifier=\"103\" label=\"Notifications\" paletteLabel=\"Notifications\" tag=\"103\" image=\"TPWTB_Notifications\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"z3r-Sc-CPs\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"yTn-hb-5mQ\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"DAADB4A9-1320-4760-92B4-C87B72E3AC6D\" explicitItemIdentifier=\"104\" label=\"Highlights\" paletteLabel=\"Highlights\" tag=\"104\" image=\"TPWTB_Highlights\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"6P8-n2-nNV\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"qiW-zZ-e38\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"0F260716-789B-4786-B676-0C4237450930\" explicitItemIdentifier=\"105\" label=\"Interface\" paletteLabel=\"Interface\" tag=\"105\" image=\"TPWTB_Interface\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"fzQ-55-v97\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"waW-CS-aPJ\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"35A7A8DC-0CE6-4D72-9808-0A2CF2014FA4\" explicitItemIdentifier=\"106\" label=\"Style\" paletteLabel=\"Style\" tag=\"106\" image=\"TPWTB_Style\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"Ggd-0D-rbs\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"Ia1-Hq-C1G\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"58E4DD0E-BEE2-4844-889E-1BD91F6CBFB9\" explicitItemIdentifier=\"107\" label=\"Controls\" paletteLabel=\"Controls\" tag=\"107\" image=\"TPWTB_Controls\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"e6N-0C-9Eo\">\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"qAU-RF-I8Y\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"2EF7BF85-4F22-4453-B6E7-6713200C2069\" explicitItemIdentifier=\"108\" label=\"Advanced\" paletteLabel=\"Advanced\" tag=\"108\" image=\"TPWTB_Advanced\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"Ljh-iZ-r98\">\n                        <nil key=\"toolTip\"/>\n                        <popUpButton key=\"view\" tag=\"108\" id=\"J0J-90-PIH\">\n                            <rect key=\"frame\" x=\"2\" y=\"14\" width=\"55\" height=\"35\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                            <popUpButtonCell key=\"cell\" type=\"roundTextured\" bezelStyle=\"texturedRounded\" image=\"TPWTB_Advanced\" imagePosition=\"only\" alignment=\"center\" lineBreakMode=\"truncatingTail\" imageScaling=\"proportionallyDown\" inset=\"2\" pullsDown=\"YES\" id=\"o4H-Er-8Yy\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" id=\"W9G-v3-1hY\">\n                                    <items>\n                                        <menuItem image=\"TPWTB_Advanced\" hidden=\"YES\" id=\"FeN-Jh-HW4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Channel Management\" tag=\"108000\" id=\"Smm-FE-xJ9\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"Gex-G0-z8T\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Command Scope\" tag=\"108001\" id=\"Q4n-Bv-BiH\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"Awm-Cl-cbh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Flood Control\" tag=\"108002\" id=\"sgc-UQ-F8E\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"eZ2-O5-ZwN\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Incoming Data\" tag=\"108003\" id=\"HKa-gD-tv3\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"Dyy-4W-dEd\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" hidden=\"YES\" id=\"W4U-AF-ygV\"/>\n                                        <menuItem title=\"Compatibility\" tag=\"108004\" hidden=\"YES\" id=\"FDb-XE-P95\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"wJI-G9-QuF\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"GoV-UM-Is2\"/>\n                                        <menuItem title=\"File Transfers\" tag=\"108005\" id=\"OeQ-Ms-xcp\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"lNC-y4-zJh\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Inline Media\" tag=\"108006\" id=\"yys-I0-cMZ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"h99-K3-frK\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"4Q9-EF-TQw\"/>\n                                        <menuItem title=\"Log Location\" tag=\"108007\" id=\"naX-ng-Lmu\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"yX3-uo-rcl\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"40A-un-kd2\"/>\n                                        <menuItem title=\"Default Identity\" tag=\"108008\" id=\"3qn-2i-mRk\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"bVG-DN-DrK\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Default IRC Operator Messages\" tag=\"108009\" id=\"mVO-0v-1Nc\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"1Tt-jt-zZs\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"Y0B-GY-ayZ\">\n                                            <connections>\n                                                <binding destination=\"G2Q-fc-ddg\" name=\"hidden\" keyPath=\"values.System -&gt; Built with Off-the-Record Messaging Support\" id=\"NtP-3I-5El\">\n                                                    <dictionary key=\"options\">\n                                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                    </dictionary>\n                                                </binding>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Off-the-Record Messaging\" tag=\"108010\" id=\"Abd-Fd-gqU\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"TBI-ND-xPg\"/>\n                                                <binding destination=\"G2Q-fc-ddg\" name=\"hidden\" keyPath=\"values.System -&gt; Built with Off-the-Record Messaging Support\" id=\"2he-Tf-7Pa\">\n                                                    <dictionary key=\"options\">\n                                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                    </dictionary>\n                                                </binding>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <accessibility description=\"Advanced Navigation Destinations\"/>\n                        </popUpButton>\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"73o-gm-Tci\"/>\n                        </connections>\n                    </toolbarItem>\n                    <toolbarItem implicitItemIdentifier=\"19E87B08-365E-4C82-AF67-7AF1D1BA7654\" explicitItemIdentifier=\"109\" label=\"Addons\" paletteLabel=\"Addons\" tag=\"109\" image=\"TPWTB_Addons\" sizingBehavior=\"auto\" selectable=\"YES\" id=\"BVW-Pf-3Qn\">\n                        <nil key=\"toolTip\"/>\n                        <popUpButton key=\"view\" tag=\"109\" id=\"yuI-3m-esZ\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"14\" width=\"55\" height=\"35\"/>\n                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n                            <popUpButtonCell key=\"cell\" type=\"roundTextured\" bezelStyle=\"texturedRounded\" imagePosition=\"only\" alignment=\"center\" lineBreakMode=\"truncatingTail\" imageScaling=\"proportionallyDown\" inset=\"2\" pullsDown=\"YES\" selectedItem=\"b9Y-Fr-JSg\" id=\"sbw-Pi-BcH\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" id=\"mgV-ad-4kQ\">\n                                    <items>\n                                        <menuItem image=\"TPWTB_Addons\" hidden=\"YES\" id=\"b9Y-Fr-JSg\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Installed Addons\" tag=\"109000\" id=\"Im1-Pd-BXM\">\n                                            <connections>\n                                                <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"Y5J-jI-qil\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <accessibility description=\"Addons Navigation Destinations\"/>\n                        </popUpButton>\n                        <connections>\n                            <action selector=\"onPrefPaneSelected:\" target=\"-2\" id=\"yNd-wk-5x5\"/>\n                        </connections>\n                    </toolbarItem>\n                </allowedToolbarItems>\n                <defaultToolbarItems>\n                    <toolbarItem reference=\"ye6-2h-R4p\"/>\n                    <toolbarItem reference=\"4tt-rO-NHB\"/>\n                    <toolbarItem reference=\"6P8-n2-nNV\"/>\n                    <toolbarItem reference=\"z3r-Sc-CPs\"/>\n                    <toolbarItem reference=\"4tt-rO-NHB\"/>\n                    <toolbarItem reference=\"5Zi-85-Fdl\"/>\n                    <toolbarItem reference=\"e6N-0C-9Eo\"/>\n                    <toolbarItem reference=\"fzQ-55-v97\"/>\n                    <toolbarItem reference=\"Ggd-0D-rbs\"/>\n                    <toolbarItem reference=\"4tt-rO-NHB\"/>\n                    <toolbarItem reference=\"BVW-Pf-3Qn\"/>\n                    <toolbarItem reference=\"Ljh-iZ-r98\"/>\n                </defaultToolbarItems>\n            </toolbar>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"6064\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-8535\"/>\n        </window>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Eyz-5p-IkU\" userLabel=\"General\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"199\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bKt-Ac-1I2\">\n                    <rect key=\"frame\" x=\"40\" y=\"152\" width=\"295\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Request confirmation before quitting Textual\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"XAa-aA-vKv\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ConfirmApplicationQuit\" id=\"8NN-qN-fRd\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GlR-W9-ZJo\">\n                    <rect key=\"frame\" x=\"40\" y=\"132\" width=\"590\" height=\"5\"/>\n                </box>\n                <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"0.0\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lAf-Xj-H1K\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"30\" width=\"670\" height=\"86\"/>\n                    <subviews>\n                        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Arz-w3-aT6\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"86\"/>\n                            <subviews>\n                                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L50-Ud-iP2\">\n                                    <rect key=\"frame\" x=\"40\" y=\"70\" width=\"59\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Updates:\" id=\"MC0-wK-dAF\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jfn-Sc-y1D\">\n                                    <rect key=\"frame\" x=\"103\" y=\"-1\" width=\"150\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable beta updates\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"ZpK-O2-jD1\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"onChangedCheckForBetaUpdates:\" target=\"-2\" id=\"L8N-cP-zdY\"/>\n                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ReceiveBetaUpdates\" id=\"kg8-1s-fSU\"/>\n                                    </connections>\n                                </button>\n                                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"4\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rs1-p6-eOx\">\n                                    <rect key=\"frame\" x=\"105\" y=\"30\" width=\"286\" height=\"56\"/>\n                                    <subviews>\n                                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rkY-hK-RL3\">\n                                            <rect key=\"frame\" x=\"-2\" y=\"39\" width=\"288\" height=\"18\"/>\n                                            <buttonCell key=\"cell\" type=\"radio\" title=\"Automatically download and install updates\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"yeE-vC-LNb\">\n                                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"onChangedCheckForUpdates:\" target=\"-2\" id=\"Hhq-9W-xaa\"/>\n                                            </connections>\n                                        </button>\n                                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KM0-Vm-IZi\">\n                                            <rect key=\"frame\" x=\"-2\" y=\"19\" width=\"212\" height=\"18\"/>\n                                            <buttonCell key=\"cell\" type=\"radio\" title=\"Just notify if there are updates\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"Iuw-ng-k0Q\">\n                                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"onChangedCheckForUpdates:\" target=\"-2\" id=\"CfD-E5-khM\"/>\n                                            </connections>\n                                        </button>\n                                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eyl-gj-5fj\">\n                                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"172\" height=\"18\"/>\n                                            <buttonCell key=\"cell\" type=\"radio\" title=\"Don't check for updates\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"SlQ-Ey-5fd\">\n                                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"onChangedCheckForUpdates:\" target=\"-2\" id=\"2qR-a2-GtW\"/>\n                                            </connections>\n                                        </button>\n                                    </subviews>\n                                    <visibilityPriorities>\n                                        <integer value=\"1000\"/>\n                                        <integer value=\"1000\"/>\n                                        <integer value=\"1000\"/>\n                                    </visibilityPriorities>\n                                    <customSpacing>\n                                        <real value=\"3.4028234663852886e+38\"/>\n                                        <real value=\"3.4028234663852886e+38\"/>\n                                        <real value=\"3.4028234663852886e+38\"/>\n                                    </customSpacing>\n                                </stackView>\n                            </subviews>\n                            <constraints>\n                                <constraint firstItem=\"L50-Ud-iP2\" firstAttribute=\"leading\" secondItem=\"Arz-w3-aT6\" secondAttribute=\"leading\" constant=\"42\" id=\"2ci-88-Tqp\"/>\n                                <constraint firstItem=\"rs1-p6-eOx\" firstAttribute=\"leading\" secondItem=\"L50-Ud-iP2\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"ILV-3z-JJV\"/>\n                                <constraint firstItem=\"jfn-Sc-y1D\" firstAttribute=\"leading\" secondItem=\"rs1-p6-eOx\" secondAttribute=\"leading\" id=\"TJ6-iz-bg5\"/>\n                                <constraint firstItem=\"jfn-Sc-y1D\" firstAttribute=\"top\" secondItem=\"rs1-p6-eOx\" secondAttribute=\"bottom\" constant=\"14\" id=\"VDa-qC-Sx1\"/>\n                                <constraint firstItem=\"rs1-p6-eOx\" firstAttribute=\"top\" secondItem=\"Arz-w3-aT6\" secondAttribute=\"top\" id=\"cow-PV-Rx2\"/>\n                                <constraint firstItem=\"L50-Ud-iP2\" firstAttribute=\"firstBaseline\" secondItem=\"rkY-hK-RL3\" secondAttribute=\"firstBaseline\" id=\"mNv-78-rHy\"/>\n                                <constraint firstAttribute=\"bottom\" secondItem=\"jfn-Sc-y1D\" secondAttribute=\"bottom\" id=\"sJr-Sh-fkA\"/>\n                                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"jfn-Sc-y1D\" secondAttribute=\"trailing\" constant=\"20\" id=\"xQS-HA-Q0r\"/>\n                            </constraints>\n                        </customView>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"lAf-Xj-H1K\" secondAttribute=\"bottom\" constant=\"30\" id=\"4aJ-Kq-DdN\"/>\n                <constraint firstItem=\"GlR-W9-ZJo\" firstAttribute=\"centerX\" secondItem=\"Eyz-5p-IkU\" secondAttribute=\"centerX\" id=\"F6Q-dn-TP8\"/>\n                <constraint firstItem=\"bKt-Ac-1I2\" firstAttribute=\"top\" secondItem=\"Eyz-5p-IkU\" secondAttribute=\"top\" constant=\"30\" id=\"Ma8-cM-aWR\"/>\n                <constraint firstItem=\"GlR-W9-ZJo\" firstAttribute=\"leading\" secondItem=\"Eyz-5p-IkU\" secondAttribute=\"leading\" constant=\"40\" id=\"aU0-D3-FEb\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"lAf-Xj-H1K\" secondAttribute=\"trailing\" id=\"cSA-z1-DxP\"/>\n                <constraint firstItem=\"lAf-Xj-H1K\" firstAttribute=\"leading\" secondItem=\"Eyz-5p-IkU\" secondAttribute=\"leading\" id=\"cvm-7s-bPC\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"bKt-Ac-1I2\" secondAttribute=\"trailing\" constant=\"20\" id=\"hPW-7n-PiW\"/>\n                <constraint firstAttribute=\"height\" priority=\"550\" id=\"qUa-FR-bK6\"/>\n                <constraint firstItem=\"lAf-Xj-H1K\" firstAttribute=\"top\" secondItem=\"GlR-W9-ZJo\" secondAttribute=\"bottom\" constant=\"18\" id=\"sh8-NW-aa2\"/>\n                <constraint firstItem=\"GlR-W9-ZJo\" firstAttribute=\"top\" secondItem=\"bKt-Ac-1I2\" secondAttribute=\"bottom\" constant=\"18\" id=\"whZ-Hz-BUA\"/>\n                <constraint firstItem=\"bKt-Ac-1I2\" firstAttribute=\"leading\" secondItem=\"Eyz-5p-IkU\" secondAttribute=\"leading\" constant=\"42\" id=\"xOx-Fd-rV8\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-8134.5\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jdv-gk-kj9\" userLabel=\"Highlights\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"342\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <gridView xPlacement=\"leading\" yPlacement=\"fill\" rowAlignment=\"none\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rIH-aw-8aF\">\n                    <rect key=\"frame\" x=\"81\" y=\"55\" width=\"508\" height=\"182\"/>\n                    <rows>\n                        <gridRow id=\"6Vm-ha-LRz\"/>\n                        <gridRow id=\"ffr-LH-AtI\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn id=\"IJH-Fl-TgR\"/>\n                        <gridColumn id=\"nm6-qe-4j6\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"6Vm-ha-LRz\" column=\"IJH-Fl-TgR\" id=\"1Uf-ox-uPu\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DPo-1x-FIa\">\n                                <rect key=\"frame\" x=\"-2\" y=\"166\" width=\"103\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Highlight words:\" id=\"tR6-jH-Ll6\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"6Vm-ha-LRz\" column=\"nm6-qe-4j6\" id=\"oGQ-JA-r69\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jN5-O0-8cZ\">\n                                <rect key=\"frame\" x=\"256\" y=\"166\" width=\"96\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Exclude words:\" id=\"oKh-Ma-cAV\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.NicknameHighlightMatchingType\" id=\"E0J-R4-TJF\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"ffr-LH-AtI\" column=\"IJH-Fl-TgR\" id=\"95M-Kq-lRn\">\n                            <scrollView key=\"contentView\" autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dtR-hL-16n\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"250\" height=\"160\"/>\n                                <clipView key=\"contentView\" id=\"QyB-ni-plT\">\n                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"248\" height=\"158\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" id=\"nIO-jH-FEm\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"248\" height=\"158\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <tableColumns>\n                                                <tableColumn width=\"206\" minWidth=\"40\" maxWidth=\"1000\" id=\"WJE-D0-e9x\">\n                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                    </tableHeaderCell>\n                                                    <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"ewA-Ga-sCf\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <accessibility description=\"Highlight Keyword\"/>\n                                                    </textFieldCell>\n                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\"/>\n                                                    <connections>\n                                                        <binding destination=\"4310\" name=\"value\" keyPath=\"arrangedObjects.string\" id=\"t3h-DG-Lfa\"/>\n                                                    </connections>\n                                                </tableColumn>\n                                            </tableColumns>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"DPo-1x-FIa\" id=\"G91-3z-WeC\"/>\n                                                <binding destination=\"4310\" name=\"content\" keyPath=\"arrangedObjects\" id=\"N3l-S9-JyH\"/>\n                                                <binding destination=\"4310\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"N3l-S9-JyH\" id=\"XrD-iO-dF4\"/>\n                                                <binding destination=\"4310\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"XrD-iO-dF4\" id=\"Yld-1A-Ab5\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"umD-hc-veL\"/>\n                                            </connections>\n                                        </tableView>\n                                    </subviews>\n                                </clipView>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"250\" id=\"4GF-FM-AdF\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"160\" id=\"xj8-gz-7tL\"/>\n                                </constraints>\n                                <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"nvB-TS-JzJ\">\n                                    <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"181\" height=\"15\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"gLy-IW-Fxd\">\n                                    <rect key=\"frame\" x=\"167\" y=\"1\" width=\"15\" height=\"114\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"DPo-1x-FIa\" id=\"bZe-oE-ca7\"/>\n                                </connections>\n                            </scrollView>\n                        </gridCell>\n                        <gridCell row=\"ffr-LH-AtI\" column=\"nm6-qe-4j6\" id=\"buU-Qo-04O\">\n                            <scrollView key=\"contentView\" autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dIx-e4-L5V\">\n                                <rect key=\"frame\" x=\"258\" y=\"0.0\" width=\"250\" height=\"160\"/>\n                                <clipView key=\"contentView\" id=\"73A-Qg-29i\">\n                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"248\" height=\"158\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" id=\"Vqz-0J-ajG\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"248\" height=\"158\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <tableColumns>\n                                                <tableColumn width=\"205\" minWidth=\"40\" maxWidth=\"1000\" id=\"FZ6-cu-ERb\">\n                                                    <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                        <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                    </tableHeaderCell>\n                                                    <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"Dqe-Ns-Qnk\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <accessibility description=\"Excluded Keyword\"/>\n                                                    </textFieldCell>\n                                                    <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\"/>\n                                                    <connections>\n                                                        <binding destination=\"4313\" name=\"value\" keyPath=\"arrangedObjects.string\" id=\"d7y-Ha-dG2\"/>\n                                                    </connections>\n                                                </tableColumn>\n                                            </tableColumns>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"jN5-O0-8cZ\" id=\"TSz-IV-aGD\"/>\n                                                <binding destination=\"4313\" name=\"content\" keyPath=\"arrangedObjects\" id=\"53y-Fi-lzt\"/>\n                                                <binding destination=\"4313\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"53y-Fi-lzt\" id=\"ggr-RN-PgA\"/>\n                                                <binding destination=\"4313\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"ggr-RN-PgA\" id=\"eIN-nW-2Hs\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"M95-AZ-zx7\"/>\n                                            </connections>\n                                        </tableView>\n                                    </subviews>\n                                </clipView>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"160\" id=\"Rs0-GU-pHS\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"250\" id=\"cff-mN-rxV\"/>\n                                </constraints>\n                                <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"Dxw-kT-38C\">\n                                    <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"181\" height=\"15\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"qRg-kB-9cp\">\n                                    <rect key=\"frame\" x=\"167\" y=\"1\" width=\"15\" height=\"85\"/>\n                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                </scroller>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"jN5-O0-8cZ\" id=\"lLB-i5-bGT\"/>\n                                </connections>\n                            </scrollView>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KgU-fm-1CL\">\n                    <rect key=\"frame\" x=\"339\" y=\"29\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" controlSize=\"mini\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"9PI-h7-aCh\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"miniSystem\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"f2b-dV-VJR\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"u5E-eO-Gn6\"/>\n                    </constraints>\n                    <accessibility description=\"Add Excluded Keyword\"/>\n                    <connections>\n                        <action selector=\"onAddExcludeKeyword:\" target=\"-2\" id=\"grA-d2-jxL\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"faY-0p-PJo\">\n                    <rect key=\"frame\" x=\"40\" y=\"253\" width=\"590\" height=\"5\"/>\n                </box>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nqu-81-VCV\">\n                    <rect key=\"frame\" x=\"81\" y=\"29\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" controlSize=\"mini\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Zrw-3F-rh2\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"miniSystem\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"A8g-Yk-jl2\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"bnJ-Or-wXf\"/>\n                    </constraints>\n                    <accessibility description=\"Add Highlight Keyword\"/>\n                    <connections>\n                        <action selector=\"onAddHighlightKeyword:\" target=\"-2\" id=\"MzR-Ve-Olm\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"G7B-Kp-Af8\">\n                    <rect key=\"frame\" x=\"110\" y=\"29\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"overlaps\" alignment=\"center\" controlSize=\"mini\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"pYZ-UH-gZy\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"miniSystem\"/>\n                    </buttonCell>\n                    <accessibility description=\"Remove Selected Highlight Keyword\"/>\n                    <connections>\n                        <action selector=\"remove:\" target=\"4310\" id=\"itS-hv-Fdw\"/>\n                        <binding destination=\"4310\" name=\"enabled\" keyPath=\"canRemove\" id=\"P3L-bL-EfP\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qcU-SW-8KI\">\n                    <rect key=\"frame\" x=\"370\" y=\"29\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"overlaps\" alignment=\"center\" controlSize=\"mini\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"q8O-20-DrL\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"miniSystem\"/>\n                    </buttonCell>\n                    <accessibility description=\"Remove Selected Excluded Keyword\"/>\n                    <connections>\n                        <action selector=\"remove:\" target=\"4313\" id=\"eKI-75-HAW\"/>\n                        <binding destination=\"4313\" name=\"enabled2\" keyPath=\"canRemove\" previousBinding=\"Qeh-dN-yl0\" id=\"Ycy-TD-1k0\">\n                            <dictionary key=\"options\">\n                                <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                            </dictionary>\n                        </binding>\n                        <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.excludeKeywordsTable.enabled\" id=\"Qeh-dN-yl0\"/>\n                    </connections>\n                </button>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"50\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mdN-TE-pOJ\">\n                    <rect key=\"frame\" x=\"103\" y=\"274\" width=\"465\" height=\"38\"/>\n                    <subviews>\n                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8oP-r2-z2R\">\n                            <rect key=\"frame\" x=\"-3\" y=\"5\" width=\"191\" height=\"25\"/>\n                            <popUpButtonCell key=\"cell\" type=\"push\" title=\"Partial Matches\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" inset=\"2\" selectedItem=\"dnX-v4-Rf4\" id=\"j6z-4b-d9v\">\n                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" title=\"OtherViews\" id=\"bkQ-5U-psQ\">\n                                    <items>\n                                        <menuItem title=\"Partial Matches\" state=\"on\" id=\"dnX-v4-Rf4\"/>\n                                        <menuItem title=\"Full Word Matches\" tag=\"1\" id=\"vam-8x-MyD\"/>\n                                        <menuItem title=\"Regular Expression (ICU)\" tag=\"2\" id=\"S6P-uf-fin\"/>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <accessibility description=\"Highlight Match Type\"/>\n                            <connections>\n                                <action selector=\"onChangedHighlightType:\" target=\"-2\" id=\"IuQ-DS-Bb1\"/>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.NicknameHighlightMatchingType\" id=\"oS6-Kq-Pds\"/>\n                            </connections>\n                        </popUpButton>\n                        <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"6\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lZo-iP-d5m\">\n                            <rect key=\"frame\" x=\"234\" y=\"0.0\" width=\"231\" height=\"38\"/>\n                            <subviews>\n                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xJN-JU-VGr\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"21\" width=\"233\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Log highlights to separate window\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"z4k-RQ-V0s\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <action selector=\"onChangedHighlightLogging:\" target=\"-2\" id=\"ojZ-Hz-fZH\"/>\n                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.LogHighlights\" id=\"b05-J5-F0K\"/>\n                                    </connections>\n                                </button>\n                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IVv-zw-dDv\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"190\" height=\"18\"/>\n                                    <buttonCell key=\"cell\" type=\"check\" title=\"Highlight current nickname\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"9of-Kp-Asv\">\n                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                    </buttonCell>\n                                    <connections>\n                                        <binding destination=\"-2\" name=\"value\" keyPath=\"highlightCurrentNickname\" id=\"fvG-8d-rnu\"/>\n                                    </connections>\n                                </button>\n                            </subviews>\n                            <visibilityPriorities>\n                                <integer value=\"1000\"/>\n                                <integer value=\"1000\"/>\n                            </visibilityPriorities>\n                            <customSpacing>\n                                <real value=\"3.4028234663852886e+38\"/>\n                                <real value=\"3.4028234663852886e+38\"/>\n                            </customSpacing>\n                        </stackView>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"G7B-Kp-Af8\" firstAttribute=\"width\" secondItem=\"Nqu-81-VCV\" secondAttribute=\"width\" id=\"3YS-ne-Cbu\"/>\n                <constraint firstItem=\"Nqu-81-VCV\" firstAttribute=\"leading\" secondItem=\"dtR-hL-16n\" secondAttribute=\"leading\" id=\"8c0-3m-e1w\"/>\n                <constraint firstItem=\"rIH-aw-8aF\" firstAttribute=\"centerX\" secondItem=\"Jdv-gk-kj9\" secondAttribute=\"centerX\" id=\"BcW-K6-tXB\"/>\n                <constraint firstItem=\"G7B-Kp-Af8\" firstAttribute=\"top\" secondItem=\"Nqu-81-VCV\" secondAttribute=\"top\" id=\"CK7-LK-opt\"/>\n                <constraint firstItem=\"Nqu-81-VCV\" firstAttribute=\"top\" secondItem=\"dtR-hL-16n\" secondAttribute=\"bottom\" constant=\"4\" id=\"Coj-aw-Scl\"/>\n                <constraint firstItem=\"G7B-Kp-Af8\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"dtR-hL-16n\" secondAttribute=\"trailing\" id=\"GGg-3Z-qdp\"/>\n                <constraint firstItem=\"G7B-Kp-Af8\" firstAttribute=\"leading\" secondItem=\"Nqu-81-VCV\" secondAttribute=\"trailing\" constant=\"-1\" id=\"Jdf-5c-8Rd\"/>\n                <constraint firstItem=\"KgU-fm-1CL\" firstAttribute=\"top\" secondItem=\"dIx-e4-L5V\" secondAttribute=\"bottom\" constant=\"4\" id=\"MGv-Qy-tXJ\"/>\n                <constraint firstItem=\"qcU-SW-8KI\" firstAttribute=\"leading\" secondItem=\"KgU-fm-1CL\" secondAttribute=\"trailing\" constant=\"1\" id=\"Pdl-Sr-kRD\"/>\n                <constraint firstItem=\"mdN-TE-pOJ\" firstAttribute=\"centerX\" secondItem=\"Jdv-gk-kj9\" secondAttribute=\"centerX\" id=\"Pw2-01-v6C\"/>\n                <constraint firstItem=\"qcU-SW-8KI\" firstAttribute=\"width\" secondItem=\"KgU-fm-1CL\" secondAttribute=\"width\" id=\"Q9u-XV-LEU\"/>\n                <constraint firstItem=\"G7B-Kp-Af8\" firstAttribute=\"height\" secondItem=\"Nqu-81-VCV\" secondAttribute=\"height\" id=\"Xkj-Lg-pGm\"/>\n                <constraint firstItem=\"KgU-fm-1CL\" firstAttribute=\"leading\" secondItem=\"dIx-e4-L5V\" secondAttribute=\"leading\" id=\"dMf-4V-7RN\"/>\n                <constraint firstItem=\"qcU-SW-8KI\" firstAttribute=\"height\" secondItem=\"KgU-fm-1CL\" secondAttribute=\"height\" id=\"ehN-hH-xIw\"/>\n                <constraint firstItem=\"faY-0p-PJo\" firstAttribute=\"leading\" secondItem=\"Jdv-gk-kj9\" secondAttribute=\"leading\" constant=\"40\" id=\"fQ8-CG-lYY\"/>\n                <constraint firstItem=\"qcU-SW-8KI\" firstAttribute=\"top\" secondItem=\"KgU-fm-1CL\" secondAttribute=\"top\" id=\"hPg-ez-Zum\"/>\n                <constraint firstItem=\"rIH-aw-8aF\" firstAttribute=\"top\" secondItem=\"faY-0p-PJo\" secondAttribute=\"bottom\" constant=\"18\" id=\"iW0-Fh-YHu\"/>\n                <constraint firstItem=\"faY-0p-PJo\" firstAttribute=\"top\" secondItem=\"mdN-TE-pOJ\" secondAttribute=\"bottom\" constant=\"18\" id=\"ipi-Yw-mWQ\"/>\n                <constraint firstItem=\"faY-0p-PJo\" firstAttribute=\"centerX\" secondItem=\"Jdv-gk-kj9\" secondAttribute=\"centerX\" id=\"n4o-Gl-rua\"/>\n                <constraint firstItem=\"mdN-TE-pOJ\" firstAttribute=\"top\" secondItem=\"Jdv-gk-kj9\" secondAttribute=\"top\" constant=\"30\" id=\"nNY-5Z-r2F\"/>\n                <constraint firstItem=\"qcU-SW-8KI\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"dIx-e4-L5V\" secondAttribute=\"trailing\" id=\"urJ-H9-A2I\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-7695.5\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"09H-hp-iIC\" userLabel=\"Alerts\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"287\"/>\n            <subviews>\n                <tabView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5iv-Ob-ruv\">\n                    <rect key=\"frame\" x=\"13\" y=\"10\" width=\"644\" height=\"267\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"630\" id=\"tSn-WH-gsC\"/>\n                    </constraints>\n                    <font key=\"font\" metaFont=\"system\"/>\n                    <tabViewItems>\n                        <tabViewItem label=\"Alerts\" identifier=\"1\" id=\"geW-mJ-8Ef\">\n                            <view key=\"view\" id=\"KFW-OS-9of\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"221\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Speech\" identifier=\"\" id=\"lAX-Jg-QPJ\">\n                            <view key=\"view\" id=\"E2I-6n-N4n\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"221\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ijs-9e-po6\">\n                                        <rect key=\"frame\" x=\"40\" y=\"174\" width=\"361\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Only speak Channel Messages for the selected channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"Wr9-i3-ItC\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"-2\" name=\"value\" keyPath=\"self.onlySpeakEventsForSelection\" id=\"8g4-NF-YJ2\"/>\n                                        </connections>\n                                    </button>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YQc-5a-Xjp\">\n                                        <rect key=\"frame\" x=\"40\" y=\"141\" width=\"268\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Include when speaking a Channel Message:\" id=\"va5-dc-OSt\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ktT-0t-F2C\">\n                                        <rect key=\"frame\" x=\"62\" y=\"92\" width=\"111\" height=\"40\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eJA-wf-fU4\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"23\" width=\"113\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Channel name\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"0Zc-1M-sD7\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"value\" keyPath=\"self.channelMessageSpeakChannelName\" id=\"dOK-qW-wcJ\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.OnlySpeakNotificationsForSelection\" id=\"vof-1F-5Zi\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"evp-5y-vS7\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"87\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Nickname\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"1Ug-zc-jEr\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"value\" keyPath=\"self.channelMessageSpeakNickname\" id=\"N9T-Aa-8hO\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"ijs-9e-po6\" firstAttribute=\"leading\" secondItem=\"E2I-6n-N4n\" secondAttribute=\"leading\" constant=\"42\" id=\"Gqf-Lw-KdH\"/>\n                                    <constraint firstItem=\"ktT-0t-F2C\" firstAttribute=\"leading\" secondItem=\"YQc-5a-Xjp\" secondAttribute=\"leading\" constant=\"20\" id=\"LKv-qY-cfb\"/>\n                                    <constraint firstItem=\"ktT-0t-F2C\" firstAttribute=\"top\" secondItem=\"YQc-5a-Xjp\" secondAttribute=\"bottom\" constant=\"9\" id=\"TcJ-YU-qWv\"/>\n                                    <constraint firstItem=\"ijs-9e-po6\" firstAttribute=\"top\" secondItem=\"E2I-6n-N4n\" secondAttribute=\"top\" constant=\"30\" id=\"WVG-SS-9Hk\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ijs-9e-po6\" secondAttribute=\"trailing\" constant=\"20\" id=\"YZp-pZ-XAW\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"YQc-5a-Xjp\" secondAttribute=\"trailing\" constant=\"20\" id=\"hAx-f4-FhM\"/>\n                                    <constraint firstItem=\"YQc-5a-Xjp\" firstAttribute=\"leading\" secondItem=\"E2I-6n-N4n\" secondAttribute=\"leading\" constant=\"42\" id=\"hfv-bJ-Jub\"/>\n                                    <constraint firstItem=\"YQc-5a-Xjp\" firstAttribute=\"top\" secondItem=\"ijs-9e-po6\" secondAttribute=\"bottom\" constant=\"18\" id=\"zNe-xb-Evf\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Advanced\" identifier=\"2\" id=\"Ivz-PB-a1d\">\n                            <view key=\"view\" id=\"k1L-3m-afM\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"221\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tno-Zq-S4W\">\n                                        <rect key=\"frame\" x=\"42\" y=\"145\" width=\"424\" height=\"46\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oe8-JD-drm\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"420\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show number of unread private messages on Textual's Dock icon\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"JLd-nU-beO\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayDockBadges\" id=\"64Q-Jk-rUE\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CzB-hl-Vy9\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"426\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show number of unread channel messages on Textual's Dock icon\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"8oW-yL-fGe\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayPublicMessageCountInDockBadge\" id=\"EAo-gX-afc\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5zM-ja-Fht\">\n                                        <rect key=\"frame\" x=\"40\" y=\"91\" width=\"286\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Show notifications when Textual is focused\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"gmn-OS-fhp\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.PostNotificationsWhileInFocus\" id=\"POH-Gc-56W\"/>\n                                        </connections>\n                                    </button>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AKo-pK-APa\">\n                                        <rect key=\"frame\" x=\"40\" y=\"124\" width=\"550\" height=\"5\"/>\n                                    </box>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"AKo-pK-APa\" firstAttribute=\"leading\" secondItem=\"k1L-3m-afM\" secondAttribute=\"leading\" constant=\"40\" id=\"AA8-zu-SVu\"/>\n                                    <constraint firstItem=\"AKo-pK-APa\" firstAttribute=\"top\" secondItem=\"tno-Zq-S4W\" secondAttribute=\"bottom\" constant=\"18\" id=\"T95-xt-E5B\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"5zM-ja-Fht\" secondAttribute=\"trailing\" id=\"YVj-Br-erv\"/>\n                                    <constraint firstItem=\"5zM-ja-Fht\" firstAttribute=\"top\" secondItem=\"AKo-pK-APa\" secondAttribute=\"bottom\" constant=\"18\" id=\"dC4-4U-qHl\"/>\n                                    <constraint firstItem=\"AKo-pK-APa\" firstAttribute=\"centerX\" secondItem=\"k1L-3m-afM\" secondAttribute=\"centerX\" constant=\"3\" id=\"dan-fM-VMm\"/>\n                                    <constraint firstItem=\"tno-Zq-S4W\" firstAttribute=\"top\" secondItem=\"k1L-3m-afM\" secondAttribute=\"top\" constant=\"30\" id=\"fj5-R6-w9G\"/>\n                                    <constraint firstItem=\"5zM-ja-Fht\" firstAttribute=\"leading\" secondItem=\"k1L-3m-afM\" secondAttribute=\"leading\" constant=\"42\" id=\"s0a-hp-YFg\"/>\n                                    <constraint firstItem=\"tno-Zq-S4W\" firstAttribute=\"leading\" secondItem=\"k1L-3m-afM\" secondAttribute=\"leading\" constant=\"42\" id=\"wmB-fD-RqF\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                    </tabViewItems>\n                </tabView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"5iv-Ob-ruv\" firstAttribute=\"leading\" secondItem=\"09H-hp-iIC\" secondAttribute=\"leading\" constant=\"20\" id=\"3cf-xK-pGT\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"5iv-Ob-ruv\" secondAttribute=\"bottom\" constant=\"20\" id=\"BMF-DV-25S\"/>\n                <constraint firstItem=\"5iv-Ob-ruv\" firstAttribute=\"top\" secondItem=\"09H-hp-iIC\" secondAttribute=\"top\" constant=\"16\" id=\"YCZ-yU-Ucn\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"5iv-Ob-ruv\" secondAttribute=\"trailing\" constant=\"20\" id=\"lzx-DY-1CH\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-7248\"/>\n        </customView>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yrc-pc-3Zr\" userLabel=\"Behavior\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"272\"/>\n            <subviews>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dcr-ig-DFq\">\n                    <rect key=\"frame\" x=\"40\" y=\"225\" width=\"255\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Open browser links in the background\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"78p-ZY-hL0\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.OpenClickedLinksInBackgroundBrowser\" id=\"0lJ-iu-aCv\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fmc-YR-xfp\">\n                    <rect key=\"frame\" x=\"40\" y=\"205\" width=\"590\" height=\"5\"/>\n                </box>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p8O-gX-t0n\">\n                    <rect key=\"frame\" x=\"40\" y=\"172\" width=\"286\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Automatically rejoin a channel when kicked\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"RRR-Ng-LIU\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.RejoinChannelOnLocalKick\" id=\"4g7-xO-cAm\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VYB-Yi-fp6\">\n                    <rect key=\"frame\" x=\"40\" y=\"142\" width=\"275\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Automatically join a channel when invited\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"Onr-Yr-Ms6\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutojoinChannelOnInvite\" id=\"nOM-Na-bNT\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xKd-AN-3BU\">\n                    <rect key=\"frame\" x=\"40\" y=\"112\" width=\"340\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Toggle away status when your display goes to sleep\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"oRS-41-peI\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.SetAwayOnScreenSleep\" id=\"9hY-eU-AQr\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sEi-KB-hee\">\n                    <rect key=\"frame\" x=\"40\" y=\"92\" width=\"590\" height=\"5\"/>\n                </box>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OwD-V4-eKh\">\n                    <rect key=\"frame\" x=\"40\" y=\"59\" width=\"275\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Restore scrollback from previous session\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"rdw-r8-Wgf\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ReloadScrollbackOnLaunch\" id=\"EXo-2P-e31\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2fI-fE-Q2a\">\n                    <rect key=\"frame\" x=\"40\" y=\"29\" width=\"330\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Restore the state of queries from previous session\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"kq6-SH-wmj\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ServerListRetainsQueriesBetweenRestarts\" id=\"kpU-pS-LO5\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"xKd-AN-3BU\" secondAttribute=\"trailing\" constant=\"20\" id=\"0fF-fv-xsc\"/>\n                <constraint firstItem=\"2fI-fE-Q2a\" firstAttribute=\"leading\" secondItem=\"OwD-V4-eKh\" secondAttribute=\"leading\" id=\"1D5-i0-ou3\"/>\n                <constraint firstItem=\"Fmc-YR-xfp\" firstAttribute=\"leading\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"leading\" constant=\"40\" id=\"3IW-UR-ErE\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"2fI-fE-Q2a\" secondAttribute=\"bottom\" constant=\"30\" id=\"5OK-SG-6Vw\"/>\n                <constraint firstItem=\"p8O-gX-t0n\" firstAttribute=\"leading\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"leading\" constant=\"42\" id=\"6fB-zi-Wbh\"/>\n                <constraint firstItem=\"Fmc-YR-xfp\" firstAttribute=\"top\" secondItem=\"dcr-ig-DFq\" secondAttribute=\"bottom\" constant=\"18\" id=\"91D-nO-ZaO\"/>\n                <constraint firstItem=\"xKd-AN-3BU\" firstAttribute=\"top\" secondItem=\"VYB-Yi-fp6\" secondAttribute=\"bottom\" constant=\"14\" id=\"AQv-0d-a36\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"VYB-Yi-fp6\" secondAttribute=\"trailing\" constant=\"20\" id=\"Cf4-5J-lO7\"/>\n                <constraint firstItem=\"sEi-KB-hee\" firstAttribute=\"leading\" secondItem=\"Fmc-YR-xfp\" secondAttribute=\"leading\" id=\"FfB-ff-ZiE\"/>\n                <constraint firstItem=\"p8O-gX-t0n\" firstAttribute=\"top\" secondItem=\"Fmc-YR-xfp\" secondAttribute=\"bottom\" constant=\"18\" id=\"Gkj-5o-yAv\"/>\n                <constraint firstItem=\"OwD-V4-eKh\" firstAttribute=\"top\" secondItem=\"sEi-KB-hee\" secondAttribute=\"bottom\" constant=\"18\" id=\"HdJ-qi-BEz\"/>\n                <constraint firstItem=\"OwD-V4-eKh\" firstAttribute=\"leading\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"leading\" constant=\"42\" id=\"K05-fJ-sdg\"/>\n                <constraint firstItem=\"Fmc-YR-xfp\" firstAttribute=\"centerX\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"centerX\" id=\"U7v-yX-Yhb\"/>\n                <constraint firstItem=\"sEi-KB-hee\" firstAttribute=\"trailing\" secondItem=\"Fmc-YR-xfp\" secondAttribute=\"trailing\" id=\"Wi0-2j-m0a\"/>\n                <constraint firstItem=\"dcr-ig-DFq\" firstAttribute=\"top\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"top\" constant=\"30\" id=\"XV2-ff-i46\"/>\n                <constraint firstItem=\"dcr-ig-DFq\" firstAttribute=\"leading\" secondItem=\"Yrc-pc-3Zr\" secondAttribute=\"leading\" constant=\"42\" id=\"Xlp-sE-GmQ\"/>\n                <constraint firstItem=\"sEi-KB-hee\" firstAttribute=\"top\" secondItem=\"xKd-AN-3BU\" secondAttribute=\"bottom\" constant=\"18\" id=\"Yde-nj-z0M\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"2fI-fE-Q2a\" secondAttribute=\"trailing\" constant=\"20\" id=\"goS-dF-HI1\"/>\n                <constraint firstItem=\"VYB-Yi-fp6\" firstAttribute=\"top\" secondItem=\"p8O-gX-t0n\" secondAttribute=\"bottom\" constant=\"14\" id=\"ngU-q7-jKV\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"p8O-gX-t0n\" secondAttribute=\"trailing\" constant=\"20\" id=\"o5j-UO-RTO\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"OwD-V4-eKh\" secondAttribute=\"trailing\" constant=\"20\" id=\"pja-2Z-LuY\"/>\n                <constraint firstItem=\"xKd-AN-3BU\" firstAttribute=\"leading\" secondItem=\"VYB-Yi-fp6\" secondAttribute=\"leading\" id=\"qDW-Kc-cZq\"/>\n                <constraint firstItem=\"VYB-Yi-fp6\" firstAttribute=\"leading\" secondItem=\"p8O-gX-t0n\" secondAttribute=\"leading\" id=\"sS5-Ry-hhS\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"dcr-ig-DFq\" secondAttribute=\"trailing\" constant=\"20\" id=\"yM2-MK-thd\"/>\n                <constraint firstItem=\"2fI-fE-Q2a\" firstAttribute=\"top\" secondItem=\"OwD-V4-eKh\" secondAttribute=\"bottom\" constant=\"14\" id=\"zK3-2W-liT\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"318\" y=\"-6756\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fnm-DD-Hbc\" userLabel=\"Controls\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"536\"/>\n            <subviews>\n                <tabView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iOA-1f-6sc\">\n                    <rect key=\"frame\" x=\"13\" y=\"10\" width=\"644\" height=\"516\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"500\" id=\"Zr4-WE-Fqe\"/>\n                        <constraint firstAttribute=\"width\" constant=\"630\" id=\"rEQ-8v-kZP\"/>\n                    </constraints>\n                    <font key=\"font\" metaFont=\"system\"/>\n                    <tabViewItems>\n                        <tabViewItem label=\"Keyboard &amp; Mouse\" identifier=\"1\" id=\"SL3-8G-t51\">\n                            <view key=\"view\" id=\"4ZT-mV-qxZ\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"470\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YgC-u1-eRM\">\n                                        <rect key=\"frame\" x=\"42\" y=\"181\" width=\"261\" height=\"106\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nsU-oF-11h\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"89\" width=\"230\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Connect to server on double click\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"HyM-B2-IjQ\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ServerListDoubleClickConnectServer\" id=\"SU3-zR-t9N\">\n                                                        <dictionary key=\"options\">\n                                                            <bool key=\"NSAllowsEditingMultipleValuesSelection\" value=\"NO\"/>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Qqp-Rw-jY7\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"263\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Disconnect from server on double click\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"Lsg-37-h0b\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ServerListDoubleClickDisconnectServer\" id=\"Z6K-zk-kVU\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sGF-Q4-JiC\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"198\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Join channel on double click\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"0Jk-qA-tn1\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ServerListDoubleClickJoinChannel\" id=\"jry-km-hpE\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tem-fj-U6Q\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"208\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Leave channel on double click\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"qbS-rY-mJ8\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ServerListDoubleClickLeaveChannel\" id=\"Fhp-dP-C84\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRR-9J-n7G\">\n                                        <rect key=\"frame\" x=\"40\" y=\"127\" width=\"223\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Automatically copy selected text\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"uSz-ME-EyF\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.CopyTextSelectionOnMouseUp\" id=\"IIP-gf-lvG\"/>\n                                        </connections>\n                                    </button>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TIz-dH-HBF\">\n                                        <rect key=\"frame\" x=\"40\" y=\"413\" width=\"335\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Channel navigation is limited to the selected server\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"beH-aC-ScW\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ChannelNavigationIsServerSpecific\" id=\"9Da-Wn-wMb\"/>\n                                        </connections>\n                                    </button>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JFd-1Y-9jH\">\n                                        <rect key=\"frame\" x=\"40\" y=\"160\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZHD-P3-6vN\">\n                                        <rect key=\"frame\" x=\"40\" y=\"393\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"INb-El-pAB\">\n                                        <rect key=\"frame\" x=\"58\" y=\"105\" width=\"451\" height=\"15\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Hold the Option key (⌥) while selecting text to temporarily disable this feature.\" id=\"8Nk-L2-mjZ\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"link\" destination=\"YRR-9J-n7G\" id=\"9Jx-rB-82K\"/>\n                                        </connections>\n                                    </textField>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dJl-5C-foA\">\n                                        <rect key=\"frame\" x=\"40\" y=\"303\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"13\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oXg-Hs-Qvc\">\n                                        <rect key=\"frame\" x=\"70\" y=\"324\" width=\"484\" height=\"53\"/>\n                                        <rows>\n                                            <gridRow id=\"lMI-Cd-nai\"/>\n                                            <gridRow id=\"Fuu-gA-vhp\"/>\n                                        </rows>\n                                        <columns>\n                                            <gridColumn id=\"pXN-tW-hCd\"/>\n                                            <gridColumn xPlacement=\"fill\" id=\"GTP-aT-ARZ\"/>\n                                        </columns>\n                                        <gridCells>\n                                            <gridCell row=\"lMI-Cd-nai\" column=\"pXN-tW-hCd\" id=\"pbb-5x-qmc\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rd9-Tz-a8b\">\n                                                    <rect key=\"frame\" x=\"19\" y=\"36\" width=\"142\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Double clicking a user:\" id=\"NhJ-3F-Unb\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"lMI-Cd-nai\" column=\"GTP-aT-ARZ\" id=\"1X6-5d-LSp\">\n                                                <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tfq-lx-1BD\">\n                                                    <rect key=\"frame\" x=\"164\" y=\"29\" width=\"324\" height=\"25\"/>\n                                                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Open Query\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"200\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"Lfz-k6-aUF\" id=\"FX8-ei-qeg\">\n                                                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                        <menu key=\"menu\" title=\"OtherViews\" id=\"oka-gF-dyN\">\n                                                            <items>\n                                                                <menuItem title=\"Open Query\" state=\"on\" tag=\"200\" id=\"Lfz-k6-aUF\"/>\n                                                                <menuItem title=\"Whois User\" tag=\"100\" id=\"FMM-aC-dKv\"/>\n                                                                <menuItem title=\"Insert Name Into Text Field\" tag=\"300\" id=\"qM6-KO-sYq\"/>\n                                                            </items>\n                                                        </menu>\n                                                    </popUpButtonCell>\n                                                    <accessibility description=\"Double Clicking on a User Action\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"Rd9-Tz-a8b\" id=\"dYG-vi-Rv0\"/>\n                                                        <accessibilityConnection property=\"title\" destination=\"Rd9-Tz-a8b\" id=\"kHb-PD-iAe\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.UserListDoubleClickAction\" id=\"IgS-x5-Dmk\"/>\n                                                    </connections>\n                                                </popUpButton>\n                                            </gridCell>\n                                            <gridCell row=\"Fuu-gA-vhp\" column=\"pXN-tW-hCd\" id=\"vvl-3u-iq0\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ykv-44-sRE\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"163\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Command + W key action:\" id=\"4oC-Tr-qfm\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"Fuu-gA-vhp\" column=\"GTP-aT-ARZ\" id=\"dUs-aL-7qx\">\n                                                <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zfk-65-afW\">\n                                                    <rect key=\"frame\" x=\"164\" y=\"-4\" width=\"324\" height=\"25\"/>\n                                                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Close Main Window\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"WSZ-ji-Ch7\" id=\"qna-h9-Sw2\">\n                                                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                        <menu key=\"menu\" title=\"OtherViews\" id=\"ntn-0O-xE7\">\n                                                            <items>\n                                                                <menuItem title=\"Close Main Window\" state=\"on\" id=\"WSZ-ji-Ch7\"/>\n                                                                <menuItem title=\"Close Selected Query or Part Selected Channel\" id=\"e7p-VL-p6K\"/>\n                                                                <menuItem title=\"Disconnect from Selected Server\" id=\"AGV-XB-vKT\"/>\n                                                                <menuItem title=\"Disconnect and Quit Application\" id=\"kBD-9T-FwG\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </popUpButtonCell>\n                                                    <accessibility description=\"Command W Keyboard Action\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"ykv-44-sRE\" id=\"3a8-Ce-LYA\"/>\n                                                        <accessibilityConnection property=\"title\" destination=\"ykv-44-sRE\" id=\"HUb-6q-lnK\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedIndex\" keyPath=\"values.Keyboard -&gt; Command+W Key Action\" id=\"DBX-FS-Vcg\"/>\n                                                    </connections>\n                                                </popUpButton>\n                                            </gridCell>\n                                        </gridCells>\n                                    </gridView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"INb-El-pAB\" secondAttribute=\"trailing\" constant=\"20\" id=\"3eA-kc-wS3\"/>\n                                    <constraint firstItem=\"YRR-9J-n7G\" firstAttribute=\"top\" secondItem=\"JFd-1Y-9jH\" secondAttribute=\"bottom\" constant=\"18\" id=\"8yW-k3-fZw\"/>\n                                    <constraint firstItem=\"oXg-Hs-Qvc\" firstAttribute=\"leading\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"leading\" constant=\"70\" id=\"9Ul-AK-UFx\"/>\n                                    <constraint firstItem=\"ZHD-P3-6vN\" firstAttribute=\"top\" secondItem=\"TIz-dH-HBF\" secondAttribute=\"bottom\" constant=\"18\" id=\"CKt-F5-S9b\"/>\n                                    <constraint firstItem=\"ZHD-P3-6vN\" firstAttribute=\"leading\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"leading\" constant=\"40\" id=\"D5V-h5-OrA\"/>\n                                    <constraint firstItem=\"JFd-1Y-9jH\" firstAttribute=\"leading\" secondItem=\"ZHD-P3-6vN\" secondAttribute=\"leading\" id=\"KX6-bq-wd3\"/>\n                                    <constraint firstItem=\"dJl-5C-foA\" firstAttribute=\"trailing\" secondItem=\"ZHD-P3-6vN\" secondAttribute=\"trailing\" id=\"Y87-5k-IEW\"/>\n                                    <constraint firstItem=\"TIz-dH-HBF\" firstAttribute=\"leading\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"leading\" constant=\"42\" id=\"Zw2-cE-bAA\"/>\n                                    <constraint firstItem=\"YgC-u1-eRM\" firstAttribute=\"top\" secondItem=\"dJl-5C-foA\" secondAttribute=\"bottom\" constant=\"18\" id=\"cxu-yh-S6e\"/>\n                                    <constraint firstItem=\"oXg-Hs-Qvc\" firstAttribute=\"centerX\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"centerX\" id=\"fMT-Ug-n7Z\"/>\n                                    <constraint firstItem=\"INb-El-pAB\" firstAttribute=\"leading\" secondItem=\"YRR-9J-n7G\" secondAttribute=\"leading\" constant=\"18\" id=\"hUL-NI-Gdl\"/>\n                                    <constraint firstItem=\"JFd-1Y-9jH\" firstAttribute=\"trailing\" secondItem=\"ZHD-P3-6vN\" secondAttribute=\"trailing\" id=\"hu3-K8-yCA\"/>\n                                    <constraint firstItem=\"oXg-Hs-Qvc\" firstAttribute=\"top\" secondItem=\"ZHD-P3-6vN\" secondAttribute=\"bottom\" constant=\"18\" id=\"jTq-GD-Rff\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"YRR-9J-n7G\" secondAttribute=\"trailing\" constant=\"20\" id=\"jW4-vE-UPv\"/>\n                                    <constraint firstItem=\"dJl-5C-foA\" firstAttribute=\"top\" secondItem=\"oXg-Hs-Qvc\" secondAttribute=\"bottom\" constant=\"18\" id=\"jno-nA-0IL\"/>\n                                    <constraint firstItem=\"TIz-dH-HBF\" firstAttribute=\"top\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"top\" constant=\"40\" id=\"n7u-qR-bGS\"/>\n                                    <constraint firstItem=\"ZHD-P3-6vN\" firstAttribute=\"centerX\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"centerX\" id=\"nlk-sS-JCg\"/>\n                                    <constraint firstItem=\"YRR-9J-n7G\" firstAttribute=\"leading\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"leading\" constant=\"42\" id=\"ojV-Pm-HSN\"/>\n                                    <constraint firstItem=\"dJl-5C-foA\" firstAttribute=\"leading\" secondItem=\"ZHD-P3-6vN\" secondAttribute=\"leading\" id=\"owe-3P-Kd7\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"TIz-dH-HBF\" secondAttribute=\"trailing\" constant=\"20\" id=\"riN-jp-KWa\"/>\n                                    <constraint firstItem=\"JFd-1Y-9jH\" firstAttribute=\"top\" secondItem=\"YgC-u1-eRM\" secondAttribute=\"bottom\" constant=\"18\" id=\"tDQ-Rk-cid\"/>\n                                    <constraint firstItem=\"YgC-u1-eRM\" firstAttribute=\"leading\" secondItem=\"4ZT-mV-qxZ\" secondAttribute=\"leading\" constant=\"42\" id=\"tJc-xS-deD\"/>\n                                    <constraint firstItem=\"INb-El-pAB\" firstAttribute=\"top\" secondItem=\"YRR-9J-n7G\" secondAttribute=\"bottom\" constant=\"8\" id=\"u4p-pn-vwP\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Main Text Field\" identifier=\"2\" id=\"lJH-z2-zrz\">\n                            <view key=\"view\" id=\"Jbg-Wd-zzj\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"470\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7dN-Dw-p6U\">\n                                        <rect key=\"frame\" x=\"40\" y=\"290\" width=\"534\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tcb-mG-sBA\">\n                                        <rect key=\"frame\" x=\"40\" y=\"177\" width=\"534\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pwx-16-f5L\">\n                                        <rect key=\"frame\" x=\"40\" y=\"403\" width=\"534\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"z2E-fq-Jyq\">\n                                        <rect key=\"frame\" x=\"40\" y=\"120\" width=\"534\" height=\"5\"/>\n                                    </box>\n                                    <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"one-ni-Mfg\">\n                                        <rect key=\"frame\" x=\"84\" y=\"50\" width=\"456\" height=\"54\"/>\n                                        <rows>\n                                            <gridRow id=\"W7w-za-NLm\"/>\n                                            <gridRow id=\"3as-Bs-tz6\"/>\n                                        </rows>\n                                        <columns>\n                                            <gridColumn xPlacement=\"trailing\" id=\"ouX-sf-fmu\"/>\n                                            <gridColumn xPlacement=\"fill\" id=\"xIx-H8-hL3\"/>\n                                        </columns>\n                                        <gridCells>\n                                            <gridCell row=\"W7w-za-NLm\" column=\"ouX-sf-fmu\" id=\"ao7-JM-F7t\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"G5s-ZV-vl4\">\n                                                    <rect key=\"frame\" x=\"32\" y=\"37\" width=\"97\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Tab key Action:\" id=\"KMv-Al-scp\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"W7w-za-NLm\" column=\"xIx-H8-hL3\" id=\"dq7-1Z-Oj4\">\n                                                <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FCb-0i-eUL\">\n                                                    <rect key=\"frame\" x=\"132\" y=\"30\" width=\"328\" height=\"25\"/>\n                                                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Complete nicknames, channels, and commands\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" inset=\"2\" arrowPosition=\"arrowAtCenter\" preferredEdge=\"maxY\" selectedItem=\"BB3-hI-0sU\" id=\"qkg-MZ-4sK\">\n                                                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                        <menu key=\"menu\" title=\"OtherViews\" id=\"uQz-ra-1Dt\">\n                                                            <items>\n                                                                <menuItem title=\"Perform no action\" tag=\"100\" id=\"JeZ-iW-YnD\"/>\n                                                                <menuItem title=\"Move to next unread channel\" tag=\"1\" id=\"WMd-6W-689\"/>\n                                                                <menuItem title=\"Complete nicknames, channels, and commands\" state=\"on\" id=\"BB3-hI-0sU\"/>\n                                                            </items>\n                                                        </menu>\n                                                        <connections>\n                                                            <accessibilityConnection property=\"title\" destination=\"G5s-ZV-vl4\" id=\"Ayt-NL-FFi\"/>\n                                                        </connections>\n                                                    </popUpButtonCell>\n                                                    <accessibility description=\"Tab Key Action\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"G5s-ZV-vl4\" id=\"Q2N-xl-bDn\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.Keyboard -&gt; Tab Key Action\" id=\"J4g-ex-7PH\"/>\n                                                    </connections>\n                                                </popUpButton>\n                                            </gridCell>\n                                            <gridCell row=\"3as-Bs-tz6\" column=\"ouX-sf-fmu\" id=\"qgf-ko-6EF\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gEg-D9-LJK\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"131\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Autocomplete Suffix:\" id=\"Mgd-OI-qia\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"3as-Bs-tz6\" column=\"xIx-H8-hL3\" id=\"KuV-oB-Kcf\">\n                                                <stackView key=\"contentView\" distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zKJ-Y0-6fq\">\n                                                    <rect key=\"frame\" x=\"135\" y=\"0.0\" width=\"321\" height=\"22\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IYV-h0-Zl5\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"62\" height=\"22\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"6cE-3P-K5T\"/>\n                                                                <constraint firstAttribute=\"width\" constant=\"62\" id=\"mmh-hK-CIT\"/>\n                                                            </constraints>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"ydh-1p-3xf\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Tab Key Autocompletion Suffix\" help=\"Suffix to place after result when using the tab key to autocomplete a value.\"/>\n                                                            <connections>\n                                                                <accessibilityConnection property=\"title\" destination=\"gEg-D9-LJK\" id=\"bYn-Eb-G1a\"/>\n                                                                <accessibilityConnection property=\"title\" destination=\"gEg-D9-LJK\" id=\"oZ8-I3-VTZ\"/>\n                                                                <accessibilityConnection property=\"title\" destination=\"gEg-D9-LJK\" id=\"wsh-Cx-kqF\"/>\n                                                                <accessibilityConnection property=\"title\" destination=\"gEg-D9-LJK\" id=\"zA3-hC-oN8\"/>\n                                                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.Keyboard -&gt; Tab Key Completion Suffix\" id=\"3nC-GZ-boD\">\n                                                                    <dictionary key=\"options\">\n                                                                        <bool key=\"NSContinuouslyUpdatesValue\" value=\"YES\"/>\n                                                                    </dictionary>\n                                                                </binding>\n                                                            </connections>\n                                                        </textField>\n                                                        <box horizontalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AAZ-jr-pf8\">\n                                                            <rect key=\"frame\" x=\"68\" y=\"0.0\" width=\"5\" height=\"22\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"PyT-1w-baG\"/>\n                                                            </constraints>\n                                                        </box>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ggk-WY-GPx\">\n                                                            <rect key=\"frame\" x=\"77\" y=\"4\" width=\"57\" height=\"15\"/>\n                                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Preview:\" id=\"Mfg-SH-a2v\">\n                                                                <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <textField focusRingType=\"none\" horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QFY-JA-Thc\">\n                                                            <rect key=\"frame\" x=\"138\" y=\"4\" width=\"185\" height=\"15\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Label\" id=\"Q2m-Lf-iMp\">\n                                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"G2Q-fc-ddg\" name=\"displayPatternValue1\" keyPath=\"values.Keyboard -&gt; Tab Key Completion Suffix\" id=\"KQn-yW-WJK\">\n                                                                    <dictionary key=\"options\">\n                                                                        <string key=\"NSDisplayPattern\">JohnDoe%{value1}@…</string>\n                                                                    </dictionary>\n                                                                </binding>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <visibilityPriorities>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                    </visibilityPriorities>\n                                                    <customSpacing>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                    </customSpacing>\n                                                </stackView>\n                                            </gridCell>\n                                        </gridCells>\n                                    </gridView>\n                                    <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gGb-wc-eZP\">\n                                        <rect key=\"frame\" x=\"162\" y=\"141\" width=\"301\" height=\"20\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PP9-CX-ahk\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"191\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Text size of the input text field:\" id=\"R1K-MQ-Z0M\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hw5-Ii-JYo\">\n                                                <rect key=\"frame\" x=\"192\" y=\"-4\" width=\"113\" height=\"25\"/>\n                                                <popUpButtonCell key=\"cell\" type=\"push\" title=\"Normal\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"1\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"1rW-DR-UZS\" id=\"CyX-fz-iYF\">\n                                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                    <menu key=\"menu\" title=\"OtherViews\" id=\"frO-sN-3ps\">\n                                                        <items>\n                                                            <menuItem title=\"Normal\" state=\"on\" tag=\"1\" id=\"1rW-DR-UZS\">\n                                                                <attributedString key=\"attributedTitle\"/>\n                                                            </menuItem>\n                                                            <menuItem title=\"Large\" tag=\"2\" id=\"elC-wm-fSP\">\n                                                                <attributedString key=\"attributedTitle\"/>\n                                                            </menuItem>\n                                                            <menuItem title=\"Extra Large\" tag=\"3\" id=\"bcG-qK-Dpa\">\n                                                                <attributedString key=\"attributedTitle\"/>\n                                                            </menuItem>\n                                                            <menuItem title=\"Humongous\" tag=\"4\" id=\"IVc-2c-qAv\">\n                                                                <attributedString key=\"attributedTitle\"/>\n                                                            </menuItem>\n                                                        </items>\n                                                    </menu>\n                                                </popUpButtonCell>\n                                                <accessibility description=\"Main Text Field Text Size\"/>\n                                                <connections>\n                                                    <action selector=\"onChangedMainInputTextViewFontSize:\" target=\"-2\" id=\"NHv-SK-fmf\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.Main Input Text Field -&gt; Font Size\" id=\"BAj-Y5-IIX\"/>\n                                                </connections>\n                                            </popUpButton>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QB5-Xf-FbA\">\n                                        <rect key=\"frame\" x=\"42\" y=\"311\" width=\"205\" height=\"76\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"10g-d7-Fnj\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"192\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Check spelling while typing\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"YIe-6t-oYS\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.TextFieldAutomaticSpellCheck\" id=\"JLd-GV-Eh9\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Afa-eJ-6xg\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"199\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Check grammar while typing\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"FSB-Bk-bvA\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.TextFieldAutomaticGrammarCheck\" id=\"yf3-mI-4Jo\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"a8L-AB-ahR\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"207\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Correct spelling automatically\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"a9u-Lw-W1l\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.TextFieldAutomaticSpellCorrection\" id=\"9eT-2Q-xgl\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qdK-c5-LSO\">\n                                        <rect key=\"frame\" x=\"43\" y=\"198\" width=\"412\" height=\"76\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5bf-6w-qFe\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"360\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Save input history for each channel rather than globally\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"vj4-ZX-CtP\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedInputHistoryScheme:\" target=\"-2\" id=\"oq6-SV-DnI\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.SaveInputHistoryPerSelection\" id=\"z6n-74-mzf\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HX9-Ua-Lzw\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"345\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Command Return (⌘⏎) sends message as an action\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"YqM-cS-deW\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedInputHistoryScheme:\" target=\"-2\" id=\"xWQ-9u-r1u\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.CommandReturnSendsMessageAsAction\" id=\"crq-75-D2J\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M32-by-Z8q\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"414\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Control Enter (⌃⎆) sends message instead of inserting new line\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"qN2-RC-TZe\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedInputHistoryScheme:\" target=\"-2\" id=\"OzB-Lz-cNG\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ControlEnterSendsMessage\" id=\"VjY-0Q-agU\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KBt-zr-O6u\">\n                                        <rect key=\"frame\" x=\"40\" y=\"423\" width=\"281\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Hide the buttons left of the input text field\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"45X-la-mo0\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"onChangedMainWindowSegmentedController:\" target=\"-2\" id=\"bVN-xI-Sod\"/>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisableMainWindowSegmentedController\" id=\"icZ-6P-wKs\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"7dN-Dw-p6U\" firstAttribute=\"leading\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"leading\" id=\"0QG-k4-6fW\"/>\n                                    <constraint firstItem=\"one-ni-Mfg\" firstAttribute=\"top\" secondItem=\"z2E-fq-Jyq\" secondAttribute=\"bottom\" constant=\"18\" id=\"1DM-MM-fC3\"/>\n                                    <constraint firstItem=\"one-ni-Mfg\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"leading\" constant=\"80\" id=\"59r-Jz-Rn5\"/>\n                                    <constraint firstItem=\"QB5-Xf-FbA\" firstAttribute=\"leading\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"leading\" constant=\"42\" id=\"8Jr-Et-FbC\"/>\n                                    <constraint firstItem=\"QB5-Xf-FbA\" firstAttribute=\"top\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"bottom\" constant=\"18\" id=\"9nl-Tp-VuW\"/>\n                                    <constraint firstItem=\"tcb-mG-sBA\" firstAttribute=\"leading\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"leading\" id=\"BF6-rn-zTW\"/>\n                                    <constraint firstItem=\"Pwx-16-f5L\" firstAttribute=\"leading\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"leading\" constant=\"40\" id=\"FKI-0U-gko\"/>\n                                    <constraint firstItem=\"7dN-Dw-p6U\" firstAttribute=\"trailing\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"trailing\" id=\"HBg-Dx-JiY\"/>\n                                    <constraint firstItem=\"z2E-fq-Jyq\" firstAttribute=\"trailing\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"trailing\" id=\"IAl-Gc-QdL\"/>\n                                    <constraint firstItem=\"gGb-wc-eZP\" firstAttribute=\"centerX\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"centerX\" id=\"Tbo-AT-PlI\"/>\n                                    <constraint firstItem=\"KBt-zr-O6u\" firstAttribute=\"leading\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"leading\" constant=\"42\" id=\"Tvt-TR-jZa\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"KBt-zr-O6u\" secondAttribute=\"trailing\" constant=\"20\" id=\"UhQ-sy-bzt\"/>\n                                    <constraint firstItem=\"tcb-mG-sBA\" firstAttribute=\"trailing\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"trailing\" id=\"Uqd-TB-MY4\"/>\n                                    <constraint firstItem=\"qdK-c5-LSO\" firstAttribute=\"top\" secondItem=\"7dN-Dw-p6U\" secondAttribute=\"bottom\" constant=\"18\" id=\"Wl8-3o-kbO\"/>\n                                    <constraint firstItem=\"z2E-fq-Jyq\" firstAttribute=\"top\" secondItem=\"gGb-wc-eZP\" secondAttribute=\"bottom\" constant=\"18\" id=\"YCw-Wp-Fv5\"/>\n                                    <constraint firstItem=\"z2E-fq-Jyq\" firstAttribute=\"leading\" secondItem=\"Pwx-16-f5L\" secondAttribute=\"leading\" id=\"aER-aY-Yum\"/>\n                                    <constraint firstItem=\"KBt-zr-O6u\" firstAttribute=\"top\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"top\" constant=\"30\" id=\"bH8-sa-dqc\"/>\n                                    <constraint firstItem=\"Pwx-16-f5L\" firstAttribute=\"top\" secondItem=\"KBt-zr-O6u\" secondAttribute=\"bottom\" constant=\"18\" id=\"bdA-m7-Lp6\"/>\n                                    <constraint firstItem=\"gGb-wc-eZP\" firstAttribute=\"top\" secondItem=\"tcb-mG-sBA\" secondAttribute=\"bottom\" constant=\"18\" id=\"cbz-4l-vZh\"/>\n                                    <constraint firstItem=\"qdK-c5-LSO\" firstAttribute=\"leading\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"leading\" constant=\"43\" id=\"dnA-d9-1ED\"/>\n                                    <constraint firstItem=\"tcb-mG-sBA\" firstAttribute=\"top\" secondItem=\"qdK-c5-LSO\" secondAttribute=\"bottom\" constant=\"18\" id=\"sJI-8K-QmO\"/>\n                                    <constraint firstItem=\"7dN-Dw-p6U\" firstAttribute=\"top\" secondItem=\"QB5-Xf-FbA\" secondAttribute=\"bottom\" constant=\"18\" id=\"tqF-Ta-6EG\"/>\n                                    <constraint firstItem=\"Pwx-16-f5L\" firstAttribute=\"centerX\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"centerX\" constant=\"-5\" id=\"xp9-HT-fY4\"/>\n                                    <constraint firstItem=\"one-ni-Mfg\" firstAttribute=\"centerX\" secondItem=\"Jbg-Wd-zzj\" secondAttribute=\"centerX\" id=\"yR0-ZE-xyk\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                    </tabViewItems>\n                </tabView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"iOA-1f-6sc\" secondAttribute=\"trailing\" constant=\"20\" id=\"1oE-8v-pGt\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"iOA-1f-6sc\" secondAttribute=\"bottom\" constant=\"20\" id=\"6cm-bO-55E\"/>\n                <constraint firstItem=\"iOA-1f-6sc\" firstAttribute=\"leading\" secondItem=\"Fnm-DD-Hbc\" secondAttribute=\"leading\" constant=\"20\" id=\"bea-tI-6Go\"/>\n                <constraint firstItem=\"iOA-1f-6sc\" firstAttribute=\"top\" secondItem=\"Fnm-DD-Hbc\" secondAttribute=\"top\" constant=\"16\" id=\"c8M-KK-Fu0\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-6165\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Th-u8-aIC\" userLabel=\"Interface\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"436\"/>\n            <userGuides>\n                <userLayoutGuide location=\"445\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <tabView initialItem=\"cUA-Ui-lzO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"emo-oX-cWx\">\n                    <rect key=\"frame\" x=\"13\" y=\"10\" width=\"644\" height=\"416\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"630\" id=\"PX9-cE-RFw\"/>\n                        <constraint firstAttribute=\"height\" constant=\"400\" id=\"baE-9c-bPU\"/>\n                    </constraints>\n                    <font key=\"font\" metaFont=\"system\"/>\n                    <tabViewItems>\n                        <tabViewItem label=\"General\" identifier=\"1\" id=\"cUA-Ui-lzO\">\n                            <view key=\"view\" id=\"Ht3-ub-Duo\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"370\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5Ks-KS-pKv\">\n                                        <rect key=\"frame\" x=\"42\" y=\"58\" width=\"341\" height=\"76\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gmu-Oh-Krb\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"343\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Use “x” to indicate user with no mode set in user list\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"8DQ-Jg-CgL\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"8dT-fz-izq\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayUserListNoModeSymbol\" id=\"Tvx-vv-1Xj\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fdc-sn-QgS\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"341\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Place known server staff members at top of user list\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"egC-El-gcj\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedUserListModeSortOrder:\" target=\"-2\" id=\"oYh-wc-tHB\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.MemberListSortFavorsServerStaff\" id=\"lRa-9p-0ml\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tNs-id-cdg\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"298\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"User list info popover updates while scrolling\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"0ZL-Zz-8el\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.MemberListUpdatesUserInfoPopoverOnScroll\" id=\"d0I-sB-16Z\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pbE-2M-fRW\">\n                                        <rect key=\"frame\" x=\"40\" y=\"293\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kad-3P-XnO\">\n                                        <rect key=\"frame\" x=\"40\" y=\"313\" width=\"124\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Right to left text\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"4PT-nq-SYL\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"onChangedTheme:\" target=\"-2\" id=\"j4B-lg-2d0\"/>\n                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"E6q-7p-2bw\">\n                                                <dictionary key=\"options\">\n                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                </dictionary>\n                                            </binding>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.RightToLeftTextFormatting\" id=\"HNm-WZ-6Dm\"/>\n                                        </connections>\n                                    </button>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"v8u-aO-cik\">\n                                        <rect key=\"frame\" x=\"40\" y=\"150\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RZ1-8W-O04\">\n                                        <rect key=\"frame\" x=\"40\" y=\"207\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dwh-L6-1bu\">\n                                        <rect key=\"frame\" x=\"100\" y=\"228\" width=\"425\" height=\"49\"/>\n                                        <rows>\n                                            <gridRow id=\"mZ9-hx-ewv\"/>\n                                            <gridRow id=\"XiR-N0-kUX\"/>\n                                        </rows>\n                                        <columns>\n                                            <gridColumn id=\"fVa-ZO-Yb4\"/>\n                                            <gridColumn xPlacement=\"leading\" id=\"Lzf-OU-P1K\"/>\n                                        </columns>\n                                        <gridCells>\n                                            <gridCell row=\"mZ9-hx-ewv\" column=\"fVa-ZO-Yb4\" id=\"oHW-zq-h02\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Sgb-MI-xrH\">\n                                                    <rect key=\"frame\" x=\"6\" y=\"32\" width=\"162\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" lineBreakMode=\"clipping\" alignment=\"right\" title=\"Main window appearance:\" id=\"8Z0-DR-TbO\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"mZ9-hx-ewv\" column=\"Lzf-OU-P1K\" id=\"Iv6-fi-vMO\">\n                                                <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IpK-gF-a4e\">\n                                                    <rect key=\"frame\" x=\"171\" y=\"25\" width=\"154\" height=\"25\"/>\n                                                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Your Mac's Default\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"Css-S7-CuP\" id=\"Vx1-Tf-9xQ\">\n                                                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                        <menu key=\"menu\" id=\"EVK-x2-XAx\">\n                                                            <items>\n                                                                <menuItem title=\"Your Mac's Default\" state=\"on\" id=\"Css-S7-CuP\"/>\n                                                                <menuItem isSeparatorItem=\"YES\" id=\"blI-1A-aBK\"/>\n                                                                <menuItem title=\"Light\" tag=\"1\" id=\"FcH-RG-lTN\"/>\n                                                                <menuItem title=\"Dark\" tag=\"2\" id=\"mub-Pt-QHm\">\n                                                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                                                </menuItem>\n                                                            </items>\n                                                        </menu>\n                                                    </popUpButtonCell>\n                                                    <connections>\n                                                        <action selector=\"onChangedAppearance:\" target=\"-2\" id=\"EIC-vs-75R\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.Appearance\" id=\"nfE-87-3lM\"/>\n                                                    </connections>\n                                                </popUpButton>\n                                            </gridCell>\n                                            <gridCell row=\"XiR-N0-kUX\" column=\"fVa-ZO-Yb4\" id=\"vrD-Wb-mLY\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wa5-Rg-5aD\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"1\" width=\"170\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Main window transparency:\" id=\"Pab-0Z-VAE\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"XiR-N0-kUX\" column=\"Lzf-OU-P1K\" id=\"JpA-7o-5a3\">\n                                                <stackView key=\"contentView\" distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" spacing=\"6\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l99-Sl-yf7\">\n                                                    <rect key=\"frame\" x=\"174\" y=\"0.0\" width=\"251\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lSR-7V-PDD\">\n                                                            <rect key=\"frame\" x=\"-2\" y=\"1\" width=\"29\" height=\"14\"/>\n                                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"80%\" id=\"etq-xm-HYN\">\n                                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                        <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6Uk-IU-HIb\">\n                                                            <rect key=\"frame\" x=\"29\" y=\"-2\" width=\"200\" height=\"20\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"width\" constant=\"196\" id=\"vvo-4g-75D\"/>\n                                                            </constraints>\n                                                            <sliderCell key=\"cell\" controlSize=\"small\" continuous=\"YES\" state=\"on\" alignment=\"left\" minValue=\"0.20000000000000001\" maxValue=\"1\" doubleValue=\"1\" tickMarkPosition=\"above\" sliderType=\"linear\" id=\"4bQ-HS-Zy3\"/>\n                                                            <accessibility description=\"Main Window Transparency Percent\"/>\n                                                            <connections>\n                                                                <accessibilityConnection property=\"title\" destination=\"wa5-Rg-5aD\" id=\"LIf-mV-7Qb\"/>\n                                                                <action selector=\"onChangedTransparency:\" target=\"-2\" id=\"Gaw-Ji-di5\"/>\n                                                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.MainWindowTransparencyLevel\" id=\"5kG-AH-VhK\"/>\n                                                            </connections>\n                                                        </slider>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lQi-te-LwT\">\n                                                            <rect key=\"frame\" x=\"231\" y=\"1\" width=\"22\" height=\"14\"/>\n                                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"0%\" id=\"TsQ-VK-5QG\">\n                                                                <font key=\"font\" metaFont=\"smallSystem\"/>\n                                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <visibilityPriorities>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                    </visibilityPriorities>\n                                                    <customSpacing>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                    </customSpacing>\n                                                </stackView>\n                                            </gridCell>\n                                        </gridCells>\n                                    </gridView>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iWl-Y8-qXs\">\n                                        <rect key=\"frame\" x=\"102\" y=\"174\" width=\"166\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Arrange multiple channels:\" id=\"aNN-WN-TzZ\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dG4-2O-lpO\">\n                                        <rect key=\"frame\" x=\"271\" y=\"167\" width=\"125\" height=\"25\"/>\n                                        <popUpButtonCell key=\"cell\" type=\"push\" title=\"Top to bottom\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"5M2-Hy-cjn\" id=\"2Va-c1-ec9\">\n                                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                            <menu key=\"menu\" id=\"4KX-3N-cgN\">\n                                                <items>\n                                                    <menuItem title=\"Top to bottom\" state=\"on\" id=\"5M2-Hy-cjn\"/>\n                                                    <menuItem title=\"Left to right\" tag=\"1\" id=\"KQL-S9-iQv\"/>\n                                                </items>\n                                            </menu>\n                                        </popUpButtonCell>\n                                        <connections>\n                                            <action selector=\"onChangedChannelViewArrangement:\" target=\"-2\" id=\"UCu-N5-YV9\"/>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.ChannelViewArrangement\" id=\"wYA-YM-Paw\"/>\n                                        </connections>\n                                    </popUpButton>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"kad-3P-XnO\" firstAttribute=\"top\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"top\" constant=\"40\" id=\"0tB-P2-qcy\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"kad-3P-XnO\" secondAttribute=\"trailing\" constant=\"20\" id=\"FUh-Lo-Gvl\"/>\n                                    <constraint firstItem=\"pbE-2M-fRW\" firstAttribute=\"leading\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"leading\" constant=\"40\" id=\"H2R-dY-dLb\"/>\n                                    <constraint firstItem=\"v8u-aO-cik\" firstAttribute=\"top\" secondItem=\"dG4-2O-lpO\" secondAttribute=\"bottom\" constant=\"18\" id=\"IMO-ib-ZcF\"/>\n                                    <constraint firstItem=\"iWl-Y8-qXs\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"leading\" constant=\"20\" id=\"JSv-wD-y74\"/>\n                                    <constraint firstItem=\"pbE-2M-fRW\" firstAttribute=\"top\" secondItem=\"kad-3P-XnO\" secondAttribute=\"bottom\" constant=\"18\" id=\"LIx-LE-czg\"/>\n                                    <constraint firstItem=\"kad-3P-XnO\" firstAttribute=\"leading\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"leading\" constant=\"42\" id=\"LY1-vR-XH4\"/>\n                                    <constraint firstItem=\"iWl-Y8-qXs\" firstAttribute=\"firstBaseline\" secondItem=\"dG4-2O-lpO\" secondAttribute=\"firstBaseline\" id=\"PgP-vd-lzi\"/>\n                                    <constraint firstItem=\"RZ1-8W-O04\" firstAttribute=\"top\" secondItem=\"Dwh-L6-1bu\" secondAttribute=\"bottom\" constant=\"18\" id=\"QPe-se-sRj\"/>\n                                    <constraint firstItem=\"Dwh-L6-1bu\" firstAttribute=\"top\" secondItem=\"pbE-2M-fRW\" secondAttribute=\"bottom\" constant=\"18\" id=\"Qfh-3C-AeF\"/>\n                                    <constraint firstItem=\"5Ks-KS-pKv\" firstAttribute=\"top\" secondItem=\"v8u-aO-cik\" secondAttribute=\"bottom\" constant=\"18\" id=\"cPk-D1-rts\"/>\n                                    <constraint firstItem=\"Dwh-L6-1bu\" firstAttribute=\"centerX\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"centerX\" id=\"cdo-bt-dO5\"/>\n                                    <constraint firstItem=\"iWl-Y8-qXs\" firstAttribute=\"trailing\" secondItem=\"wa5-Rg-5aD\" secondAttribute=\"trailing\" id=\"clT-et-REG\"/>\n                                    <constraint firstItem=\"pbE-2M-fRW\" firstAttribute=\"centerX\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"centerX\" id=\"fFn-5h-Lk5\"/>\n                                    <constraint firstItem=\"5Ks-KS-pKv\" firstAttribute=\"leading\" secondItem=\"Ht3-ub-Duo\" secondAttribute=\"leading\" constant=\"42\" id=\"fHb-kJ-GLg\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"dG4-2O-lpO\" secondAttribute=\"trailing\" constant=\"20\" id=\"hLa-N4-poA\"/>\n                                    <constraint firstItem=\"v8u-aO-cik\" firstAttribute=\"leading\" secondItem=\"pbE-2M-fRW\" secondAttribute=\"leading\" id=\"p0M-qe-TGP\"/>\n                                    <constraint firstItem=\"RZ1-8W-O04\" firstAttribute=\"trailing\" secondItem=\"pbE-2M-fRW\" secondAttribute=\"trailing\" id=\"pJY-Ko-MFa\"/>\n                                    <constraint firstItem=\"dG4-2O-lpO\" firstAttribute=\"leading\" secondItem=\"iWl-Y8-qXs\" secondAttribute=\"trailing\" constant=\"8\" id=\"qFn-ie-VbH\"/>\n                                    <constraint firstItem=\"dG4-2O-lpO\" firstAttribute=\"top\" secondItem=\"RZ1-8W-O04\" secondAttribute=\"bottom\" constant=\"18\" id=\"tig-jy-hcB\"/>\n                                    <constraint firstItem=\"v8u-aO-cik\" firstAttribute=\"trailing\" secondItem=\"pbE-2M-fRW\" secondAttribute=\"trailing\" id=\"w9Q-yh-9nO\"/>\n                                    <constraint firstItem=\"RZ1-8W-O04\" firstAttribute=\"leading\" secondItem=\"pbE-2M-fRW\" secondAttribute=\"leading\" id=\"yCe-v6-oZy\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Server List Colors\" identifier=\"\" id=\"HCE-kN-Cdc\">\n                            <view key=\"view\" id=\"hBO-c8-FmJ\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"370\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"djo-q8-UrU\">\n                                        <rect key=\"frame\" x=\"103\" y=\"316\" width=\"418\" height=\"24\"/>\n                                        <subviews>\n                                            <colorWell translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DUy-zX-hVp\">\n                                                <rect key=\"frame\" x=\"312\" y=\"0.0\" width=\"48\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"48\" id=\"OWb-Sf-cgr\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"ePJ-T6-zWB\"/>\n                                                </constraints>\n                                                <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <connections>\n                                                    <accessibilityConnection property=\"title\" destination=\"aSj-pP-pk3\" id=\"Y4p-bJ-NC4\"/>\n                                                    <action selector=\"onChangedServerListUnreadBadgeColor:\" target=\"-2\" id=\"ldT-Rr-QPH\"/>\n                                                    <binding destination=\"-2\" name=\"value\" keyPath=\"self.serverListUnreadCountBadgeHighlightColor\" id=\"BrJ-NT-gHC\"/>\n                                                </connections>\n                                            </colorWell>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aSj-pP-pk3\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"308\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Background color for unread badge with highlight:\" id=\"sqY-lA-TEZ\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pZM-BH-WK6\">\n                                                <rect key=\"frame\" x=\"367\" y=\"-1\" width=\"52\" height=\"23\"/>\n                                                <buttonCell key=\"cell\" type=\"roundTextured\" title=\"Reset\" bezelStyle=\"texturedRounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"LRn-gf-kEg\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <accessibility description=\"Reset Background Color for Unread Badge with Highlight\"/>\n                                                <connections>\n                                                    <action selector=\"onResetServerListUnreadBadgeColorsToDefault:\" target=\"-2\" id=\"gd5-H0-ojf\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"aSj-pP-pk3\" firstAttribute=\"leading\" secondItem=\"djo-q8-UrU\" secondAttribute=\"leading\" id=\"2kR-Ka-RVY\"/>\n                                            <constraint firstItem=\"DUy-zX-hVp\" firstAttribute=\"leading\" secondItem=\"aSj-pP-pk3\" secondAttribute=\"trailing\" constant=\"8\" id=\"Bdj-5y-zmR\"/>\n                                            <constraint firstItem=\"pZM-BH-WK6\" firstAttribute=\"firstBaseline\" secondItem=\"aSj-pP-pk3\" secondAttribute=\"firstBaseline\" id=\"DLz-Ph-iOm\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"DUy-zX-hVp\" secondAttribute=\"bottom\" id=\"fch-re-bob\"/>\n                                            <constraint firstItem=\"DUy-zX-hVp\" firstAttribute=\"centerY\" secondItem=\"aSj-pP-pk3\" secondAttribute=\"centerY\" id=\"jhe-0q-MNt\"/>\n                                            <constraint firstItem=\"pZM-BH-WK6\" firstAttribute=\"leading\" secondItem=\"DUy-zX-hVp\" secondAttribute=\"trailing\" constant=\"8\" id=\"jyw-kE-e2G\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"pZM-BH-WK6\" secondAttribute=\"trailing\" id=\"sG6-Dj-fLL\"/>\n                                            <constraint firstItem=\"DUy-zX-hVp\" firstAttribute=\"top\" secondItem=\"djo-q8-UrU\" secondAttribute=\"top\" id=\"y5i-wH-oRL\"/>\n                                        </constraints>\n                                    </customView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"djo-q8-UrU\" firstAttribute=\"centerX\" secondItem=\"hBO-c8-FmJ\" secondAttribute=\"centerX\" id=\"1F0-tZ-1cX\"/>\n                                    <constraint firstItem=\"djo-q8-UrU\" firstAttribute=\"top\" secondItem=\"hBO-c8-FmJ\" secondAttribute=\"top\" constant=\"30\" id=\"If2-Fo-Ri8\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"User List Colors\" identifier=\"2\" id=\"ozM-AW-weC\">\n                            <view key=\"view\" id=\"wAG-b4-1dF\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"370\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KaQ-rf-529\">\n                                        <rect key=\"frame\" x=\"124\" y=\"316\" width=\"377\" height=\"32\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"These colors represent the various user modes shown on the user list for each channel.\" id=\"2QW-Qh-FdK\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yGR-pH-h8S\">\n                                        <rect key=\"frame\" x=\"40\" y=\"295\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1GB-Dc-JXA\">\n                                        <rect key=\"frame\" x=\"40\" y=\"65\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"awz-7b-J7x\">\n                                        <rect key=\"frame\" x=\"232\" y=\"27\" width=\"160\" height=\"23\"/>\n                                        <buttonCell key=\"cell\" type=\"roundTextured\" title=\"Reset to Defaults\" bezelStyle=\"texturedRounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"wwW-w1-jyD\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"158\" id=\"xp3-Ib-MOr\"/>\n                                        </constraints>\n                                        <accessibility description=\"Reset User List Colors to Default Values\"/>\n                                        <connections>\n                                            <action selector=\"onResetUserListModeColorsToDefaults:\" target=\"-2\" id=\"aNk-h8-cQO\"/>\n                                        </connections>\n                                    </button>\n                                    <gridView xPlacement=\"trailing\" yPlacement=\"center\" rowAlignment=\"none\" rowSpacing=\"11\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gSp-DR-d4L\">\n                                        <rect key=\"frame\" x=\"199\" y=\"86\" width=\"227\" height=\"193\"/>\n                                        <rows>\n                                            <gridRow id=\"1ly-Qg-5fO\"/>\n                                            <gridRow id=\"PmZ-VQ-Cmc\"/>\n                                            <gridRow id=\"SUL-Qo-ane\"/>\n                                            <gridRow id=\"PJ6-Cq-Wyt\"/>\n                                            <gridRow id=\"gJP-Xf-nv5\"/>\n                                            <gridRow id=\"z3c-5A-xPY\"/>\n                                        </rows>\n                                        <columns>\n                                            <gridColumn xPlacement=\"trailing\" id=\"sJU-tc-EwK\"/>\n                                            <gridColumn xPlacement=\"fill\" id=\"XT8-6U-SES\"/>\n                                        </columns>\n                                        <gridCells>\n                                            <gridCell row=\"1ly-Qg-5fO\" column=\"sJU-tc-EwK\" id=\"nel-AD-UtW\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"um4-jh-YFM\">\n                                                    <rect key=\"frame\" x=\"39\" y=\"174\" width=\"134\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Server Staff Member:\" id=\"MCy-M2-bOc\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"1ly-Qg-5fO\" column=\"XT8-6U-SES\" id=\"B2R-YK-bY5\">\n                                                <colorWell key=\"contentView\" tag=\"10\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JhD-ZF-Sav\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"170\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"BnX-Gw-vyY\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"dvG-us-jaY\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"um4-jh-YFM\" id=\"f5O-5Q-vXU\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"IXq-I3-M72\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +y\" id=\"GzY-Ki-kDQ\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                            <gridCell row=\"PmZ-VQ-Cmc\" column=\"sJU-tc-EwK\" id=\"Vd8-Jr-5an\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hfA-Bg-ot8\">\n                                                    <rect key=\"frame\" x=\"43\" y=\"140\" width=\"130\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Channel Owner (+q):\" id=\"UFb-25-XAa\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"PmZ-VQ-Cmc\" column=\"XT8-6U-SES\" id=\"uVE-GZ-YOk\">\n                                                <colorWell key=\"contentView\" tag=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JXn-pJ-hWs\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"136\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"cHU-Cz-Wrg\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"cXS-5U-kMn\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"hfA-Bg-ot8\" id=\"PR8-bt-DGd\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"meL-e3-Oab\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +q\" id=\"jNB-MT-zjP\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                            <gridCell row=\"SUL-Qo-ane\" column=\"sJU-tc-EwK\" id=\"PpM-0y-s9o\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QgH-Fh-Jts\">\n                                                    <rect key=\"frame\" x=\"2\" y=\"106\" width=\"171\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Channel Administrator (+a):\" id=\"sZQ-wC-KNB\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"SUL-Qo-ane\" column=\"XT8-6U-SES\" id=\"M9A-4R-Mn8\">\n                                                <colorWell key=\"contentView\" tag=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YGS-3n-rXC\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"102\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"Rbq-WT-nOr\"/>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"l1J-Hx-Efw\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"QgH-Fh-Jts\" id=\"2Gm-P1-Hsu\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"qyJ-DW-aTf\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +a\" id=\"OpN-Q4-qQT\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                            <gridCell row=\"PJ6-Cq-Wyt\" column=\"sJU-tc-EwK\" id=\"HOR-Qv-HCM\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"S7K-Fn-yaj\">\n                                                    <rect key=\"frame\" x=\"28\" y=\"72\" width=\"145\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Channel Operator (+o):\" id=\"zFp-kc-rli\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"PJ6-Cq-Wyt\" column=\"XT8-6U-SES\" id=\"62V-tC-1RW\">\n                                                <colorWell key=\"contentView\" tag=\"7\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O44-GT-9T4\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"68\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"lgL-q2-x5x\"/>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"uhZ-aB-fQk\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"S7K-Fn-yaj\" id=\"cnp-k2-7gH\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"d9J-XE-tNi\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +o\" id=\"Dbp-qa-FSS\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                            <gridCell row=\"gJP-Xf-nv5\" column=\"sJU-tc-EwK\" id=\"Be4-CF-SFb\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FS5-lg-ZQk\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"38\" width=\"175\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Channel Half-Operator (+h):\" id=\"GSl-Ms-MKb\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"gJP-Xf-nv5\" column=\"XT8-6U-SES\" id=\"7oL-M6-0Yy\">\n                                                <colorWell key=\"contentView\" tag=\"6\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4Ej-1Y-15S\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"34\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"ZyG-8h-C2E\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"uQC-7x-gAf\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"FS5-lg-ZQk\" id=\"Xb2-zS-4A4\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"Y7e-RA-FfC\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +h\" id=\"AnD-Pz-Jld\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                            <gridCell row=\"z3c-5A-xPY\" column=\"sJU-tc-EwK\" id=\"Aid-jl-VHe\">\n                                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XeX-Ma-9Hc\">\n                                                    <rect key=\"frame\" x=\"63\" y=\"4\" width=\"110\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Voiced User (+v):\" id=\"D4D-ZL-ab0\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </gridCell>\n                                            <gridCell row=\"z3c-5A-xPY\" column=\"XT8-6U-SES\" id=\"LeV-IY-nrw\">\n                                                <colorWell key=\"contentView\" tag=\"5\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CIN-D3-YPG\">\n                                                    <rect key=\"frame\" x=\"179\" y=\"0.0\" width=\"48\" height=\"23\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"48\" id=\"2dW-tx-6us\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"ED1-Ft-2cu\"/>\n                                                    </constraints>\n                                                    <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                    <connections>\n                                                        <accessibilityConnection property=\"title\" destination=\"XeX-Ma-9Hc\" id=\"AGo-nH-LHA\"/>\n                                                        <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"jdM-Ar-u3T\"/>\n                                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.User List Mode Badge Colors -&gt; +v\" id=\"LGN-uw-k3a\">\n                                                            <dictionary key=\"options\">\n                                                                <string key=\"NSValueTransformerName\">NSUnarchiveFromData</string>\n                                                            </dictionary>\n                                                        </binding>\n                                                    </connections>\n                                                </colorWell>\n                                            </gridCell>\n                                        </gridCells>\n                                    </gridView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"awz-7b-J7x\" firstAttribute=\"centerX\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"centerX\" id=\"4Ry-eM-Sds\"/>\n                                    <constraint firstItem=\"yGR-pH-h8S\" firstAttribute=\"trailing\" secondItem=\"1GB-Dc-JXA\" secondAttribute=\"trailing\" id=\"5o1-Te-MzU\"/>\n                                    <constraint firstItem=\"yGR-pH-h8S\" firstAttribute=\"top\" secondItem=\"KaQ-rf-529\" secondAttribute=\"bottom\" constant=\"18\" id=\"9ml-nn-iBg\"/>\n                                    <constraint firstItem=\"KaQ-rf-529\" firstAttribute=\"top\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"top\" constant=\"22\" id=\"ENa-e3-6kB\"/>\n                                    <constraint firstItem=\"1GB-Dc-JXA\" firstAttribute=\"leading\" secondItem=\"yGR-pH-h8S\" secondAttribute=\"leading\" id=\"MGC-oW-0ov\"/>\n                                    <constraint firstItem=\"gSp-DR-d4L\" firstAttribute=\"top\" secondItem=\"yGR-pH-h8S\" secondAttribute=\"bottom\" constant=\"18\" id=\"PBx-0l-WsJ\"/>\n                                    <constraint firstItem=\"yGR-pH-h8S\" firstAttribute=\"centerX\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"centerX\" id=\"W3D-B4-405\"/>\n                                    <constraint firstItem=\"KaQ-rf-529\" firstAttribute=\"centerX\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"centerX\" id=\"WCf-99-da0\"/>\n                                    <constraint firstItem=\"1GB-Dc-JXA\" firstAttribute=\"top\" secondItem=\"gSp-DR-d4L\" secondAttribute=\"bottom\" constant=\"18\" id=\"YA4-18-DL5\"/>\n                                    <constraint firstItem=\"gSp-DR-d4L\" firstAttribute=\"centerX\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"centerX\" id=\"mcK-K3-kFb\"/>\n                                    <constraint firstItem=\"awz-7b-J7x\" firstAttribute=\"top\" secondItem=\"1GB-Dc-JXA\" secondAttribute=\"bottom\" constant=\"18\" id=\"vyJ-aN-03n\"/>\n                                    <constraint firstItem=\"yGR-pH-h8S\" firstAttribute=\"leading\" secondItem=\"wAG-b4-1dF\" secondAttribute=\"leading\" constant=\"40\" id=\"xFb-aO-GgV\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                    </tabViewItems>\n                </tabView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"emo-oX-cWx\" firstAttribute=\"top\" secondItem=\"2Th-u8-aIC\" secondAttribute=\"top\" constant=\"16\" id=\"5rO-aJ-VyF\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"emo-oX-cWx\" secondAttribute=\"trailing\" constant=\"20\" id=\"GzX-AU-IaN\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"emo-oX-cWx\" secondAttribute=\"bottom\" constant=\"20\" id=\"QsU-Ce-KXb\"/>\n                <constraint firstItem=\"emo-oX-cWx\" firstAttribute=\"leading\" secondItem=\"2Th-u8-aIC\" secondAttribute=\"leading\" constant=\"20\" id=\"f7l-ep-Nt6\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-5533\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oeR-nv-slx\" userLabel=\"Style\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"346\"/>\n            <subviews>\n                <tabView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lpz-77-UDw\">\n                    <rect key=\"frame\" x=\"13\" y=\"10\" width=\"644\" height=\"326\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"310\" id=\"g8B-Bz-RFb\"/>\n                    </constraints>\n                    <font key=\"font\" metaFont=\"system\"/>\n                    <tabViewItems>\n                        <tabViewItem label=\"General\" identifier=\"1\" id=\"yKL-ON-PSA\">\n                            <view key=\"view\" id=\"bCO-56-p1h\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"280\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EC4-0b-hiq\">\n                                        <rect key=\"frame\" x=\"170\" y=\"173\" width=\"284\" height=\"21\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"19a-B6-iEv\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"35\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Font:\" id=\"Rms-5m-RLS\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <textField focusRingType=\"none\" horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WiQ-md-lej\">\n                                                <rect key=\"frame\" x=\"39\" y=\"0.0\" width=\"179\" height=\"21\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" title=\"Helvetica 12pt\" drawsBackground=\"YES\" id=\"Yeq-PY-2Ot\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <accessibility description=\"Current Content Font\"/>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"displayPatternValue1\" keyPath=\"themeChannelViewFontName\" id=\"lNo-Q4-L19\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSDisplayPattern\">%{value1}@ %{value2}@pt</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"-2\" name=\"displayPatternValue2\" keyPath=\"themeChannelViewFontSize\" previousBinding=\"lNo-Q4-L19\" id=\"421-AF-MFO\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSDisplayPattern\">%{value1}@ %{value2}@pt</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.Theme -&gt; Channel Font Preference Enabled\" id=\"JfV-UB-ZCB\"/>\n                                                </connections>\n                                            </textField>\n                                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RCg-fG-WEB\">\n                                                <rect key=\"frame\" x=\"226\" y=\"0.0\" width=\"58\" height=\"19\"/>\n                                                <buttonCell key=\"cell\" type=\"roundRect\" title=\"Change\" bezelStyle=\"roundedRect\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"Oyi-xz-dDf\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                </buttonCell>\n                                                <accessibility description=\"Change Content Font\"/>\n                                                <connections>\n                                                    <accessibilityConnection property=\"title\" destination=\"19a-B6-iEv\" id=\"Ikc-qO-S3F\"/>\n                                                    <action selector=\"onSelectNewFont:\" target=\"-2\" id=\"Q0K-AD-1dQ\"/>\n                                                    <binding destination=\"-2\" name=\"enabled2\" keyPath=\"self.reloadingTheme\" previousBinding=\"BXQ-7H-Qn2\" id=\"cvN-1i-doc\">\n                                                        <dictionary key=\"options\">\n                                                            <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                            <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.Theme -&gt; Channel Font Preference Enabled\" id=\"BXQ-7H-Qn2\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mpf-VK-Ftr\">\n                                        <rect key=\"frame\" x=\"112\" y=\"230\" width=\"400\" height=\"20\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"inL-ss-ERr\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"39\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Style:\" id=\"0nX-n7-cOc\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <popUpButton horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ICa-wc-PBy\">\n                                                <rect key=\"frame\" x=\"40\" y=\"-4\" width=\"239\" height=\"25\"/>\n                                                <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" inset=\"2\" id=\"hFg-IF-B8g\">\n                                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                    <menu key=\"menu\" title=\"OtherViews\" id=\"vmB-ra-bu8\"/>\n                                                </popUpButtonCell>\n                                                <accessibility description=\"Current Style\"/>\n                                                <connections>\n                                                    <action selector=\"onChangedThemeSelection:\" target=\"-2\" id=\"Fsz-Xr-4Ro\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"p3e-3O-pA8\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </popUpButton>\n                                            <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wmq-Ee-waL\">\n                                                <rect key=\"frame\" x=\"283\" y=\"0.0\" width=\"117\" height=\"19\"/>\n                                                <buttonCell key=\"cell\" type=\"roundRect\" title=\"Browse Style Files\" bezelStyle=\"roundedRect\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"gtM-zH-PMU\">\n                                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                </buttonCell>\n                                                <accessibility description=\"View files associated with the current style\"/>\n                                                <connections>\n                                                    <action selector=\"onOpenPathToTheme:\" target=\"-2\" id=\"Fa3-dM-vjS\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"xIj-Ez-hta\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"j2v-v4-NVg\">\n                                        <rect key=\"frame\" x=\"40\" y=\"209\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FAp-of-4TG\">\n                                        <rect key=\"frame\" x=\"40\" y=\"151\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yk4-L0-S54\">\n                                        <rect key=\"frame\" x=\"187\" y=\"59\" width=\"251\" height=\"76\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jNN-n9-eyu\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"253\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Automatically add scrollback markers\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"imb-ex-Fq2\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutomaticallyAddScrollbackMarker\" id=\"kBt-PY-72G\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SLL-vr-2ha\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"145\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show date changes\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"YYv-Je-Wv0\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedTheme:\" target=\"-2\" id=\"mOm-KX-hCK\"/>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayEventInLogView -&gt; Date Changes\" id=\"hWe-E5-KIU\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7LB-4e-2Po\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"210\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show general event messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"toP-T2-dv6\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayEventInLogView -&gt; Join, Part, Quit\" id=\"Jwb-Rk-nuD\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I3x-2t-PYn\">\n                                        <rect key=\"frame\" x=\"203\" y=\"36\" width=\"257\" height=\"15\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"These include join, part, and quit messages. \" id=\"Lfm-fL-lVE\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"link\" destination=\"7LB-4e-2Po\" id=\"Bd1-he-n9U\"/>\n                                        </connections>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"Mpf-VK-Ftr\" firstAttribute=\"top\" secondItem=\"bCO-56-p1h\" secondAttribute=\"top\" constant=\"30\" id=\"0vd-Yj-7tF\"/>\n                                    <constraint firstItem=\"j2v-v4-NVg\" firstAttribute=\"leading\" secondItem=\"bCO-56-p1h\" secondAttribute=\"leading\" constant=\"40\" id=\"3aW-Da-V3R\"/>\n                                    <constraint firstItem=\"FAp-of-4TG\" firstAttribute=\"top\" secondItem=\"EC4-0b-hiq\" secondAttribute=\"bottom\" constant=\"18.5\" id=\"5Mg-K4-c4T\"/>\n                                    <constraint firstItem=\"Mpf-VK-Ftr\" firstAttribute=\"centerX\" secondItem=\"bCO-56-p1h\" secondAttribute=\"centerX\" id=\"7VT-n8-ZQX\"/>\n                                    <constraint firstItem=\"Mpf-VK-Ftr\" firstAttribute=\"leading\" secondItem=\"bCO-56-p1h\" secondAttribute=\"leading\" constant=\"112\" id=\"8Sa-hn-VYQ\"/>\n                                    <constraint firstItem=\"yk4-L0-S54\" firstAttribute=\"centerX\" secondItem=\"bCO-56-p1h\" secondAttribute=\"centerX\" id=\"8bF-Co-Wx1\"/>\n                                    <constraint firstItem=\"j2v-v4-NVg\" firstAttribute=\"top\" secondItem=\"Mpf-VK-Ftr\" secondAttribute=\"bottom\" constant=\"18\" id=\"9Xx-Fw-4FG\"/>\n                                    <constraint firstItem=\"I3x-2t-PYn\" firstAttribute=\"leading\" secondItem=\"7LB-4e-2Po\" secondAttribute=\"leading\" constant=\"18\" id=\"I7d-gL-zJK\"/>\n                                    <constraint firstItem=\"yk4-L0-S54\" firstAttribute=\"top\" secondItem=\"FAp-of-4TG\" secondAttribute=\"bottom\" constant=\"18\" id=\"L1x-hg-vqa\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"I3x-2t-PYn\" secondAttribute=\"trailing\" constant=\"20\" id=\"MnT-ef-fUY\"/>\n                                    <constraint firstItem=\"FAp-of-4TG\" firstAttribute=\"leading\" secondItem=\"j2v-v4-NVg\" secondAttribute=\"leading\" id=\"aNx-3X-Uc8\"/>\n                                    <constraint firstItem=\"j2v-v4-NVg\" firstAttribute=\"centerX\" secondItem=\"bCO-56-p1h\" secondAttribute=\"centerX\" id=\"gL6-or-0Xm\"/>\n                                    <constraint firstItem=\"I3x-2t-PYn\" firstAttribute=\"top\" secondItem=\"7LB-4e-2Po\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"l21-wT-1fL\"/>\n                                    <constraint firstItem=\"EC4-0b-hiq\" firstAttribute=\"leading\" secondItem=\"bCO-56-p1h\" secondAttribute=\"leading\" constant=\"170\" id=\"l3l-8q-kwa\"/>\n                                    <constraint firstItem=\"EC4-0b-hiq\" firstAttribute=\"top\" secondItem=\"j2v-v4-NVg\" secondAttribute=\"bottom\" constant=\"17.5\" id=\"lrG-6c-jOZ\"/>\n                                    <constraint firstItem=\"FAp-of-4TG\" firstAttribute=\"trailing\" secondItem=\"j2v-v4-NVg\" secondAttribute=\"trailing\" id=\"rUN-Oi-OMq\"/>\n                                    <constraint firstItem=\"EC4-0b-hiq\" firstAttribute=\"centerX\" secondItem=\"bCO-56-p1h\" secondAttribute=\"centerX\" id=\"szL-JY-PdC\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Developers\" identifier=\"\" id=\"1bZ-1x-Ua9\">\n                            <view key=\"view\" id=\"zwO-BD-Weo\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"625\" height=\"280\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hcQ-eU-esk\">\n                                        <rect key=\"frame\" x=\"40\" y=\"175\" width=\"545\" height=\"5\"/>\n                                    </box>\n                                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ywg-YX-GQf\">\n                                        <rect key=\"frame\" x=\"195\" y=\"132\" width=\"236\" height=\"32\"/>\n                                        <buttonCell key=\"cell\" type=\"push\" title=\"Modify Custom Style Sheet Rules\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"QFK-n6-IVM\">\n                                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"onModifyUserStyleSheetRules:\" target=\"-2\" id=\"lNM-SU-jMT\"/>\n                                        </connections>\n                                    </button>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OHt-lc-jrk\">\n                                        <rect key=\"frame\" x=\"136\" y=\"233\" width=\"351\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Automatically reload custom styles when they change\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"mrD-Ge-g9M\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutomaticallyReloadCustomThemesWhenTheyChange\" id=\"4eu-Dj-tFb\"/>\n                                        </connections>\n                                    </button>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5jC-mC-OiS\">\n                                        <rect key=\"frame\" x=\"154\" y=\"196\" width=\"330\" height=\"30\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"A reload will occur if any file with the extension .css or .js is modified within the root directory of the active style.\" id=\"vYn-fL-9T7\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"5jC-mC-OiS\" firstAttribute=\"top\" secondItem=\"OHt-lc-jrk\" secondAttribute=\"bottom\" constant=\"8\" id=\"1Vf-Ec-kBn\"/>\n                                    <constraint firstItem=\"hcQ-eU-esk\" firstAttribute=\"leading\" secondItem=\"zwO-BD-Weo\" secondAttribute=\"leading\" constant=\"40\" id=\"3mD-8H-o1Z\"/>\n                                    <constraint firstItem=\"OHt-lc-jrk\" firstAttribute=\"top\" secondItem=\"zwO-BD-Weo\" secondAttribute=\"top\" constant=\"30\" id=\"8Do-di-uUR\"/>\n                                    <constraint firstItem=\"hcQ-eU-esk\" firstAttribute=\"centerX\" secondItem=\"zwO-BD-Weo\" secondAttribute=\"centerX\" id=\"Efu-9j-edC\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"5jC-mC-OiS\" secondAttribute=\"trailing\" constant=\"20\" id=\"ErC-8E-qGR\"/>\n                                    <constraint firstItem=\"hcQ-eU-esk\" firstAttribute=\"top\" secondItem=\"5jC-mC-OiS\" secondAttribute=\"bottom\" constant=\"18\" id=\"HY5-bp-tIB\"/>\n                                    <constraint firstItem=\"ywg-YX-GQf\" firstAttribute=\"top\" secondItem=\"hcQ-eU-esk\" secondAttribute=\"bottom\" constant=\"18\" id=\"O8g-Ut-pjn\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"OHt-lc-jrk\" secondAttribute=\"trailing\" constant=\"20\" id=\"Tqq-0k-MYb\"/>\n                                    <constraint firstItem=\"5jC-mC-OiS\" firstAttribute=\"leading\" secondItem=\"OHt-lc-jrk\" secondAttribute=\"leading\" constant=\"18\" id=\"XuU-Bi-L43\"/>\n                                    <constraint firstItem=\"ywg-YX-GQf\" firstAttribute=\"centerX\" secondItem=\"zwO-BD-Weo\" secondAttribute=\"centerX\" id=\"b0X-0B-gn1\"/>\n                                    <constraint firstItem=\"OHt-lc-jrk\" firstAttribute=\"leading\" secondItem=\"zwO-BD-Weo\" secondAttribute=\"leading\" constant=\"138\" id=\"lWq-wB-75e\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Scrollback\" identifier=\"\" id=\"77x-1S-pOH\">\n                            <view key=\"view\" id=\"Ez7-yK-bTh\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"625\" height=\"280\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"51b-3N-Ofw\">\n                                        <rect key=\"frame\" x=\"178\" y=\"232\" width=\"269\" height=\"19\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PTW-Er-MK5\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"2\" width=\"137\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Scrollback Save Limit:\" id=\"RaE-yM-G1d\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <comboBox focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cbq-aG-DA1\">\n                                                <rect key=\"frame\" x=\"141\" y=\"-4\" width=\"131\" height=\"25\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"128\" id=\"jdj-N4-JKy\"/>\n                                                </constraints>\n                                                <comboBoxCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" completes=\"NO\" numberOfVisibleItems=\"5\" id=\"AGK-eb-sBS\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <objectValues>\n                                                        <string>1000</string>\n                                                        <string>2000</string>\n                                                        <string>3000</string>\n                                                        <string>4000</string>\n                                                        <string>5000</string>\n                                                        <string>10000</string>\n                                                        <string>20000</string>\n                                                        <string>30000</string>\n                                                        <string>40000</string>\n                                                        <string>50000</string>\n                                                    </objectValues>\n                                                </comboBoxCell>\n                                                <connections>\n                                                    <accessibilityConnection property=\"title\" destination=\"PTW-Er-MK5\" id=\"F6O-ip-5s9\"/>\n                                                    <action selector=\"onChangedScrollbackSaveLimit:\" target=\"-2\" id=\"CfJ-Nm-Ito\"/>\n                                                    <binding destination=\"-2\" name=\"value\" keyPath=\"scrollbackSaveLimit\" id=\"IH4-UZ-3ib\">\n                                                        <dictionary key=\"options\">\n                                                            <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </comboBox>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RSW-HW-m6Z\">\n                                        <rect key=\"frame\" x=\"176\" y=\"134\" width=\"290\" height=\"90\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"b0a-Dq-Qqw\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <string key=\"title\">The maximum number of messages, per-channel, that are accessible through the scrollback.\n\nMessages are not saved between app launches unless “Restore scrollback from previous session” in the Behavior section of Preferences is enabled.</string>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"RSW-HW-m6Z\" firstAttribute=\"top\" secondItem=\"51b-3N-Ofw\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"BOw-wa-Qdv\"/>\n                                    <constraint firstItem=\"51b-3N-Ofw\" firstAttribute=\"centerX\" secondItem=\"Ez7-yK-bTh\" secondAttribute=\"centerX\" id=\"Ce6-Iy-vci\"/>\n                                    <constraint firstItem=\"RSW-HW-m6Z\" firstAttribute=\"leading\" secondItem=\"PTW-Er-MK5\" secondAttribute=\"leading\" id=\"HpL-QK-QIZ\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"RSW-HW-m6Z\" secondAttribute=\"trailing\" constant=\"20\" id=\"Q75-Hl-Tro\"/>\n                                    <constraint firstItem=\"51b-3N-Ofw\" firstAttribute=\"top\" secondItem=\"Ez7-yK-bTh\" secondAttribute=\"top\" constant=\"29.5\" id=\"zpi-gt-JYC\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Advanced\" identifier=\"2\" id=\"ze5-c7-Zra\">\n                            <view key=\"view\" id=\"GFi-uq-h4X\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"625\" height=\"280\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3m7-iu-b8N\">\n                                        <rect key=\"frame\" x=\"40\" y=\"131\" width=\"545\" height=\"5\"/>\n                                    </box>\n                                    <comboBox focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZLg-nc-ynI\">\n                                        <rect key=\"frame\" x=\"256\" y=\"174\" width=\"226\" height=\"25\"/>\n                                        <comboBoxCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" title=\"[%H:%M:%S]\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" completes=\"NO\" numberOfVisibleItems=\"100\" id=\"Mbr-ah-TIe\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <objectValues>\n                                                <string>[%H:%M]</string>\n                                                <string>[%H:%M:%S]</string>\n                                                <string>[%I:%M:%S %p]</string>\n                                                <string>[%m/%d/%Y -:- %I:%M:%S %p]</string>\n                                            </objectValues>\n                                        </comboBoxCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"ram-Ya-z5o\" id=\"pjv-FT-Twg\"/>\n                                            <action selector=\"onChangedTheme:\" target=\"-2\" id=\"oYR-CR-4rF\"/>\n                                            <binding destination=\"-2\" name=\"enabled2\" keyPath=\"self.reloadingTheme\" previousBinding=\"iNL-m0-JXI\" id=\"9H5-ba-0L6\">\n                                                <dictionary key=\"options\">\n                                                    <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                </dictionary>\n                                            </binding>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.Theme -&gt; Timestamp Format\" id=\"rdn-oH-aHO\"/>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.Theme -&gt; Timestamp Format Preference Enabled\" id=\"iNL-m0-JXI\">\n                                                <dictionary key=\"options\">\n                                                    <bool key=\"NSRaisesForNotApplicableKeys\" value=\"NO\"/>\n                                                </dictionary>\n                                            </binding>\n                                        </connections>\n                                    </comboBox>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VxK-V6-0nX\">\n                                        <rect key=\"frame\" x=\"135\" y=\"233\" width=\"115\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Nickname Format:\" id=\"560-ss-Wf5\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZIn-Pm-F4C\">\n                                        <rect key=\"frame\" x=\"167\" y=\"207\" width=\"300\" height=\"17\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"mPp-b5-RuW\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"300\" height=\"17\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" findStyle=\"panel\" id=\"HFC-Nn-zVf\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"107\" width=\"300\" height=\"17\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <size key=\"minSize\" width=\"300\" height=\"17\"/>\n                                                    <size key=\"maxSize\" width=\"463\" height=\"10000000\"/>\n                                                    <attributedString key=\"textStorage\">\n                                                        <fragment content=\"Symbols: \">\n                                                            <attributes>\n                                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <font key=\"NSFont\" metaFont=\"systemBold\" size=\"12\"/>\n                                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\" size=\"12\"/>\n                                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                            </attributes>\n                                                        </fragment>\n                                                        <fragment content=\" %@ = User mode; %n = User nickname\">\n                                                            <attributes>\n                                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                            </attributes>\n                                                        </fragment>\n                                                    </attributedString>\n                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textView>\n                                            </subviews>\n                                        </clipView>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"300\" id=\"9iH-ME-vLm\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"aqc-qA-u15\"/>\n                                        </constraints>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"p14-N5-Ibe\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"3Ey-4h-bzR\">\n                                            <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ram-Ya-z5o\">\n                                        <rect key=\"frame\" x=\"128\" y=\"180\" width=\"122\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Timestamp Format:\" id=\"fCW-LA-Zoa\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fBp-jn-dhC\">\n                                        <rect key=\"frame\" x=\"135\" y=\"152\" width=\"360\" height=\"17\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"hYd-WC-meI\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"360\" height=\"17\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" findStyle=\"panel\" id=\"bjI-Oj-ZU6\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"107\" width=\"360\" height=\"17\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <size key=\"minSize\" width=\"360\" height=\"17\"/>\n                                                    <size key=\"maxSize\" width=\"463\" height=\"10000000\"/>\n                                                    <attributedString key=\"textStorage\">\n                                                        <fragment content=\"A list of formatting symbols can be found at \">\n                                                            <attributes>\n                                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                            </attributes>\n                                                        </fragment>\n                                                        <fragment content=\"OpenGroup.org\">\n                                                            <attributes>\n                                                                <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                                                <url key=\"NSLink\" string=\"http://opengroup.org/onlinepubs/007908799/xsh/strftime.html\"/>\n                                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                                            </attributes>\n                                                        </fragment>\n                                                    </attributedString>\n                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textView>\n                                            </subviews>\n                                        </clipView>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"17\" id=\"Kfo-hb-cso\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"360\" id=\"h3w-vJ-435\"/>\n                                        </constraints>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"yJW-7q-lZW\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"KUc-FQ-quD\">\n                                            <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                    <comboBox focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z2q-8o-VzU\">\n                                        <rect key=\"frame\" x=\"256\" y=\"227\" width=\"226\" height=\"25\"/>\n                                        <comboBoxCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" title=\"&lt;%@%n&gt;\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" completes=\"NO\" numberOfVisibleItems=\"100\" id=\"EZr-cF-H8a\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <objectValues>\n                                                <string>%n: </string>\n                                                <string>%@%n: </string>\n                                                <string>(%n) </string>\n                                                <string>&lt;%n&gt; </string>\n                                                <string>&lt;%@%n&gt; </string>\n                                                <string>&lt;%@%-9n&gt;</string>\n                                            </objectValues>\n                                        </comboBoxCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"VxK-V6-0nX\" id=\"p50-3O-uug\"/>\n                                            <action selector=\"onChangedTheme:\" target=\"-2\" id=\"Ajj-YO-qAZ\"/>\n                                            <binding destination=\"-2\" name=\"enabled2\" keyPath=\"self.reloadingTheme\" previousBinding=\"I79-xs-TVI\" id=\"v6w-y1-eNE\">\n                                                <dictionary key=\"options\">\n                                                    <integer key=\"NSMultipleValuesPlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNoSelectionPlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNotApplicablePlaceholder\" value=\"-1\"/>\n                                                    <integer key=\"NSNullPlaceholder\" value=\"-1\"/>\n                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                </dictionary>\n                                            </binding>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.Theme -&gt; Nickname Format\" id=\"quV-wg-zM4\"/>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.Theme -&gt; Nickname Format Preference Enabled\" id=\"I79-xs-TVI\">\n                                                <dictionary key=\"options\">\n                                                    <bool key=\"NSRaisesForNotApplicableKeys\" value=\"NO\"/>\n                                                </dictionary>\n                                            </binding>\n                                        </connections>\n                                    </comboBox>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gcs-0W-25e\">\n                                        <rect key=\"frame\" x=\"158\" y=\"39\" width=\"309\" height=\"76\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NO4-3h-9X7\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"174\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Disable nickname colors\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"v8i-xw-cdg\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <action selector=\"onChangedDisableNicknameColorHashing:\" target=\"-2\" id=\"PEy-dS-w1h\"/>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"D5v-N0-vo5\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisableRemoteNicknameColorHashing\" id=\"d6n-Xn-8mL\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GRq-y8-Cey\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"311\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show mode symbol in front of inline nicknames\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"D6Y-wP-JfC\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"ZXK-5a-JbM\">\n                                                        <dictionary key=\"options\">\n                                                            <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                        </dictionary>\n                                                    </binding>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ConversationTrackingIncludesUserModeSymbol\" id=\"0aI-pn-dxf\"/>\n                                                </connections>\n                                            </button>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g7F-sy-Fxi\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"276\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" title=\"Show server Message of the Day (MOTD)\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"BD5-Mg-W7N\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <connections>\n                                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisplayServerMessageOfTheDayOnConnect\" id=\"F0q-c1-PSH\"/>\n                                                </connections>\n                                            </button>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"ram-Ya-z5o\" firstAttribute=\"firstBaseline\" secondItem=\"ZLg-nc-ynI\" secondAttribute=\"firstBaseline\" id=\"7PK-wy-c1d\"/>\n                                    <constraint firstItem=\"ZIn-Pm-F4C\" firstAttribute=\"top\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"bottom\" constant=\"7\" id=\"7nA-TS-8XV\"/>\n                                    <constraint firstItem=\"3m7-iu-b8N\" firstAttribute=\"centerX\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"centerX\" id=\"CMN-1i-7RA\"/>\n                                    <constraint firstItem=\"fBp-jn-dhC\" firstAttribute=\"top\" secondItem=\"ZLg-nc-ynI\" secondAttribute=\"bottom\" constant=\"9\" id=\"EPm-EA-Ufp\"/>\n                                    <constraint firstItem=\"ZLg-nc-ynI\" firstAttribute=\"top\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"bottom\" constant=\"34\" id=\"NeM-u4-LC0\"/>\n                                    <constraint firstItem=\"gcs-0W-25e\" firstAttribute=\"top\" secondItem=\"3m7-iu-b8N\" secondAttribute=\"bottom\" constant=\"18\" id=\"Pkm-8A-clo\"/>\n                                    <constraint firstItem=\"VxK-V6-0nX\" firstAttribute=\"firstBaseline\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"firstBaseline\" id=\"Qof-o4-yHD\"/>\n                                    <constraint firstItem=\"fBp-jn-dhC\" firstAttribute=\"leading\" secondItem=\"ram-Ya-z5o\" secondAttribute=\"leading\" constant=\"5\" id=\"Vsf-xf-IPT\"/>\n                                    <constraint firstItem=\"ZLg-nc-ynI\" firstAttribute=\"trailing\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"trailing\" id=\"axF-S4-TXP\"/>\n                                    <constraint firstItem=\"ZLg-nc-ynI\" firstAttribute=\"leading\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"leading\" id=\"cKj-Re-nNZ\"/>\n                                    <constraint firstItem=\"3m7-iu-b8N\" firstAttribute=\"leading\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"leading\" constant=\"40\" id=\"cMe-Ia-MEP\"/>\n                                    <constraint firstItem=\"ram-Ya-z5o\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"leading\" constant=\"20\" id=\"fuu-An-m7v\"/>\n                                    <constraint firstItem=\"ZIn-Pm-F4C\" firstAttribute=\"leading\" secondItem=\"VxK-V6-0nX\" secondAttribute=\"leading\" constant=\"30\" id=\"gbk-9g-q8D\"/>\n                                    <constraint firstItem=\"Z2q-8o-VzU\" firstAttribute=\"top\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"top\" constant=\"30\" id=\"hnt-BU-U3B\"/>\n                                    <constraint firstItem=\"Z2q-8o-VzU\" firstAttribute=\"leading\" secondItem=\"VxK-V6-0nX\" secondAttribute=\"trailing\" constant=\"8\" id=\"j6M-0m-Nqy\"/>\n                                    <constraint firstItem=\"3m7-iu-b8N\" firstAttribute=\"top\" secondItem=\"fBp-jn-dhC\" secondAttribute=\"bottom\" constant=\"18\" id=\"oU3-NQ-jGK\"/>\n                                    <constraint firstItem=\"gcs-0W-25e\" firstAttribute=\"centerX\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"centerX\" id=\"qgb-Ne-VFw\"/>\n                                    <constraint firstItem=\"VxK-V6-0nX\" firstAttribute=\"leading\" secondItem=\"GFi-uq-h4X\" secondAttribute=\"leading\" constant=\"137\" id=\"r5J-Qv-q61\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"Z2q-8o-VzU\" secondAttribute=\"trailing\" constant=\"146\" id=\"s93-3P-3lM\"/>\n                                    <constraint firstItem=\"ram-Ya-z5o\" firstAttribute=\"trailing\" secondItem=\"VxK-V6-0nX\" secondAttribute=\"trailing\" id=\"xCe-Sv-yzs\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                    </tabViewItems>\n                </tabView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"lpz-77-UDw\" firstAttribute=\"top\" secondItem=\"oeR-nv-slx\" secondAttribute=\"top\" constant=\"16\" id=\"231-Af-s1D\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"lpz-77-UDw\" secondAttribute=\"bottom\" constant=\"20\" id=\"FAv-1K-i7Y\"/>\n                <constraint firstItem=\"lpz-77-UDw\" firstAttribute=\"leading\" secondItem=\"oeR-nv-slx\" secondAttribute=\"leading\" constant=\"20\" id=\"cnn-JT-VTe\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"lpz-77-UDw\" secondAttribute=\"trailing\" constant=\"20\" id=\"e3z-AQ-9NZ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"318.5\" y=\"-5050\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4zD-VW-F1h\" userLabel=\"Installed Addons\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"392\"/>\n            <subviews>\n                <scrollView focusRingType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" allowsMagnification=\"YES\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7ca-ja-B6d\">\n                    <rect key=\"frame\" x=\"100\" y=\"128\" width=\"470\" height=\"210\"/>\n                    <clipView key=\"contentView\" id=\"AXK-zU-57a\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"468\" height=\"208\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowSizeStyle=\"automatic\" viewBased=\"YES\" floatsGroupRows=\"NO\" id=\"rGf-Ih-C97\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"468\" height=\"208\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"addonCommand\" width=\"426\" minWidth=\"40\" maxWidth=\"1000\" id=\"GzW-ZW-4AC\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Name\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" alignment=\"left\" title=\"Text Cell\" id=\"Zew-yH-iHU\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Script Name\"/>\n                                        </textFieldCell>\n                                        <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"caseInsensitiveCompare:\" sortKey=\"string\"/>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\"/>\n                                        <prototypeCellViews>\n                                            <tableCellView id=\"5gM-WP-Vf6\">\n                                                <rect key=\"frame\" x=\"1\" y=\"1\" width=\"435\" height=\"17\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                <subviews>\n                                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mh1-TF-o7A\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"1\" width=\"435\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"gJi-dD-yjf\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                        <connections>\n                                                            <binding destination=\"5gM-WP-Vf6\" name=\"value\" keyPath=\"objectValue.string\" id=\"Jdj-h1-zqE\"/>\n                                                        </connections>\n                                                    </textField>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"mh1-TF-o7A\" firstAttribute=\"top\" secondItem=\"5gM-WP-Vf6\" secondAttribute=\"top\" id=\"5PS-2z-8JA\"/>\n                                                    <constraint firstItem=\"mh1-TF-o7A\" firstAttribute=\"leading\" secondItem=\"5gM-WP-Vf6\" secondAttribute=\"leading\" constant=\"2\" id=\"QT3-Lv-X1i\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"mh1-TF-o7A\" secondAttribute=\"trailing\" constant=\"2\" id=\"XQf-zU-HOV\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <outlet property=\"textField\" destination=\"mh1-TF-o7A\" id=\"LCs-QW-zoc\"/>\n                                                </connections>\n                                            </tableCellView>\n                                        </prototypeCellViews>\n                                    </tableColumn>\n                                </tableColumns>\n                                <accessibility description=\"Installed Addons\"/>\n                                <connections>\n                                    <binding destination=\"92m-WJ-gkY\" name=\"content\" keyPath=\"arrangedObjects\" id=\"asi-Bt-r0r\"/>\n                                    <binding destination=\"92m-WJ-gkY\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"asi-Bt-r0r\" id=\"9Ql-ju-OaA\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"210\" id=\"IQV-Mj-e0g\"/>\n                        <constraint firstAttribute=\"width\" constant=\"470\" id=\"YWA-Ad-aCT\"/>\n                    </constraints>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"Nce-bu-TzS\">\n                        <rect key=\"frame\" x=\"1\" y=\"193\" width=\"468\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"DYh-HY-NdA\">\n                        <rect key=\"frame\" x=\"454\" y=\"17\" width=\"15\" height=\"175\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ut7-9O-xlD\">\n                    <rect key=\"frame\" x=\"98\" y=\"346\" width=\"286\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"The following custom commands are available:\" id=\"KaT-z7-mCE\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pxa-Um-3pA\">\n                    <rect key=\"frame\" x=\"98\" y=\"68\" width=\"474\" height=\"48\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" id=\"pVP-3h-Oiy\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">The commands listed above are performed like any other: write a forward slash (/) followed by the name of the command plus any required arguments. Textual will perform the command and output the results accordingly.</string>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ehJ-Ot-jXi\">\n                    <rect key=\"frame\" x=\"199\" y=\"30\" width=\"272\" height=\"18\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UuX-nP-keM\">\n                            <rect key=\"frame\" x=\"-2\" y=\"2\" width=\"170\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Custom Addons Location:\" id=\"aKI-dl-dpt\">\n                                <font key=\"font\" metaFont=\"systemBold\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wqE-6p-1vl\">\n                            <rect key=\"frame\" x=\"174\" y=\"-1\" width=\"98\" height=\"19\"/>\n                            <buttonCell key=\"cell\" type=\"roundRect\" title=\"Open In Finder\" bezelStyle=\"roundedRect\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"T7i-UT-s8v\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                            </buttonCell>\n                            <accessibility description=\"Open Custom Addons Location in Finder\"/>\n                            <connections>\n                                <action selector=\"onOpenPathToScripts:\" target=\"-2\" id=\"0gm-KQ-Hgc\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"Ut7-9O-xlD\" firstAttribute=\"leading\" secondItem=\"7ca-ja-B6d\" secondAttribute=\"leading\" id=\"3N7-lW-FfT\"/>\n                <constraint firstItem=\"7ca-ja-B6d\" firstAttribute=\"top\" secondItem=\"Ut7-9O-xlD\" secondAttribute=\"bottom\" constant=\"8\" id=\"B6l-v0-ewu\"/>\n                <constraint firstItem=\"7ca-ja-B6d\" firstAttribute=\"centerX\" secondItem=\"4zD-VW-F1h\" secondAttribute=\"centerX\" id=\"EAh-Rn-c7U\"/>\n                <constraint firstItem=\"Ut7-9O-xlD\" firstAttribute=\"top\" secondItem=\"4zD-VW-F1h\" secondAttribute=\"top\" constant=\"30\" id=\"OCE-zU-oth\"/>\n                <constraint firstItem=\"Pxa-Um-3pA\" firstAttribute=\"top\" secondItem=\"7ca-ja-B6d\" secondAttribute=\"bottom\" constant=\"12\" id=\"OQT-dr-9re\"/>\n                <constraint firstItem=\"Pxa-Um-3pA\" firstAttribute=\"leading\" secondItem=\"7ca-ja-B6d\" secondAttribute=\"leading\" id=\"Uay-7B-AAE\"/>\n                <constraint firstItem=\"Ut7-9O-xlD\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"7ca-ja-B6d\" secondAttribute=\"trailing\" id=\"Vly-k3-vGM\"/>\n                <constraint firstItem=\"Pxa-Um-3pA\" firstAttribute=\"trailing\" secondItem=\"7ca-ja-B6d\" secondAttribute=\"trailing\" id=\"WEW-d8-ACK\"/>\n                <constraint firstItem=\"ehJ-Ot-jXi\" firstAttribute=\"centerX\" secondItem=\"4zD-VW-F1h\" secondAttribute=\"centerX\" id=\"aRr-mR-CAF\"/>\n                <constraint firstItem=\"ehJ-Ot-jXi\" firstAttribute=\"top\" secondItem=\"Pxa-Um-3pA\" secondAttribute=\"bottom\" constant=\"20\" id=\"iAC-1d-dcR\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ehJ-Ot-jXi\" secondAttribute=\"bottom\" constant=\"30\" id=\"ns4-kC-kJH\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-4592\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kTM-XW-Yb5\" userLabel=\"Channel Management\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"212\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jTo-pM-g6s\">\n                    <rect key=\"frame\" x=\"92\" y=\"93\" width=\"129\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Default Kick Reason:\" id=\"8Tj-Z2-BEA\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ttq-5L-YOn\">\n                    <rect key=\"frame\" x=\"92\" y=\"165\" width=\"142\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Hostmask Ban Format:\" id=\"1sH-tB-X5p\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"doe-fL-WAB\">\n                    <rect key=\"frame\" x=\"237\" y=\"158\" width=\"221\" height=\"25\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"nickname!username@address\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"qeE-pR-c4L\" id=\"wVg-8i-HY5\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                        <menu key=\"menu\" title=\"OtherViews\" id=\"UJE-9X-azF\">\n                            <items>\n                                <menuItem title=\"*!*@address\" id=\"pb2-SP-miv\"/>\n                                <menuItem title=\"*!ident@address\" id=\"Xfr-mW-SrH\"/>\n                                <menuItem title=\"nickname!*@address\" id=\"Gbn-5e-b0B\"/>\n                                <menuItem title=\"nickname!username@address\" state=\"on\" id=\"qeE-pR-c4L\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"Ttq-5L-YOn\" id=\"2d5-On-agN\"/>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedIndex\" keyPath=\"values.DefaultBanCommandHostmaskFormat\" id=\"QKp-yp-xBH\"/>\n                    </connections>\n                </popUpButton>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kWh-2T-Yta\">\n                    <rect key=\"frame\" x=\"104\" y=\"123\" width=\"446\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"When used in the context of a hostmask, an asterisk (*) represents a wildcard character that is matched by any possible value.\" id=\"lyl-DA-xkL\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Giv-s5-hR3\">\n                    <rect key=\"frame\" x=\"94\" y=\"30\" width=\"455\" height=\"55\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"55\" id=\"HQ1-fa-xj8\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"2aJ-p3-18o\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <connections>\n                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ChannelOperatorDefaultLocalization -&gt; Kick Reason\" id=\"bIe-Po-b7V\"/>\n                        </connections>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"jTo-pM-g6s\" id=\"vac-O1-F0z\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"doe-fL-WAB\" firstAttribute=\"leading\" secondItem=\"Ttq-5L-YOn\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"160-hY-ieL\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"Giv-s5-hR3\" secondAttribute=\"bottom\" constant=\"30\" id=\"8ba-ZW-i2X\"/>\n                <constraint firstItem=\"jTo-pM-g6s\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"Giv-s5-hR3\" secondAttribute=\"trailing\" id=\"CJ5-si-COV\"/>\n                <constraint firstItem=\"jTo-pM-g6s\" firstAttribute=\"top\" secondItem=\"kWh-2T-Yta\" secondAttribute=\"bottom\" constant=\"14\" id=\"Em4-ug-H7f\"/>\n                <constraint firstItem=\"Giv-s5-hR3\" firstAttribute=\"top\" secondItem=\"jTo-pM-g6s\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"P3g-sc-kQF\"/>\n                <constraint firstItem=\"Ttq-5L-YOn\" firstAttribute=\"firstBaseline\" secondItem=\"doe-fL-WAB\" secondAttribute=\"firstBaseline\" id=\"Wbb-Le-d8i\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"doe-fL-WAB\" secondAttribute=\"trailing\" constant=\"20\" id=\"X5p-B5-FYm\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"Giv-s5-hR3\" secondAttribute=\"trailing\" constant=\"121\" id=\"YHD-Ly-X1I\"/>\n                <constraint firstItem=\"doe-fL-WAB\" firstAttribute=\"top\" secondItem=\"kTM-XW-Yb5\" secondAttribute=\"top\" constant=\"30\" id=\"aN7-Hc-Hey\"/>\n                <constraint firstItem=\"Ttq-5L-YOn\" firstAttribute=\"leading\" secondItem=\"kTM-XW-Yb5\" secondAttribute=\"leading\" constant=\"94\" id=\"bGT-yy-DbW\"/>\n                <constraint firstItem=\"jTo-pM-g6s\" firstAttribute=\"leading\" secondItem=\"Giv-s5-hR3\" secondAttribute=\"leading\" id=\"fRE-mc-CJh\"/>\n                <constraint firstItem=\"kWh-2T-Yta\" firstAttribute=\"leading\" secondItem=\"Ttq-5L-YOn\" secondAttribute=\"leading\" constant=\"12\" id=\"r0c-Mo-sRz\"/>\n                <constraint firstItem=\"Giv-s5-hR3\" firstAttribute=\"leading\" secondItem=\"kTM-XW-Yb5\" secondAttribute=\"leading\" constant=\"94\" id=\"tXM-6x-DAf\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"kWh-2T-Yta\" secondAttribute=\"trailing\" constant=\"20\" id=\"uQZ-52-RXT\"/>\n                <constraint firstItem=\"kWh-2T-Yta\" firstAttribute=\"top\" secondItem=\"doe-fL-WAB\" secondAttribute=\"bottom\" constant=\"9\" id=\"wgl-Y2-eoa\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-4115\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"e8Q-5b-yYH\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"76\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ink-td-oFr\">\n                    <rect key=\"frame\" x=\"40\" y=\"29\" width=\"223\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable echo-message capability\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"k2j-qv-6ty\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.IRC -&gt; Enable echo-message Capability\" id=\"JWt-1e-abq\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"Ink-td-oFr\" secondAttribute=\"bottom\" constant=\"30\" id=\"0Ac-4O-f3E\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Ink-td-oFr\" secondAttribute=\"trailing\" constant=\"20\" id=\"8oo-XL-6zc\"/>\n                <constraint firstItem=\"Ink-td-oFr\" firstAttribute=\"top\" secondItem=\"e8Q-5b-yYH\" secondAttribute=\"top\" constant=\"30\" id=\"Rug-cD-ODk\"/>\n                <constraint firstItem=\"Ink-td-oFr\" firstAttribute=\"leading\" secondItem=\"e8Q-5b-yYH\" secondAttribute=\"leading\" constant=\"42\" id=\"Yvx-kI-Ikd\"/>\n            </constraints>\n            <string key=\"userLabel\">Compatibility\t</string>\n            <point key=\"canvasLocation\" x=\"318\" y=\"-3861\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1YF-k7-FrW\" userLabel=\"Command Scope\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"312\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zY5-8K-Mie\">\n                    <rect key=\"frame\" x=\"84\" y=\"122\" width=\"336\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Give focus to the destination of the /msg command\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"ekF-Cf-Mjw\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.FocusSelectionOnMessageCommandExecution\" id=\"O7w-61-9Do\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nlA-Ew-LSZ\">\n                    <rect key=\"frame\" x=\"40\" y=\"102\" width=\"590\" height=\"5\"/>\n                </box>\n                <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vT0-4B-zbA\">\n                    <rect key=\"frame\" x=\"40\" y=\"155\" width=\"590\" height=\"5\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xEg-Db-K0K\">\n                    <rect key=\"frame\" x=\"84\" y=\"70\" width=\"121\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Forward notices to:\" id=\"UgN-n4-JIQ\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"fillEqually\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IzG-w4-VXU\">\n                    <rect key=\"frame\" x=\"86\" y=\"176\" width=\"268\" height=\"106\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aVp-mc-vNk\">\n                            <rect key=\"frame\" x=\"-2\" y=\"89\" width=\"270\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"/amsg and /ame apply to all connections\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"G2J-m9-ooO\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ApplyCommandToAllConnections -&gt; amsg\" id=\"TB5-j1-Yxa\"/>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fg1-OG-7A7\">\n                            <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"218\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"/away applies to all connections\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"jGt-tN-qzV\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ApplyCommandToAllConnections -&gt; away\" id=\"TCq-6o-7SS\"/>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Y4Q-Ki-gfe\">\n                            <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"213\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"/nick applies to all connections\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"gih-NF-Noz\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ApplyCommandToAllConnections -&gt; nick\" id=\"pON-XZ-8rv\"/>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HZq-oo-s5C\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"231\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"/clearall applies to all connections\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"QcP-gl-hx4\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ApplyCommandToAllConnections -&gt; clearall\" id=\"bKs-W3-GMH\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"4\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NSe-gI-Nm7\">\n                    <rect key=\"frame\" x=\"211\" y=\"30\" width=\"131\" height=\"56\"/>\n                    <subviews>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fsx-cd-pY6\">\n                            <rect key=\"frame\" x=\"-2\" y=\"39\" width=\"119\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"Server Console\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"cCE-T0-zar\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"onChangedForwardNoticeTo:\" target=\"-2\" id=\"yYL-au-VTX\"/>\n                            </connections>\n                        </button>\n                        <button tag=\"1\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IcT-S0-dsA\">\n                            <rect key=\"frame\" x=\"-2\" y=\"19\" width=\"133\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"Selected Channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"isT-C5-ie1\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"onChangedForwardNoticeTo:\" target=\"-2\" id=\"AJG-j9-QYI\"/>\n                            </connections>\n                        </button>\n                        <button tag=\"2\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uum-Jf-eoo\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"126\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"Private Message\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"EZN-9J-FUP\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"onChangedForwardNoticeTo:\" target=\"-2\" id=\"SOt-2E-iuy\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"NSe-gI-Nm7\" secondAttribute=\"bottom\" constant=\"30\" id=\"1dN-lF-kaF\"/>\n                <constraint firstItem=\"NSe-gI-Nm7\" firstAttribute=\"top\" secondItem=\"nlA-Ew-LSZ\" secondAttribute=\"bottom\" constant=\"18\" id=\"9av-VF-gTL\"/>\n                <constraint firstItem=\"xEg-Db-K0K\" firstAttribute=\"leading\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"leading\" constant=\"86\" id=\"AGv-v2-P6L\"/>\n                <constraint firstItem=\"xEg-Db-K0K\" firstAttribute=\"firstBaseline\" secondItem=\"Fsx-cd-pY6\" secondAttribute=\"firstBaseline\" id=\"H41-vB-ut3\"/>\n                <constraint firstItem=\"vT0-4B-zbA\" firstAttribute=\"top\" secondItem=\"IzG-w4-VXU\" secondAttribute=\"bottom\" constant=\"18\" id=\"QAA-Pn-lmw\"/>\n                <constraint firstItem=\"nlA-Ew-LSZ\" firstAttribute=\"leading\" secondItem=\"vT0-4B-zbA\" secondAttribute=\"leading\" id=\"RgL-aY-fFR\"/>\n                <constraint firstItem=\"nlA-Ew-LSZ\" firstAttribute=\"top\" secondItem=\"zY5-8K-Mie\" secondAttribute=\"bottom\" constant=\"18\" id=\"UeX-tm-lpF\"/>\n                <constraint firstItem=\"vT0-4B-zbA\" firstAttribute=\"centerX\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"centerX\" id=\"YjD-wK-T5a\"/>\n                <constraint firstItem=\"IzG-w4-VXU\" firstAttribute=\"top\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"top\" constant=\"30\" id=\"jEP-hD-E8s\"/>\n                <constraint firstItem=\"zY5-8K-Mie\" firstAttribute=\"leading\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"leading\" constant=\"86\" id=\"lBH-G6-Xgm\"/>\n                <constraint firstItem=\"vT0-4B-zbA\" firstAttribute=\"leading\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"leading\" constant=\"40\" id=\"o7G-Ls-gg0\"/>\n                <constraint firstItem=\"NSe-gI-Nm7\" firstAttribute=\"leading\" secondItem=\"xEg-Db-K0K\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"qOK-eG-qwn\"/>\n                <constraint firstItem=\"zY5-8K-Mie\" firstAttribute=\"top\" secondItem=\"vT0-4B-zbA\" secondAttribute=\"bottom\" constant=\"18\" id=\"qlS-6I-6ce\"/>\n                <constraint firstItem=\"IzG-w4-VXU\" firstAttribute=\"leading\" secondItem=\"1YF-k7-FrW\" secondAttribute=\"leading\" constant=\"86\" id=\"vh9-lM-yjf\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"zY5-8K-Mie\" secondAttribute=\"trailing\" constant=\"20\" id=\"wGo-fC-jSY\"/>\n                <constraint firstItem=\"vT0-4B-zbA\" firstAttribute=\"trailing\" secondItem=\"nlA-Ew-LSZ\" secondAttribute=\"trailing\" id=\"xBF-TR-lYT\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"318\" y=\"-3584\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"n4A-Pk-quE\" userLabel=\"Flood Control\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"434\"/>\n            <subviews>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cDy-R9-0Ub\">\n                    <rect key=\"frame\" x=\"42\" y=\"280\" width=\"250\" height=\"54\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vyq-Uz-h3Q\">\n                            <rect key=\"frame\" x=\"-2\" y=\"38\" width=\"187\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Delay Between Channel Joins:\" id=\"LlJ-il-Put\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"751\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O9S-wJ-0VX\">\n                            <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"241\" height=\"30\"/>\n                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"How long, in seconds, to wait in-between each join.\" id=\"SKh-K9-i5D\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"V7m-3A-nss\">\n                    <rect key=\"frame\" x=\"281\" y=\"50\" width=\"109\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Current Value: 100\" id=\"J0v-lX-lSI\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"displayPatternValue1\" keyPath=\"values.TrackUserAwayStatusMaximumChannelSize\" id=\"9bt-Ac-FRt\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSDisplayPattern\">Current Value: %{value1}@</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </textField>\n                <stackView distribution=\"equalSpacing\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"6\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wIq-2E-v60\">\n                    <rect key=\"frame\" x=\"77\" y=\"30\" width=\"516\" height=\"16\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ovt-cD-DOK\">\n                            <rect key=\"frame\" x=\"-2\" y=\"1\" width=\"65\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"0 (disable)\" id=\"yQ3-ZF-7V3\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tfY-TP-YZN\">\n                            <rect key=\"frame\" x=\"65\" y=\"-2\" width=\"414\" height=\"20\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" constant=\"410\" id=\"HTg-8L-R5e\"/>\n                            </constraints>\n                            <sliderCell key=\"cell\" controlSize=\"small\" alignment=\"left\" maxValue=\"2000\" doubleValue=\"960\" tickMarkPosition=\"below\" numberOfTickMarks=\"51\" allowsTickMarkValuesOnly=\"YES\" sliderType=\"linear\" id=\"JHI-LK-miQ\"/>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"wcy-2K-Z0C\" id=\"cW8-Bg-bLX\"/>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.TrackUserAwayStatusMaximumChannelSize\" id=\"R7b-3V-IUf\"/>\n                            </connections>\n                        </slider>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xYi-8b-aQD\">\n                            <rect key=\"frame\" x=\"481\" y=\"1\" width=\"37\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"2,000\" id=\"lYL-2U-2IR\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PPm-GB-sT3\">\n                    <rect key=\"frame\" x=\"42\" y=\"350\" width=\"250\" height=\"54\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9we-bb-EEs\">\n                            <rect key=\"frame\" x=\"-2\" y=\"38\" width=\"174\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Delay Before Channel Joins:\" id=\"uFV-wB-bh3\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"751\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WkU-7v-VLt\">\n                            <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"254\" height=\"30\"/>\n                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"How long, in seconds, to wait before joining channels after identifying.\" id=\"Nn9-kA-OjY\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VWV-XI-SXi\">\n                    <rect key=\"frame\" x=\"104\" y=\"81\" width=\"462\" height=\"99\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wcy-2K-Z0C\">\n                            <rect key=\"frame\" x=\"-2\" y=\"83\" width=\"250\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"WHO Command Maximum Channel Size:\" id=\"xkB-rD-fPk\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OVq-cn-ftD\">\n                            <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"466\" height=\"75\"/>\n                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"juM-7X-6WQ\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <string key=\"title\">Textual must periodically poll the channels that you are in to find out when the away status of each user changes. This preference defines the maximum number of users a channel can contain before the channel is skipped over.\n\nA lower value is always better especially when in a large number of channels.</string>\n                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GdS-Lf-0FM\">\n                    <rect key=\"frame\" x=\"40\" y=\"196\" width=\"590\" height=\"5\"/>\n                </box>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"centerX\" spacing=\"4\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yo6-0a-8O6\">\n                    <rect key=\"frame\" x=\"310\" y=\"290\" width=\"318\" height=\"35\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yHF-Mm-7mA\">\n                            <rect key=\"frame\" x=\"105\" y=\"20\" width=\"109\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Current Value: 100\" id=\"Upf-sb-9aG\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"displayPatternValue1\" keyPath=\"values.AutojoinDelayBetweenChannelJoins\" id=\"hhw-Qb-VNW\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSDisplayPattern\">Current Value: %{value1}@ seconds</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </textField>\n                        <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"6\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8gi-yj-GXQ\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"318\" height=\"16\"/>\n                            <subviews>\n                                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"boi-EW-JP6\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"22\" height=\"15\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"0.5\" id=\"0lT-WD-kfS\">\n                                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                                <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6vz-or-deD\">\n                                    <rect key=\"frame\" x=\"22\" y=\"-2\" width=\"268\" height=\"20\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"width\" constant=\"264\" id=\"i7h-B6-Xno\"/>\n                                    </constraints>\n                                    <sliderCell key=\"cell\" controlSize=\"small\" state=\"on\" alignment=\"left\" minValue=\"0.5\" maxValue=\"10\" doubleValue=\"5\" tickMarkPosition=\"below\" numberOfTickMarks=\"20\" allowsTickMarkValuesOnly=\"YES\" sliderType=\"linear\" id=\"dfY-Hj-2Rl\"/>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"wcy-2K-Z0C\" id=\"Uzf-OY-O1N\"/>\n                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutojoinDelayBetweenChannelJoins\" id=\"DPo-VB-P1C\"/>\n                                    </connections>\n                                </slider>\n                                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ceo-Jx-hPr\">\n                                    <rect key=\"frame\" x=\"292\" y=\"0.0\" width=\"28\" height=\"15\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"10.0\" id=\"ItF-pC-wlw\">\n                                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </subviews>\n                            <visibilityPriorities>\n                                <integer value=\"1000\"/>\n                                <integer value=\"1000\"/>\n                                <integer value=\"1000\"/>\n                            </visibilityPriorities>\n                            <customSpacing>\n                                <real value=\"3.4028234663852886e+38\"/>\n                                <real value=\"3.4028234663852886e+38\"/>\n                                <real value=\"3.4028234663852886e+38\"/>\n                            </customSpacing>\n                        </stackView>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"centerX\" spacing=\"4\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XZO-OK-ByC\">\n                    <rect key=\"frame\" x=\"310\" y=\"360\" width=\"318\" height=\"35\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"N6h-L8-c0i\">\n                            <rect key=\"frame\" x=\"105\" y=\"20\" width=\"109\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Current Value: 100\" id=\"ZFz-7f-mH4\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"displayPatternValue1\" keyPath=\"values.AutojoinDelayAfterIdentification\" id=\"huh-Bf-In7\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSDisplayPattern\">Current Value: %{value1}@ seconds</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </textField>\n                        <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"6\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ulc-ga-rFe\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"318\" height=\"16\"/>\n                            <subviews>\n                                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nUX-Py-gGJ\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"22\" height=\"15\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"0.0\" id=\"eFu-Az-3oV\">\n                                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                                <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oaQ-mE-jls\">\n                                    <rect key=\"frame\" x=\"22\" y=\"-2\" width=\"268\" height=\"20\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"width\" constant=\"264\" id=\"a7M-ba-o58\"/>\n                                    </constraints>\n                                    <sliderCell key=\"cell\" controlSize=\"small\" state=\"on\" alignment=\"left\" maxValue=\"10\" doubleValue=\"5\" tickMarkPosition=\"below\" numberOfTickMarks=\"21\" allowsTickMarkValuesOnly=\"YES\" sliderType=\"linear\" id=\"j0d-E3-tre\"/>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"wcy-2K-Z0C\" id=\"TJN-S2-CcI\"/>\n                                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutojoinDelayAfterIdentification\" id=\"Hz7-NQ-eiz\"/>\n                                    </connections>\n                                </slider>\n                                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DNr-fg-Zx1\">\n                                    <rect key=\"frame\" x=\"292\" y=\"0.0\" width=\"28\" height=\"15\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"10.0\" id=\"RuE-BO-Pjb\">\n                                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </subviews>\n                            <visibilityPriorities>\n                                <integer value=\"1000\"/>\n                                <integer value=\"1000\"/>\n                                <integer value=\"1000\"/>\n                            </visibilityPriorities>\n                            <customSpacing>\n                                <real value=\"3.4028234663852886e+38\"/>\n                                <real value=\"3.4028234663852886e+38\"/>\n                                <real value=\"3.4028234663852886e+38\"/>\n                            </customSpacing>\n                        </stackView>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hqK-uc-gyL\">\n                    <rect key=\"frame\" x=\"40\" y=\"217\" width=\"590\" height=\"45\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"Zer-Bw-gRh\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <string key=\"title\">Joining too many channels at once may be detected as an attack by some IRC networks. You could be disconnected or banned as a result. It is recommended to use a moderate delay (~2.5 seconds) for both timers when joining a large number of channels. </string>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"Yo6-0a-8O6\" firstAttribute=\"centerY\" secondItem=\"cDy-R9-0Ub\" secondAttribute=\"centerY\" id=\"018-zi-Mcd\"/>\n                <constraint firstItem=\"GdS-Lf-0FM\" firstAttribute=\"centerX\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"centerX\" id=\"CXh-P8-ubJ\"/>\n                <constraint firstItem=\"GdS-Lf-0FM\" firstAttribute=\"leading\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"leading\" constant=\"40\" id=\"DBh-uu-2Y1\"/>\n                <constraint firstItem=\"cDy-R9-0Ub\" firstAttribute=\"leading\" secondItem=\"PPm-GB-sT3\" secondAttribute=\"leading\" id=\"E3f-0K-QDy\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"XZO-OK-ByC\" secondAttribute=\"trailing\" constant=\"42\" id=\"FyA-qo-tiB\"/>\n                <constraint firstItem=\"XZO-OK-ByC\" firstAttribute=\"centerY\" secondItem=\"PPm-GB-sT3\" secondAttribute=\"centerY\" id=\"HZQ-p0-4oA\"/>\n                <constraint firstItem=\"wIq-2E-v60\" firstAttribute=\"centerX\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"centerX\" id=\"J6H-TD-Zxc\"/>\n                <constraint firstItem=\"V7m-3A-nss\" firstAttribute=\"top\" secondItem=\"VWV-XI-SXi\" secondAttribute=\"bottom\" constant=\"16\" id=\"Kdo-44-ioD\"/>\n                <constraint firstItem=\"hqK-uc-gyL\" firstAttribute=\"top\" secondItem=\"O9S-wJ-0VX\" secondAttribute=\"bottom\" constant=\"18\" id=\"Kxt-8e-9gc\"/>\n                <constraint firstItem=\"hqK-uc-gyL\" firstAttribute=\"trailing\" secondItem=\"Yo6-0a-8O6\" secondAttribute=\"trailing\" id=\"LUG-DR-qOV\"/>\n                <constraint firstItem=\"Yo6-0a-8O6\" firstAttribute=\"leading\" secondItem=\"XZO-OK-ByC\" secondAttribute=\"leading\" id=\"MM6-hf-ZAp\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"wIq-2E-v60\" secondAttribute=\"bottom\" constant=\"30\" id=\"Sac-SE-EkG\"/>\n                <constraint firstItem=\"tfY-TP-YZN\" firstAttribute=\"top\" secondItem=\"V7m-3A-nss\" secondAttribute=\"bottom\" constant=\"4\" id=\"W4X-lr-9kg\"/>\n                <constraint firstItem=\"OVq-cn-ftD\" firstAttribute=\"centerX\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"centerX\" id=\"Xgq-lP-HbH\"/>\n                <constraint firstItem=\"PPm-GB-sT3\" firstAttribute=\"leading\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"leading\" constant=\"42\" id=\"Y7K-0f-JyZ\"/>\n                <constraint firstItem=\"PPm-GB-sT3\" firstAttribute=\"top\" secondItem=\"n4A-Pk-quE\" secondAttribute=\"top\" constant=\"30\" id=\"Zd7-GL-J2I\"/>\n                <constraint firstItem=\"cDy-R9-0Ub\" firstAttribute=\"trailing\" secondItem=\"PPm-GB-sT3\" secondAttribute=\"trailing\" id=\"hZS-zD-Trf\"/>\n                <constraint firstItem=\"V7m-3A-nss\" firstAttribute=\"centerX\" secondItem=\"wIq-2E-v60\" secondAttribute=\"centerX\" id=\"iFe-8D-wui\"/>\n                <constraint firstItem=\"hqK-uc-gyL\" firstAttribute=\"leading\" secondItem=\"cDy-R9-0Ub\" secondAttribute=\"leading\" id=\"ou7-pN-dJc\"/>\n                <constraint firstItem=\"XZO-OK-ByC\" firstAttribute=\"leading\" secondItem=\"PPm-GB-sT3\" secondAttribute=\"trailing\" constant=\"18\" id=\"pe1-N9-l61\"/>\n                <constraint firstItem=\"GdS-Lf-0FM\" firstAttribute=\"top\" secondItem=\"hqK-uc-gyL\" secondAttribute=\"bottom\" constant=\"18\" id=\"plR-Te-onZ\"/>\n                <constraint firstItem=\"VWV-XI-SXi\" firstAttribute=\"top\" secondItem=\"GdS-Lf-0FM\" secondAttribute=\"bottom\" constant=\"18\" id=\"sR7-bH-u1p\"/>\n                <constraint firstItem=\"Yo6-0a-8O6\" firstAttribute=\"trailing\" secondItem=\"XZO-OK-ByC\" secondAttribute=\"trailing\" id=\"yTw-yV-nLW\"/>\n                <constraint firstItem=\"cDy-R9-0Ub\" firstAttribute=\"top\" secondItem=\"PPm-GB-sT3\" secondAttribute=\"bottom\" constant=\"16\" id=\"zZy-v9-3eL\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-3113\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KpN-mD-prv\" userLabel=\"Incoming Data\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"259\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qfG-DF-6ev\">\n                    <rect key=\"frame\" x=\"151\" y=\"212\" width=\"359\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Automatically reply to Client-to-Client (CTCP) requests\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"MT3-bO-x65\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.ReplyUnignoredExternalCTCPRequests\" id=\"F3h-Qb-l6T\"/>\n                    </connections>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uSb-WR-Mph\">\n                    <rect key=\"frame\" x=\"151\" y=\"182\" width=\"243\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Automatically ignore highlight spam\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"9iB-R9-pX3\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutomaticallyDetectHighlightSpam\" id=\"Frv-8s-0eY\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nyl-Dm-Tsm\">\n                    <rect key=\"frame\" x=\"169\" y=\"145\" width=\"350\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Do not notify you of a highlight if 75% of a message consists of ten or more nicknames.\" id=\"34J-sn-YZe\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"uSb-WR-Mph\" id=\"9gI-fO-CqF\"/>\n                    </connections>\n                </textField>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RP8-vi-u0X\">\n                    <rect key=\"frame\" x=\"151\" y=\"67\" width=\"293\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Replace Combining Diacritical Marks with �\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"nGd-LX-rxu\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.AutomaticallyFilterUnicodeTextSpam\" id=\"N77-BH-TuM\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gPo-O3-udJ\">\n                    <rect key=\"frame\" x=\"169\" y=\"30\" width=\"337\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"These characters are often combined to form “Zalgo text”, which is used by some users to disrupt chatrooms.\" id=\"1Vl-Us-7KM\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"uSb-WR-Mph\" id=\"fxn-N4-SjE\"/>\n                    </connections>\n                </textField>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"McB-sS-fgg\">\n                    <rect key=\"frame\" x=\"151\" y=\"118\" width=\"296\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Remove formatting from incoming messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"TQw-6D-bCG\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.RemoveIRCTextFormatting\" id=\"djG-dx-r2c\"/>\n                    </connections>\n                </button>\n                <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mqa-tv-bpf\">\n                    <rect key=\"frame\" x=\"167\" y=\"94\" width=\"350\" height=\"17\"/>\n                    <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"MeX-O6-c8G\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"350\" height=\"17\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" findStyle=\"panel\" allowsNonContiguousLayout=\"YES\" spellingCorrection=\"YES\" id=\"ijO-xj-OPG\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"350\" height=\"17\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <size key=\"minSize\" width=\"350\" height=\"17\"/>\n                                <size key=\"maxSize\" width=\"6332\" height=\"10000000\"/>\n                                <attributedString key=\"textStorage\">\n                                    <fragment content=\"Removes formatting such as \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"bold\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"systemBold\" size=\"12\"/>\n                                            <font key=\"NSOriginalFont\" metaFont=\"smallSystemBold\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\", \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"colors\">\n                                        <attributes>\n                                            <color key=\"NSColor\" red=\"0.0095936315713639475\" green=\"0.59505010166779315\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\", \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"underline\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                            <integer key=\"NSUnderline\" value=\"1\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\", etc.\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"cellTitle\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\"/>\n                                        </attributes>\n                                    </fragment>\n                                </attributedString>\n                                <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"17\" id=\"tL8-dI-01t\"/>\n                        <constraint firstAttribute=\"width\" constant=\"350\" id=\"zjM-DK-6jT\"/>\n                    </constraints>\n                    <edgeInsets key=\"contentInsets\" left=\"0.0\" right=\"0.0\" top=\"0.0\" bottom=\"0.0\"/>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"xt0-iE-zr2\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"fk4-zf-lYK\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"16\" height=\"17\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"McB-sS-fgg\" firstAttribute=\"leading\" secondItem=\"uSb-WR-Mph\" secondAttribute=\"leading\" id=\"1x2-HM-kEI\"/>\n                <constraint firstItem=\"gPo-O3-udJ\" firstAttribute=\"top\" secondItem=\"RP8-vi-u0X\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"9cB-sH-O46\"/>\n                <constraint firstItem=\"RP8-vi-u0X\" firstAttribute=\"top\" secondItem=\"ijO-xj-OPG\" secondAttribute=\"bottom\" constant=\"10\" id=\"AlU-Yd-gwf\"/>\n                <constraint firstItem=\"McB-sS-fgg\" firstAttribute=\"top\" secondItem=\"nyl-Dm-Tsm\" secondAttribute=\"bottom\" constant=\"10\" id=\"Cec-nC-0GV\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"uSb-WR-Mph\" secondAttribute=\"trailing\" constant=\"20\" id=\"DRH-Qr-ZKi\"/>\n                <constraint firstItem=\"nyl-Dm-Tsm\" firstAttribute=\"top\" secondItem=\"uSb-WR-Mph\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"Dwk-WK-1Ly\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"gPo-O3-udJ\" secondAttribute=\"trailing\" constant=\"20\" id=\"Fet-iz-KBi\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"gPo-O3-udJ\" secondAttribute=\"bottom\" constant=\"30\" id=\"GhK-Mq-yai\"/>\n                <constraint firstItem=\"mqa-tv-bpf\" firstAttribute=\"leading\" secondItem=\"McB-sS-fgg\" secondAttribute=\"leading\" constant=\"14\" id=\"LK5-Vm-NyA\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"nyl-Dm-Tsm\" secondAttribute=\"trailing\" constant=\"20\" id=\"M20-XN-OzF\"/>\n                <constraint firstItem=\"RP8-vi-u0X\" firstAttribute=\"leading\" secondItem=\"McB-sS-fgg\" secondAttribute=\"leading\" id=\"VKg-BW-Qhc\"/>\n                <constraint firstItem=\"gPo-O3-udJ\" firstAttribute=\"leading\" secondItem=\"RP8-vi-u0X\" secondAttribute=\"leading\" constant=\"18\" id=\"ZSy-lq-aUu\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"McB-sS-fgg\" secondAttribute=\"trailing\" constant=\"20\" id=\"aBg-id-Ck2\"/>\n                <constraint firstItem=\"uSb-WR-Mph\" firstAttribute=\"top\" secondItem=\"qfG-DF-6ev\" secondAttribute=\"bottom\" constant=\"14\" id=\"awP-qH-37v\"/>\n                <constraint firstItem=\"qfG-DF-6ev\" firstAttribute=\"top\" secondItem=\"KpN-mD-prv\" secondAttribute=\"top\" constant=\"30\" id=\"hlP-eP-8Eb\"/>\n                <constraint firstItem=\"uSb-WR-Mph\" firstAttribute=\"leading\" secondItem=\"qfG-DF-6ev\" secondAttribute=\"leading\" id=\"lc3-td-PS8\"/>\n                <constraint firstItem=\"nyl-Dm-Tsm\" firstAttribute=\"leading\" secondItem=\"uSb-WR-Mph\" secondAttribute=\"leading\" constant=\"18\" id=\"oFi-Xd-wUB\"/>\n                <constraint firstItem=\"qfG-DF-6ev\" firstAttribute=\"leading\" secondItem=\"KpN-mD-prv\" secondAttribute=\"leading\" constant=\"153\" id=\"rP5-8S-uRt\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"RP8-vi-u0X\" secondAttribute=\"trailing\" constant=\"20\" id=\"t00-Fc-yZC\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"mqa-tv-bpf\" secondAttribute=\"trailing\" constant=\"20\" id=\"uBb-C4-Bb7\"/>\n                <constraint firstItem=\"mqa-tv-bpf\" firstAttribute=\"top\" secondItem=\"McB-sS-fgg\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"vP7-iz-2mN\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"qfG-DF-6ev\" secondAttribute=\"trailing\" constant=\"20\" id=\"xZh-Qx-lGJ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-2176\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4pD-W0-ghZ\" userLabel=\"File Transfers\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"381\"/>\n            <subviews>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"boQ-fB-7JU\">\n                    <rect key=\"frame\" x=\"89\" y=\"206\" width=\"492\" height=\"88\"/>\n                    <rows>\n                        <gridRow id=\"ZQK-oQ-JYt\"/>\n                        <gridRow id=\"z65-ho-3y5\"/>\n                        <gridRow id=\"ua1-BC-ZVo\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"trailing\" id=\"Bus-Va-tRO\"/>\n                        <gridColumn xPlacement=\"leading\" id=\"BWk-SA-z5h\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"ZQK-oQ-JYt\" column=\"Bus-Va-tRO\" id=\"Fdy-g2-p9G\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AOa-Oj-4Fg\">\n                                <rect key=\"frame\" x=\"-2\" y=\"71\" width=\"184\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"IP Address detection method:\" id=\"VBT-UA-wAp\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"ZQK-oQ-JYt\" column=\"BWk-SA-z5h\" id=\"V9f-l1-Uxw\">\n                            <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Kgc-ku-XGt\">\n                                <rect key=\"frame\" x=\"185\" y=\"64\" width=\"311\" height=\"25\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" title=\"Ask router with no fallback\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"3\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"PpR-MQ-ujy\" id=\"eNz-BX-xFG\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                    <menu key=\"menu\" title=\"OtherViews\" id=\"faJ-I4-ysS\">\n                                        <items>\n                                            <menuItem title=\"Ask router with no fallback\" state=\"on\" tag=\"3\" id=\"PpR-MQ-ujy\"/>\n                                            <menuItem title=\"Ask router with myip.codeux.com as fallback\" tag=\"1\" id=\"C0d-vg-gP1\"/>\n                                            <menuItem title=\"Ask router with 3rd-party website as fallback\" tag=\"4\" id=\"x7k-y5-Qhz\"/>\n                                            <menuItem title=\"Manually Enter Address\" tag=\"2\" id=\"Pp5-Ci-F1D\"/>\n                                        </items>\n                                    </menu>\n                                </popUpButtonCell>\n                                <accessibility description=\"IP Address Detection Method\"/>\n                                <connections>\n                                    <action selector=\"onFileTransferIPAddressDetectionMethodChanged:\" target=\"-2\" id=\"ajo-mq-IKh\"/>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.File Transfers -&gt; File Transfer IP Address Detection Method\" id=\"319-Hu-T0p\"/>\n                                </connections>\n                            </popUpButton>\n                        </gridCell>\n                        <gridCell row=\"z65-ho-3y5\" column=\"Bus-Va-tRO\" id=\"0Sz-vf-13a\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"751\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"T6Y-nV-U2L\">\n                                <rect key=\"frame\" x=\"3\" y=\"38\" width=\"179\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Manually entered IP address:\" id=\"CJm-Pw-2rG\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"z65-ho-3y5\" column=\"BWk-SA-z5h\" id=\"2rJ-yt-6aW\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gsf-QD-Vkr\">\n                                <rect key=\"frame\" x=\"188\" y=\"34\" width=\"100\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"100\" id=\"8eS-JZ-aSu\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"jWV-vr-kqC\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"127.0.0.1\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"26x-nD-BMT\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <accessibility description=\"Manually Specified IP Address\"/>\n                                <connections>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.File Transfers -&gt; File Transfer Manually Entered IP Address\" id=\"kE8-pr-Cxw\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"ua1-BC-ZVo\" column=\"Bus-Va-tRO\" id=\"lSh-ZL-d5e\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wph-Lj-E2b\">\n                                <rect key=\"frame\" x=\"35\" y=\"4\" width=\"147\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"File transfer port range:\" id=\"Pak-RG-PFU\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"ua1-BC-ZVo\" column=\"BWk-SA-z5h\" id=\"BBG-jh-d7u\">\n                            <stackView key=\"contentView\" distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"atp-n5-Eep\">\n                                <rect key=\"frame\" x=\"188\" y=\"0.0\" width=\"149\" height=\"22\"/>\n                                <subviews>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"B1H-Gt-xIn\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"J0n-Qj-BOW\"/>\n                                            <constraint firstAttribute=\"width\" constant=\"60\" id=\"k9S-Q2-PaN\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"1096\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"BKU-eY-ALL\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <accessibility description=\"File Transfer Port Range First Port\"/>\n                                        <connections>\n                                            <binding destination=\"-2\" name=\"value\" keyPath=\"fileTransferPortRangeStart\" id=\"qeb-cL-TzD\">\n                                                <dictionary key=\"options\">\n                                                    <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                </dictionary>\n                                            </binding>\n                                        </connections>\n                                    </textField>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zgz-mh-zlj\">\n                                        <rect key=\"frame\" x=\"66\" y=\"4\" width=\"17\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"to\" id=\"49T-fc-D6u\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sqG-aL-jV2\">\n                                        <rect key=\"frame\" x=\"89\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"60\" id=\"82Y-PK-Ffs\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"us8-3i-Xk4\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"1115\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"sbA-lo-cb0\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <accessibility description=\"File Transfer Port Range Last Port\"/>\n                                        <connections>\n                                            <binding destination=\"-2\" name=\"value\" keyPath=\"fileTransferPortRangeEnd\" id=\"TJH-DP-boK\">\n                                                <dictionary key=\"options\">\n                                                    <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                </dictionary>\n                                            </binding>\n                                        </connections>\n                                    </textField>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Wuk-ii-Ge1\">\n                    <rect key=\"frame\" x=\"96\" y=\"113\" width=\"320\" height=\"28\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"You will be asked where to save downloaded files each time you start a file transfer if a destination is not configured.\" id=\"3k5-n4-vrU\">\n                        <font key=\"font\" metaFont=\"smallSystem\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c99-82-eTv\">\n                    <rect key=\"frame\" x=\"96\" y=\"152\" width=\"175\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Download files to the folder:\" id=\"8Zx-Jz-9wf\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wNd-qD-qDv\">\n                    <rect key=\"frame\" x=\"274\" y=\"145\" width=\"160\" height=\"25\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"nIO-8c-7R3\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                        <menu key=\"menu\" title=\"OtherViews\" id=\"fHr-wS-2L4\">\n                            <items>\n                                <menuItem id=\"98I-Xn-9UD\"/>\n                                <menuItem isSeparatorItem=\"YES\" id=\"RhQ-J7-LF5\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                                </menuItem>\n                                <menuItem title=\"Select Destination…\" tag=\"2\" id=\"PSl-Ru-20E\"/>\n                                <menuItem title=\"Clear Destination\" tag=\"3\" id=\"p10-Iz-DI6\">\n                                    <connections>\n                                        <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.File Transfers -&gt; File Transfer Download Folder Bookmark\" id=\"akm-zv-tn0\">\n                                            <dictionary key=\"options\">\n                                                <string key=\"NSValueTransformerName\">NSIsNotNil</string>\n                                            </dictionary>\n                                        </binding>\n                                    </connections>\n                                </menuItem>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <accessibility description=\"File Transfer Download Destination Folder\"/>\n                    <connections>\n                        <action selector=\"onFileTransferDownloadDestinationFolderChanged:\" target=\"-2\" id=\"9aO-P4-aVP\"/>\n                    </connections>\n                </popUpButton>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PcW-EO-frL\">\n                    <rect key=\"frame\" x=\"37\" y=\"334\" width=\"234\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"When file transfer request is received:\" id=\"ODe-np-HQz\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vGr-Fx-7Yk\">\n                    <rect key=\"frame\" x=\"274\" y=\"327\" width=\"185\" height=\"25\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Automatically Download\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"3\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"dNd-oi-z2o\" id=\"QsY-G8-09D\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                        <menu key=\"menu\" title=\"OtherViews\" id=\"4hq-nK-sNm\">\n                            <items>\n                                <menuItem title=\"Ignore\" tag=\"1\" id=\"Lc7-g8-RuB\"/>\n                                <menuItem title=\"Open Dialog\" tag=\"2\" id=\"Ab8-sW-zjf\"/>\n                                <menuItem title=\"Automatically Download\" state=\"on\" tag=\"3\" id=\"dNd-oi-z2o\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <accessibility description=\"Action to Perform when File Transfer Request is Received\"/>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.File Transfers -&gt; File Transfer Request Reply Action\" id=\"O4f-48-hv4\"/>\n                    </connections>\n                </popUpButton>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"r9F-t2-uVD\">\n                    <rect key=\"frame\" x=\"40\" y=\"310\" width=\"590\" height=\"5\"/>\n                </box>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mhg-Fu-3s0\">\n                    <rect key=\"frame\" x=\"40\" y=\"185\" width=\"590\" height=\"5\"/>\n                </box>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uhz-aJ-pvT\">\n                    <rect key=\"frame\" x=\"40\" y=\"92\" width=\"590\" height=\"5\"/>\n                </box>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xxb-V7-Rr3\">\n                    <rect key=\"frame\" x=\"157\" y=\"30\" width=\"357\" height=\"46\"/>\n                    <subviews>\n                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ojQ-wC-ucw\">\n                            <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"236\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Send passive file transfer requests\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"VZZ-dp-aIT\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.File Transfers -&gt; File Transfer Requests Use Reverse DCC\" id=\"buO-pD-sf8\"/>\n                            </connections>\n                        </button>\n                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6qx-4n-aFc\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"359\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Do not allow Mac to go to sleep while transferring a file\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"n04-8I-DlI\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.File Transfers -&gt; Idle System Sleep Prevented During File Transfer\" id=\"EEl-2l-Ekm\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"xxb-V7-Rr3\" firstAttribute=\"centerX\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"centerX\" id=\"0u2-jE-9tZ\"/>\n                <constraint firstItem=\"boQ-fB-7JU\" firstAttribute=\"centerX\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"centerX\" id=\"5ye-2k-QwO\"/>\n                <constraint firstItem=\"r9F-t2-uVD\" firstAttribute=\"centerX\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"centerX\" id=\"8uh-39-hIO\"/>\n                <constraint firstItem=\"uhz-aJ-pvT\" firstAttribute=\"trailing\" secondItem=\"Mhg-Fu-3s0\" secondAttribute=\"trailing\" id=\"Jpa-T6-GpR\"/>\n                <constraint firstItem=\"wNd-qD-qDv\" firstAttribute=\"top\" secondItem=\"Mhg-Fu-3s0\" secondAttribute=\"bottom\" constant=\"18\" id=\"R1s-5n-9bP\"/>\n                <constraint firstItem=\"Wuk-ii-Ge1\" firstAttribute=\"top\" secondItem=\"c99-82-eTv\" secondAttribute=\"bottom\" constant=\"11\" id=\"SPr-LS-3HG\"/>\n                <constraint firstItem=\"uhz-aJ-pvT\" firstAttribute=\"leading\" secondItem=\"Mhg-Fu-3s0\" secondAttribute=\"leading\" id=\"TUv-W3-zY2\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"xxb-V7-Rr3\" secondAttribute=\"bottom\" constant=\"30\" id=\"TUv-xf-RCL\"/>\n                <constraint firstItem=\"xxb-V7-Rr3\" firstAttribute=\"top\" secondItem=\"uhz-aJ-pvT\" secondAttribute=\"bottom\" constant=\"18\" id=\"Yfh-4q-tyo\"/>\n                <constraint firstItem=\"vGr-Fx-7Yk\" firstAttribute=\"leading\" secondItem=\"PcW-EO-frL\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"Z7D-g8-RwO\"/>\n                <constraint firstItem=\"uhz-aJ-pvT\" firstAttribute=\"top\" secondItem=\"Wuk-ii-Ge1\" secondAttribute=\"bottom\" constant=\"18\" id=\"aaL-E8-1b4\"/>\n                <constraint firstItem=\"c99-82-eTv\" firstAttribute=\"trailing\" secondItem=\"wph-Lj-E2b\" secondAttribute=\"trailing\" id=\"bfI-b8-Wjo\"/>\n                <constraint firstItem=\"PcW-EO-frL\" firstAttribute=\"trailing\" secondItem=\"AOa-Oj-4Fg\" secondAttribute=\"trailing\" id=\"dBE-5A-50X\"/>\n                <constraint firstItem=\"Mhg-Fu-3s0\" firstAttribute=\"top\" secondItem=\"boQ-fB-7JU\" secondAttribute=\"bottom\" constant=\"18\" id=\"dhF-fG-o3f\"/>\n                <constraint firstItem=\"Mhg-Fu-3s0\" firstAttribute=\"trailing\" secondItem=\"r9F-t2-uVD\" secondAttribute=\"trailing\" id=\"eHo-3F-gpe\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Wuk-ii-Ge1\" secondAttribute=\"trailing\" constant=\"20\" id=\"eI9-3o-mN3\"/>\n                <constraint firstItem=\"boQ-fB-7JU\" firstAttribute=\"top\" secondItem=\"r9F-t2-uVD\" secondAttribute=\"bottom\" constant=\"18\" id=\"fEr-PX-lOT\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"vGr-Fx-7Yk\" secondAttribute=\"trailing\" constant=\"20\" id=\"fSg-ub-DBf\"/>\n                <constraint firstItem=\"r9F-t2-uVD\" firstAttribute=\"top\" secondItem=\"vGr-Fx-7Yk\" secondAttribute=\"bottom\" constant=\"18\" id=\"feJ-FH-8hb\"/>\n                <constraint firstItem=\"r9F-t2-uVD\" firstAttribute=\"leading\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"leading\" constant=\"40\" id=\"gTi-6t-5kk\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"wNd-qD-qDv\" secondAttribute=\"trailing\" constant=\"20\" id=\"lFZ-SX-UtL\"/>\n                <constraint firstItem=\"Wuk-ii-Ge1\" firstAttribute=\"leading\" secondItem=\"c99-82-eTv\" secondAttribute=\"leading\" id=\"mPn-Ai-gop\"/>\n                <constraint firstItem=\"Mhg-Fu-3s0\" firstAttribute=\"leading\" secondItem=\"r9F-t2-uVD\" secondAttribute=\"leading\" id=\"r3g-9A-65f\"/>\n                <constraint firstItem=\"PcW-EO-frL\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"leading\" constant=\"20\" id=\"tsu-i1-gPd\"/>\n                <constraint firstItem=\"PcW-EO-frL\" firstAttribute=\"firstBaseline\" secondItem=\"vGr-Fx-7Yk\" secondAttribute=\"firstBaseline\" id=\"u5h-zn-F5M\"/>\n                <constraint firstItem=\"c99-82-eTv\" firstAttribute=\"firstBaseline\" secondItem=\"wNd-qD-qDv\" secondAttribute=\"firstBaseline\" id=\"vkf-Be-3vJ\"/>\n                <constraint firstItem=\"wNd-qD-qDv\" firstAttribute=\"leading\" secondItem=\"c99-82-eTv\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"wKc-5k-fYr\"/>\n                <constraint firstItem=\"c99-82-eTv\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"leading\" constant=\"20\" id=\"wsK-1Q-YcF\"/>\n                <constraint firstItem=\"vGr-Fx-7Yk\" firstAttribute=\"top\" secondItem=\"4pD-W0-ghZ\" secondAttribute=\"top\" constant=\"30\" id=\"xUI-KD-LJJ\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-2626\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c5A-lx-Ey9\" userLabel=\"Inline Media\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"340\"/>\n            <subviews>\n                <tabView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yJ6-b8-T3v\">\n                    <rect key=\"frame\" x=\"13\" y=\"10\" width=\"644\" height=\"316\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"630\" id=\"gDs-qq-DRp\"/>\n                        <constraint firstAttribute=\"height\" constant=\"300\" id=\"nHf-hl-ACP\"/>\n                    </constraints>\n                    <font key=\"font\" metaFont=\"system\"/>\n                    <tabViewItems>\n                        <tabViewItem label=\"General\" identifier=\"1\" id=\"Hhx-gR-bl2\">\n                            <view key=\"view\" id=\"Ib9-4w-05S\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"270\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Clr-Kc-72d\">\n                                        <rect key=\"frame\" x=\"134\" y=\"223\" width=\"354\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Show images, videos, and other media inline with chat\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"3YM-rY-vwI\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"onChangedInlineMediaOption:\" target=\"-2\" id=\"CTM-UG-z5T\"/>\n                                            <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.reloadingTheme\" id=\"5QG-Zi-b4z\">\n                                                <dictionary key=\"options\">\n                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                </dictionary>\n                                            </binding>\n                                        </connections>\n                                    </button>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c91-O6-lXk\">\n                                        <rect key=\"frame\" x=\"152\" y=\"186\" width=\"328\" height=\"30\"/>\n                                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"This preference can be enabled or disabled for individual channels in Channel Properties.\" id=\"PMI-yd-MYO\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"Clr-Kc-72d\" firstAttribute=\"leading\" secondItem=\"Ib9-4w-05S\" secondAttribute=\"leading\" constant=\"136\" id=\"Dbq-gt-Jcj\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Clr-Kc-72d\" secondAttribute=\"trailing\" constant=\"20\" id=\"cnh-mX-Ngw\"/>\n                                    <constraint firstItem=\"Clr-Kc-72d\" firstAttribute=\"top\" secondItem=\"Ib9-4w-05S\" secondAttribute=\"top\" constant=\"30\" id=\"fRO-79-sjH\"/>\n                                    <constraint firstItem=\"c91-O6-lXk\" firstAttribute=\"top\" secondItem=\"Clr-Kc-72d\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"weN-aT-EdC\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"c91-O6-lXk\" secondAttribute=\"trailing\" constant=\"20\" id=\"yN9-0e-viM\"/>\n                                    <constraint firstItem=\"c91-O6-lXk\" firstAttribute=\"leading\" secondItem=\"Clr-Kc-72d\" secondAttribute=\"leading\" constant=\"18\" id=\"zPP-ez-c2f\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Images &amp; Video\" identifier=\"\" id=\"lC7-1K-9Qq\">\n                            <view key=\"view\" id=\"QNZ-KN-tQT\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"270\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"6\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Aw8-jv-vTD\">\n                                        <rect key=\"frame\" x=\"95\" y=\"200\" width=\"434\" height=\"48\"/>\n                                        <subviews>\n                                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O4j-qH-gbP\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"28\" width=\"434\" height=\"20\"/>\n                                                <subviews>\n                                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gJA-Vk-OGX\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"305\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Do not display images with a file size greater than\" id=\"SSa-tu-2Yq\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SBB-Bw-5cY\">\n                                                        <rect key=\"frame\" x=\"306\" y=\"-4\" width=\"132\" height=\"25\"/>\n                                                        <popUpButtonCell key=\"cell\" type=\"push\" title=\"100 Megabytes\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"10\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"Cm7-go-Ofo\" id=\"Dyp-3C-1C2\">\n                                                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                            <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                                            <menu key=\"menu\" title=\"OtherViews\" id=\"WBW-c0-Lre\">\n                                                                <items>\n                                                                    <menuItem title=\"1 Megabyte\" tag=\"1\" id=\"QYp-on-TqV\"/>\n                                                                    <menuItem title=\"2 Megabytes\" tag=\"2\" id=\"t1F-VN-p7e\"/>\n                                                                    <menuItem title=\"3 Megabytes\" tag=\"3\" id=\"Wfz-6g-01O\"/>\n                                                                    <menuItem title=\"4 Megabytes\" tag=\"4\" id=\"F4O-wb-ucB\"/>\n                                                                    <menuItem title=\"5 Megabytes\" tag=\"5\" id=\"L2W-6V-I0n\"/>\n                                                                    <menuItem title=\"10 Megabytes\" tag=\"6\" id=\"bIc-5c-e5C\"/>\n                                                                    <menuItem title=\"15 Megabytes\" tag=\"7\" id=\"5ca-8T-UYx\"/>\n                                                                    <menuItem title=\"20 Megabytes\" tag=\"8\" id=\"R2l-gU-6N6\"/>\n                                                                    <menuItem title=\"50 Megabytes\" tag=\"9\" id=\"wCN-ge-BOi\"/>\n                                                                    <menuItem title=\"100 Megabytes\" state=\"on\" tag=\"10\" id=\"Cm7-go-Ofo\"/>\n                                                                </items>\n                                                            </menu>\n                                                        </popUpButtonCell>\n                                                        <accessibility description=\"Maximum File Size for Inline Images\"/>\n                                                        <connections>\n                                                            <binding destination=\"G2Q-fc-ddg\" name=\"selectedTag\" keyPath=\"values.InlineMediaMaximumFilesize\" id=\"fxh-DZ-zVo\"/>\n                                                        </connections>\n                                                    </popUpButton>\n                                                </subviews>\n                                                <visibilityPriorities>\n                                                    <integer value=\"1000\"/>\n                                                    <integer value=\"1000\"/>\n                                                </visibilityPriorities>\n                                                <customSpacing>\n                                                    <real value=\"3.4028234663852886e+38\"/>\n                                                    <real value=\"3.4028234663852886e+38\"/>\n                                                </customSpacing>\n                                            </stackView>\n                                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Kg1-A5-vUH\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"404\" height=\"22\"/>\n                                                <subviews>\n                                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9ej-U6-DGg\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"297\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Do not display images with a height greater than\" id=\"pOk-J1-xX6\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YCI-pw-b4B\">\n                                                        <rect key=\"frame\" x=\"301\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"MZu-iT-GW3\"/>\n                                                            <constraint firstAttribute=\"width\" constant=\"60\" id=\"zV1-Di-FnT\"/>\n                                                        </constraints>\n                                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" title=\"300\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"WvG-Z3-ijn\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                        <accessibility description=\"Maximum Inline Image Height\"/>\n                                                        <connections>\n                                                            <binding destination=\"-2\" name=\"value\" keyPath=\"inlineMediaMaxHeight\" id=\"og0-Jh-heX\">\n                                                                <dictionary key=\"options\">\n                                                                    <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                                </dictionary>\n                                                            </binding>\n                                                        </connections>\n                                                    </textField>\n                                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gJo-u9-dr9\">\n                                                        <rect key=\"frame\" x=\"367\" y=\"4\" width=\"39\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"pixels\" id=\"RZU-od-0LC\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                    </textField>\n                                                </subviews>\n                                                <visibilityPriorities>\n                                                    <integer value=\"1000\"/>\n                                                    <integer value=\"1000\"/>\n                                                    <integer value=\"1000\"/>\n                                                </visibilityPriorities>\n                                                <customSpacing>\n                                                    <real value=\"3.4028234663852886e+38\"/>\n                                                    <real value=\"3.4028234663852886e+38\"/>\n                                                    <real value=\"3.4028234663852886e+38\"/>\n                                                </customSpacing>\n                                            </stackView>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"glE-SK-wgV\">\n                                        <rect key=\"frame\" x=\"95\" y=\"68\" width=\"124\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Load everything\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"0hr-Jw-zED\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <accessibility description=\"Check every link to learn if it is a video or image\"/>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.InlineMediaCheckEverything\" id=\"SFu-iR-jFH\"/>\n                                        </connections>\n                                    </button>\n                                    <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Eeu-56-HJQ\">\n                                        <rect key=\"frame\" x=\"172\" y=\"120\" width=\"281\" height=\"22\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Lga-QD-ob3\">\n                                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"142\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Scale to a maximum of\" id=\"E67-vU-c3g\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hI8-8X-GvK\">\n                                                <rect key=\"frame\" x=\"146\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" constant=\"60\" id=\"6qs-hh-w1n\"/>\n                                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"Mee-mu-YfI\"/>\n                                                </constraints>\n                                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" title=\"300\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"z61-bh-Hbo\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <accessibility description=\"Inline Image Scaled by Width\"/>\n                                                <connections>\n                                                    <binding destination=\"-2\" name=\"value\" keyPath=\"inlineMediaMaxWidth\" id=\"KTp-m6-4vJ\">\n                                                        <dictionary key=\"options\">\n                                                            <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                        </dictionary>\n                                                    </binding>\n                                                </connections>\n                                            </textField>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rB5-7e-5BB\">\n                                                <rect key=\"frame\" x=\"212\" y=\"4\" width=\"71\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"pixels wide\" id=\"0W1-eT-Pcg\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                        </subviews>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KxB-vo-Iq5\">\n                                        <rect key=\"frame\" x=\"40\" y=\"156\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"scO-dk-fBz\">\n                                        <rect key=\"frame\" x=\"40\" y=\"101\" width=\"544\" height=\"5\"/>\n                                    </box>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pdb-Rb-Vk3\">\n                                        <rect key=\"frame\" x=\"111\" y=\"177\" width=\"414\" height=\"15\"/>\n                                        <textFieldCell key=\"cell\" controlSize=\"mini\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Change the value of this preference to zero (0) to disable height checks.\" id=\"sgf-1F-mIV\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FwE-Z9-DZX\">\n                                        <rect key=\"frame\" x=\"113\" y=\"31\" width=\"375\" height=\"30\"/>\n                                        <textFieldCell key=\"cell\" controlSize=\"mini\" selectable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Load the contents of every URL posted in a channel to determine which are images or videos.\" id=\"Udl-QC-wcp\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"Aw8-jv-vTD\" firstAttribute=\"centerX\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"centerX\" id=\"1H7-aw-HZK\"/>\n                                    <constraint firstItem=\"scO-dk-fBz\" firstAttribute=\"top\" secondItem=\"Eeu-56-HJQ\" secondAttribute=\"bottom\" constant=\"16\" id=\"4g8-9M-mdq\"/>\n                                    <constraint firstItem=\"KxB-vo-Iq5\" firstAttribute=\"leading\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"leading\" constant=\"40\" id=\"5SU-eM-CyD\"/>\n                                    <constraint firstItem=\"glE-SK-wgV\" firstAttribute=\"leading\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"leading\" constant=\"97\" id=\"ELv-LM-UWa\"/>\n                                    <constraint firstItem=\"KxB-vo-Iq5\" firstAttribute=\"centerX\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"centerX\" id=\"Eud-8h-RbZ\"/>\n                                    <constraint firstItem=\"Eeu-56-HJQ\" firstAttribute=\"centerX\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"centerX\" id=\"N2Q-xq-suL\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"FwE-Z9-DZX\" secondAttribute=\"trailing\" constant=\"20\" id=\"Qfg-36-y9E\"/>\n                                    <constraint firstItem=\"scO-dk-fBz\" firstAttribute=\"trailing\" secondItem=\"KxB-vo-Iq5\" secondAttribute=\"trailing\" id=\"VsF-Ku-9cx\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"glE-SK-wgV\" secondAttribute=\"trailing\" constant=\"20\" id=\"YIW-px-NCF\"/>\n                                    <constraint firstItem=\"pdb-Rb-Vk3\" firstAttribute=\"top\" secondItem=\"Aw8-jv-vTD\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"Zh5-xF-mou\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"pdb-Rb-Vk3\" secondAttribute=\"trailing\" constant=\"20\" id=\"dU6-dt-EJy\"/>\n                                    <constraint firstItem=\"pdb-Rb-Vk3\" firstAttribute=\"leading\" secondItem=\"Aw8-jv-vTD\" secondAttribute=\"leading\" constant=\"18\" id=\"gMn-cd-TA5\"/>\n                                    <constraint firstItem=\"Aw8-jv-vTD\" firstAttribute=\"top\" secondItem=\"QNZ-KN-tQT\" secondAttribute=\"top\" constant=\"22\" id=\"imV-jO-Y04\"/>\n                                    <constraint firstItem=\"Eeu-56-HJQ\" firstAttribute=\"top\" secondItem=\"KxB-vo-Iq5\" secondAttribute=\"bottom\" constant=\"16\" id=\"jHh-Me-ewb\"/>\n                                    <constraint firstItem=\"KxB-vo-Iq5\" firstAttribute=\"top\" secondItem=\"pdb-Rb-Vk3\" secondAttribute=\"bottom\" constant=\"18\" id=\"nzi-P4-lOe\"/>\n                                    <constraint firstItem=\"FwE-Z9-DZX\" firstAttribute=\"top\" secondItem=\"glE-SK-wgV\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"rPQ-Zh-y0u\"/>\n                                    <constraint firstItem=\"glE-SK-wgV\" firstAttribute=\"top\" secondItem=\"scO-dk-fBz\" secondAttribute=\"bottom\" constant=\"18\" id=\"seg-zh-Vee\"/>\n                                    <constraint firstItem=\"scO-dk-fBz\" firstAttribute=\"leading\" secondItem=\"KxB-vo-Iq5\" secondAttribute=\"leading\" id=\"vaj-AD-z7H\"/>\n                                    <constraint firstItem=\"FwE-Z9-DZX\" firstAttribute=\"leading\" secondItem=\"glE-SK-wgV\" secondAttribute=\"leading\" constant=\"18\" id=\"xBG-98-UFp\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                        <tabViewItem label=\"Limitations\" identifier=\"\" id=\"fOT-be-gFu\">\n                            <view key=\"view\" id=\"PcM-EK-9Mh\">\n                                <rect key=\"frame\" x=\"10\" y=\"33\" width=\"624\" height=\"270\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <subviews>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oNJ-ok-jAs\">\n                                        <rect key=\"frame\" x=\"113\" y=\"223\" width=\"206\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Only inline images and videos\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"2vc-4Q-CJ8\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"-2\" name=\"value\" keyPath=\"self.inlineMediaLimitToBasics\" id=\"UgE-VO-ael\"/>\n                                        </connections>\n                                    </button>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ceh-Ul-KZi\">\n                                        <rect key=\"frame\" x=\"131\" y=\"201\" width=\"346\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Including video services such as YouTube and others\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"nXf-63-MkU\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"-2\" name=\"value\" keyPath=\"self.inlineMediaLimitBasicsToFiles\" id=\"xsv-3y-iMV\">\n                                                <dictionary key=\"options\">\n                                                    <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                </dictionary>\n                                            </binding>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.InlineMediaLimitToBasics\" id=\"NR7-a0-huY\"/>\n                                        </connections>\n                                    </button>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I6X-6F-yH4\">\n                                        <rect key=\"frame\" x=\"113\" y=\"171\" width=\"301\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Only inline media that is safe to view in public\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"NlC-I6-LZo\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.InlineMediaLimitNaughtyContent\" id=\"uxl-r1-y6v\"/>\n                                        </connections>\n                                    </button>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZhW-5j-NXk\">\n                                        <rect key=\"frame\" x=\"131\" y=\"119\" width=\"328\" height=\"45\"/>\n                                        <textFieldCell key=\"cell\" controlSize=\"mini\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"Kjb-nu-50w\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <string key=\"title\">This preference works by disabling certain services.\nIt doesn't know whether a specific image or video is safe.\nYou should therefore not rely solely on this preference.</string>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"36L-dm-E2y\">\n                                        <rect key=\"frame\" x=\"113\" y=\"92\" width=\"242\" height=\"18\"/>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Only inline media from safe sources\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"pmi-Al-qyW\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.InlineMediaLimitUnsafeContent\" id=\"pe2-wx-tqt\"/>\n                                        </connections>\n                                    </button>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zk5-W6-ihe\">\n                                        <rect key=\"frame\" x=\"131\" y=\"55\" width=\"305\" height=\"30\"/>\n                                        <textFieldCell key=\"cell\" controlSize=\"mini\" selectable=\"YES\" refusesFirstResponder=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Safe sources are services that don't inject HTML nor load external JavaScript resoures to appear inline.\" id=\"Ygv-nr-zSp\">\n                                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"I6X-6F-yH4\" firstAttribute=\"top\" secondItem=\"Ceh-Ul-KZi\" secondAttribute=\"bottom\" constant=\"14\" id=\"5gJ-eO-TwY\"/>\n                                    <constraint firstItem=\"36L-dm-E2y\" firstAttribute=\"top\" secondItem=\"ZhW-5j-NXk\" secondAttribute=\"bottom\" constant=\"10\" id=\"61y-bI-KFp\"/>\n                                    <constraint firstItem=\"ZhW-5j-NXk\" firstAttribute=\"leading\" secondItem=\"I6X-6F-yH4\" secondAttribute=\"leading\" constant=\"18\" id=\"7bc-8Y-Gkb\"/>\n                                    <constraint firstItem=\"Zk5-W6-ihe\" firstAttribute=\"leading\" secondItem=\"36L-dm-E2y\" secondAttribute=\"leading\" constant=\"18\" id=\"9Vp-bD-qVh\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"I6X-6F-yH4\" secondAttribute=\"trailing\" constant=\"20\" id=\"D2U-fE-5zW\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Ceh-Ul-KZi\" secondAttribute=\"trailing\" constant=\"20\" id=\"IhX-GA-AdU\"/>\n                                    <constraint firstItem=\"Ceh-Ul-KZi\" firstAttribute=\"leading\" secondItem=\"oNJ-ok-jAs\" secondAttribute=\"leading\" constant=\"18\" id=\"MJG-ag-Cn8\"/>\n                                    <constraint firstItem=\"I6X-6F-yH4\" firstAttribute=\"leading\" secondItem=\"oNJ-ok-jAs\" secondAttribute=\"leading\" id=\"QgZ-Ax-aDj\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"36L-dm-E2y\" secondAttribute=\"trailing\" constant=\"20\" id=\"XPR-le-PYT\"/>\n                                    <constraint firstItem=\"36L-dm-E2y\" firstAttribute=\"leading\" secondItem=\"I6X-6F-yH4\" secondAttribute=\"leading\" id=\"ZFe-9j-UWM\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"oNJ-ok-jAs\" secondAttribute=\"trailing\" constant=\"20\" id=\"aax-N4-hDw\"/>\n                                    <constraint firstItem=\"oNJ-ok-jAs\" firstAttribute=\"top\" secondItem=\"PcM-EK-9Mh\" secondAttribute=\"top\" constant=\"30\" id=\"bho-gk-o9y\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ZhW-5j-NXk\" secondAttribute=\"trailing\" constant=\"20\" id=\"fCH-k4-HnV\"/>\n                                    <constraint firstItem=\"Ceh-Ul-KZi\" firstAttribute=\"top\" secondItem=\"oNJ-ok-jAs\" secondAttribute=\"bottom\" constant=\"6\" symbolic=\"YES\" id=\"ge1-qs-WLY\"/>\n                                    <constraint firstItem=\"Zk5-W6-ihe\" firstAttribute=\"top\" secondItem=\"36L-dm-E2y\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"jdk-2I-37Y\"/>\n                                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Zk5-W6-ihe\" secondAttribute=\"trailing\" constant=\"20\" id=\"onk-Pi-W5R\"/>\n                                    <constraint firstItem=\"oNJ-ok-jAs\" firstAttribute=\"leading\" secondItem=\"PcM-EK-9Mh\" secondAttribute=\"leading\" constant=\"115\" id=\"qSP-Ti-zoH\"/>\n                                    <constraint firstItem=\"ZhW-5j-NXk\" firstAttribute=\"top\" secondItem=\"I6X-6F-yH4\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"zzf-XD-GBh\"/>\n                                </constraints>\n                            </view>\n                        </tabViewItem>\n                    </tabViewItems>\n                </tabView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"yJ6-b8-T3v\" secondAttribute=\"trailing\" constant=\"20\" id=\"7um-dT-e1i\"/>\n                <constraint firstItem=\"yJ6-b8-T3v\" firstAttribute=\"top\" secondItem=\"c5A-lx-Ey9\" secondAttribute=\"top\" constant=\"20\" id=\"UM4-Pf-WKI\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"yJ6-b8-T3v\" secondAttribute=\"bottom\" constant=\"20\" id=\"W78-sK-Shm\"/>\n                <constraint firstItem=\"yJ6-b8-T3v\" firstAttribute=\"leading\" secondItem=\"c5A-lx-Ey9\" secondAttribute=\"leading\" constant=\"20\" id=\"ysY-1T-MZS\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-1782\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DPg-Nu-HcZ\" userLabel=\"Log Location\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"80\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xFJ-dE-cHt\">\n                    <rect key=\"frame\" x=\"144\" y=\"30\" width=\"382\" height=\"20\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ldq-4s-vGV\">\n                            <rect key=\"frame\" x=\"-2\" y=\"2\" width=\"176\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Log transcripts to folder:\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"Yh4-3q-f6X\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"-2\" name=\"value\" keyPath=\"logTranscript\" id=\"XFM-G7-oO2\"/>\n                            </connections>\n                        </button>\n                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"H7x-dV-MZS\">\n                            <rect key=\"frame\" x=\"179\" y=\"-4\" width=\"207\" height=\"25\"/>\n                            <popUpButtonCell key=\"cell\" type=\"push\" title=\" \" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" inset=\"2\" arrowPosition=\"arrowAtCenter\" preferredEdge=\"maxY\" selectedItem=\"QrV-Nz-fZ5\" id=\"7JI-Be-FO7\">\n                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" title=\"OtherViews\" showsStateColumn=\"NO\" id=\"Zvg-8I-YWm\">\n                                    <items>\n                                        <menuItem title=\" \" state=\"on\" id=\"QrV-Nz-fZ5\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"2BM-nm-8CF\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                                        </menuItem>\n                                        <menuItem title=\"Select Destination…\" tag=\"2\" id=\"v2f-9c-gsp\"/>\n                                        <menuItem title=\"Clear Destination\" tag=\"3\" id=\"l8l-ff-FHu\">\n                                            <connections>\n                                                <binding destination=\"G2Q-fc-ddg\" name=\"enabled\" keyPath=\"values.LogTranscriptDestinationSecurityBookmark_5\" id=\"u9S-Eb-PHq\">\n                                                    <dictionary key=\"options\">\n                                                        <string key=\"NSValueTransformerName\">NSIsNotNil</string>\n                                                    </dictionary>\n                                                </binding>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" constant=\"200\" id=\"evc-vk-lNE\"/>\n                            </constraints>\n                            <accessibility description=\"Log Transcript Folder\"/>\n                            <connections>\n                                <action selector=\"onChangedTranscriptFolder:\" target=\"-2\" id=\"LYi-hQ-pgj\"/>\n                                <binding destination=\"-2\" name=\"enabled\" keyPath=\"logTranscript\" id=\"MJL-pl-Rso\"/>\n                            </connections>\n                        </popUpButton>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"xFJ-dE-cHt\" firstAttribute=\"centerX\" secondItem=\"DPg-Nu-HcZ\" secondAttribute=\"centerX\" id=\"FhK-zG-Ee0\"/>\n                <constraint firstItem=\"xFJ-dE-cHt\" firstAttribute=\"top\" secondItem=\"DPg-Nu-HcZ\" secondAttribute=\"top\" constant=\"30\" id=\"lju-2j-oqd\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"325\" y=\"-1522.5\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"d6J-SH-Xgl\" userLabel=\"Default Identity\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"679\" height=\"243\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"H70-fl-X2H\">\n                    <rect key=\"frame\" x=\"110\" y=\"197\" width=\"459\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"The following information will be filled in when creating a NEW connection.\" id=\"DJW-g4-9G4\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OMx-g0-PA6\">\n                    <rect key=\"frame\" x=\"178\" y=\"65\" width=\"323\" height=\"112\"/>\n                    <rows>\n                        <gridRow id=\"aCN-2Z-aGV\"/>\n                        <gridRow id=\"hax-Uw-b3z\"/>\n                        <gridRow id=\"QVg-7h-xMB\"/>\n                        <gridRow id=\"GyW-Sn-sU4\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"trailing\" id=\"gPO-Nm-Vn2\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"rEe-oe-4Fn\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"aCN-2Z-aGV\" column=\"gPO-Nm-Vn2\" id=\"5xl-OK-CVn\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"atZ-KI-pHZ\">\n                                <rect key=\"frame\" x=\"41\" y=\"94\" width=\"68\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Nickname:\" id=\"Ep5-4B-niV\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"aCN-2Z-aGV\" column=\"rEe-oe-4Fn\" id=\"ZwC-0C-eG1\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cN4-wu-5MK\">\n                                <rect key=\"frame\" x=\"115\" y=\"90\" width=\"208\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"208\" id=\"9ZH-xJ-baI\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"jD4-fZ-oLb\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"nac-sO-8FC\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"atZ-KI-pHZ\" id=\"FPR-yS-wIz\"/>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DefaultIdentity -&gt; Nickname\" id=\"MMj-2o-org\">\n                                        <dictionary key=\"options\">\n                                            <bool key=\"NSContinuouslyUpdatesValue\" value=\"YES\"/>\n                                        </dictionary>\n                                    </binding>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"hax-Uw-b3z\" column=\"gPO-Nm-Vn2\" id=\"AZQ-Rr-rhq\">\n                            <stackView key=\"contentView\" distribution=\"fill\" orientation=\"vertical\" alignment=\"trailing\" spacing=\"0.0\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RWl-og-Kwu\">\n                                <rect key=\"frame\" x=\"8\" y=\"64\" width=\"99\" height=\"16\"/>\n                                <subviews>\n                                    <textField focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zJ6-fr-Jwe\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"103\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Away Nickname:\" id=\"nlg-4Q-gCw\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                        </gridCell>\n                        <gridCell row=\"hax-Uw-b3z\" column=\"rEe-oe-4Fn\" id=\"H9Z-Sp-ctO\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QKU-rN-vv7\">\n                                <rect key=\"frame\" x=\"115\" y=\"60\" width=\"208\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"y4i-Ap-Nq2\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional \" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"cXo-4f-9dY\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"zJ6-fr-Jwe\" id=\"EJ7-A6-dXE\"/>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DefaultIdentity -&gt; AwayNickname\" id=\"83j-ch-faJ\">\n                                        <dictionary key=\"options\">\n                                            <bool key=\"NSContinuouslyUpdatesValue\" value=\"YES\"/>\n                                        </dictionary>\n                                    </binding>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"QVg-7h-xMB\" column=\"gPO-Nm-Vn2\" id=\"sd0-fO-gYh\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"awe-eA-PEP\">\n                                <rect key=\"frame\" x=\"39\" y=\"34\" width=\"70\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Username:\" id=\"P1u-x3-WTj\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"QVg-7h-xMB\" column=\"rEe-oe-4Fn\" id=\"JE1-gi-0oQ\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"at5-lc-f2l\">\n                                <rect key=\"frame\" x=\"115\" y=\"30\" width=\"208\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"TRl-ig-DmN\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"w3H-Pj-6CW\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"awe-eA-PEP\" id=\"k7I-Dz-Dg5\"/>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DefaultIdentity -&gt; Username\" id=\"YJi-sh-xTe\">\n                                        <dictionary key=\"options\">\n                                            <bool key=\"NSContinuouslyUpdatesValue\" value=\"YES\"/>\n                                        </dictionary>\n                                    </binding>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"GyW-Sn-sU4\" column=\"gPO-Nm-Vn2\" id=\"FPA-vU-8im\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"t35-1P-MUO\">\n                                <rect key=\"frame\" x=\"38\" y=\"4\" width=\"71\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Real name:\" id=\"cOZ-LR-XMc\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"GyW-Sn-sU4\" column=\"rEe-oe-4Fn\" id=\"43c-om-Zbf\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rPf-TF-oTQ\">\n                                <rect key=\"frame\" x=\"115\" y=\"0.0\" width=\"208\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"ry3-4J-O91\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"kmu-Ey-2Qm\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"t35-1P-MUO\" id=\"wtE-s7-UAc\"/>\n                                    <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DefaultIdentity -&gt; Realname\" id=\"KFg-YK-aaT\">\n                                        <dictionary key=\"options\">\n                                            <bool key=\"NSContinuouslyUpdatesValue\" value=\"YES\"/>\n                                        </dictionary>\n                                    </binding>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ImR-BQ-qOk\">\n                    <rect key=\"frame\" x=\"278\" y=\"30\" width=\"123\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"All fields are optional\" id=\"FIU-xu-elQ\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"H70-fl-X2H\" firstAttribute=\"centerX\" secondItem=\"d6J-SH-Xgl\" secondAttribute=\"centerX\" id=\"9Cn-nD-aAp\"/>\n                <constraint firstItem=\"ImR-BQ-qOk\" firstAttribute=\"top\" secondItem=\"OMx-g0-PA6\" secondAttribute=\"bottom\" constant=\"20\" id=\"Oqg-0c-4GV\"/>\n                <constraint firstItem=\"OMx-g0-PA6\" firstAttribute=\"leading\" secondItem=\"d6J-SH-Xgl\" secondAttribute=\"leading\" constant=\"178\" id=\"UZr-ef-19N\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ImR-BQ-qOk\" secondAttribute=\"bottom\" constant=\"30\" id=\"f2P-UB-F1h\"/>\n                <constraint firstItem=\"OMx-g0-PA6\" firstAttribute=\"centerX\" secondItem=\"d6J-SH-Xgl\" secondAttribute=\"centerX\" id=\"jua-TN-wP2\"/>\n                <constraint firstItem=\"OMx-g0-PA6\" firstAttribute=\"top\" secondItem=\"H70-fl-X2H\" secondAttribute=\"bottom\" constant=\"20\" id=\"l2r-ue-oEC\"/>\n                <constraint firstItem=\"ImR-BQ-qOk\" firstAttribute=\"centerX\" secondItem=\"d6J-SH-Xgl\" secondAttribute=\"centerX\" id=\"wcf-tb-qd4\"/>\n                <constraint firstItem=\"H70-fl-X2H\" firstAttribute=\"top\" secondItem=\"d6J-SH-Xgl\" secondAttribute=\"top\" constant=\"30\" id=\"zUy-q8-g3u\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329.5\" y=\"-1246.5\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pkr-Na-yb0\" userLabel=\"Default IRCop Messages\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"363\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9GL-Fm-FRS\">\n                    <rect key=\"frame\" x=\"99\" y=\"317\" width=\"122\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Default Kill Reason:\" id=\"KGB-V1-WkX\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9Fb-qx-dGB\">\n                    <rect key=\"frame\" x=\"99\" y=\"107\" width=\"134\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Default Shun Reason:\" id=\"6vn-da-cA0\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qvB-sf-fih\">\n                    <rect key=\"frame\" x=\"101\" y=\"240\" width=\"468\" height=\"69\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"69\" id=\"Z7V-jD-Z5G\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"T0B-CS-3t3\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"9GL-Fm-FRS\" id=\"VKP-nM-yWT\"/>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.IRCopDefaultLocalizaiton -&gt; Kill Reason\" id=\"qK9-GI-Duh\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ckK-Ko-G8O\">\n                    <rect key=\"frame\" x=\"101\" y=\"135\" width=\"468\" height=\"69\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"69\" id=\"LFI-cz-XH3\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"JRA-rV-k6G\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"qig-yp-6aY\" id=\"aX5-BO-Vy4\"/>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.IRCopDefaultLocalizaiton -&gt; G:Line Reason\" id=\"jC4-to-p72\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"b4u-EN-XAj\">\n                    <rect key=\"frame\" x=\"442\" y=\"212\" width=\"129\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"(Includes Ban Length)\" id=\"WL8-Lc-POK\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qig-yp-6aY\">\n                    <rect key=\"frame\" x=\"99\" y=\"212\" width=\"142\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Default G:Line Reason:\" id=\"kN3-5K-4fJ\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"URw-AA-AlF\">\n                    <rect key=\"frame\" x=\"442\" y=\"107\" width=\"129\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"(Includes Ban Length)\" id=\"10O-F4-8BP\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qg5-rl-Ov0\">\n                    <rect key=\"frame\" x=\"101\" y=\"30\" width=\"468\" height=\"69\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"69\" id=\"E8U-bt-uvH\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"tZR-F3-Bdo\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"9Fb-qx-dGB\" id=\"brb-gf-mNK\"/>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.IRCopDefaultLocalizaiton -&gt; Shun Reason\" id=\"aMW-2e-qdQ\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"qg5-rl-Ov0\" firstAttribute=\"top\" secondItem=\"9Fb-qx-dGB\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"0ul-n1-WqI\"/>\n                <constraint firstItem=\"ckK-Ko-G8O\" firstAttribute=\"top\" secondItem=\"b4u-EN-XAj\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"1UO-h9-VGk\"/>\n                <constraint firstItem=\"qig-yp-6aY\" firstAttribute=\"leading\" secondItem=\"ckK-Ko-G8O\" secondAttribute=\"leading\" id=\"7Ip-Qv-q5U\"/>\n                <constraint firstItem=\"URw-AA-AlF\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"9Fb-qx-dGB\" secondAttribute=\"trailing\" constant=\"20\" id=\"AgD-4E-A0m\"/>\n                <constraint firstItem=\"9Fb-qx-dGB\" firstAttribute=\"top\" secondItem=\"ckK-Ko-G8O\" secondAttribute=\"bottom\" constant=\"12\" id=\"BXp-ru-9dc\"/>\n                <constraint firstItem=\"9GL-Fm-FRS\" firstAttribute=\"top\" secondItem=\"Pkr-Na-yb0\" secondAttribute=\"top\" constant=\"30\" id=\"DCz-Fg-sdG\"/>\n                <constraint firstItem=\"ckK-Ko-G8O\" firstAttribute=\"trailing\" secondItem=\"qvB-sf-fih\" secondAttribute=\"trailing\" id=\"GgC-y0-i9c\"/>\n                <constraint firstItem=\"9GL-Fm-FRS\" firstAttribute=\"leading\" secondItem=\"qvB-sf-fih\" secondAttribute=\"leading\" id=\"JH5-kN-Ujj\"/>\n                <constraint firstItem=\"qig-yp-6aY\" firstAttribute=\"top\" secondItem=\"qvB-sf-fih\" secondAttribute=\"bottom\" constant=\"12\" id=\"LXm-YP-gl2\"/>\n                <constraint firstItem=\"ckK-Ko-G8O\" firstAttribute=\"leading\" secondItem=\"qvB-sf-fih\" secondAttribute=\"leading\" id=\"P89-YS-dIg\"/>\n                <constraint firstItem=\"qg5-rl-Ov0\" firstAttribute=\"trailing\" secondItem=\"ckK-Ko-G8O\" secondAttribute=\"trailing\" id=\"PaW-WZ-fPw\"/>\n                <constraint firstItem=\"9Fb-qx-dGB\" firstAttribute=\"leading\" secondItem=\"qg5-rl-Ov0\" secondAttribute=\"leading\" id=\"RMK-4z-B50\"/>\n                <constraint firstItem=\"qg5-rl-Ov0\" firstAttribute=\"leading\" secondItem=\"ckK-Ko-G8O\" secondAttribute=\"leading\" id=\"aZd-9u-vVN\"/>\n                <constraint firstItem=\"b4u-EN-XAj\" firstAttribute=\"trailing\" secondItem=\"ckK-Ko-G8O\" secondAttribute=\"trailing\" id=\"aap-xx-n6n\"/>\n                <constraint firstItem=\"qvB-sf-fih\" firstAttribute=\"centerX\" secondItem=\"Pkr-Na-yb0\" secondAttribute=\"centerX\" id=\"alK-Th-ODC\"/>\n                <constraint firstItem=\"qg5-rl-Ov0\" firstAttribute=\"top\" secondItem=\"URw-AA-AlF\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"fny-db-knM\"/>\n                <constraint firstItem=\"b4u-EN-XAj\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"qig-yp-6aY\" secondAttribute=\"trailing\" constant=\"20\" id=\"ful-Hg-XcD\"/>\n                <constraint firstItem=\"URw-AA-AlF\" firstAttribute=\"trailing\" secondItem=\"qg5-rl-Ov0\" secondAttribute=\"trailing\" id=\"pt0-Ac-ivi\"/>\n                <constraint firstItem=\"qvB-sf-fih\" firstAttribute=\"top\" secondItem=\"9GL-Fm-FRS\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"qrg-xQ-SN1\"/>\n                <constraint firstItem=\"ckK-Ko-G8O\" firstAttribute=\"top\" secondItem=\"qig-yp-6aY\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"rHN-zM-moZ\"/>\n                <constraint firstItem=\"qvB-sf-fih\" firstAttribute=\"leading\" secondItem=\"Pkr-Na-yb0\" secondAttribute=\"leading\" constant=\"101\" id=\"t1Q-9g-rM8\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"qg5-rl-Ov0\" secondAttribute=\"bottom\" constant=\"30\" id=\"z7s-hl-4pQ\"/>\n                <constraint firstItem=\"9GL-Fm-FRS\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"qvB-sf-fih\" secondAttribute=\"trailing\" id=\"zmI-2S-wVA\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-858\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZYk-23-zvA\" userLabel=\"Off-the-Record Messaging\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"327\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <box verticalHuggingPriority=\"750\" alphaValue=\"0.5\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lVR-sX-Fvg\">\n                    <rect key=\"frame\" x=\"40\" y=\"130\" width=\"590\" height=\"5\"/>\n                </box>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c2f-dF-OoT\">\n                    <rect key=\"frame\" x=\"108\" y=\"67\" width=\"245\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Do not send unencrypted messages\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"m4s-Bh-UhF\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"offRecordMessagingPolicyChanged:\" target=\"-2\" id=\"VDz-Hf-aGA\"/>\n                        <binding destination=\"-2\" name=\"value\" keyPath=\"self.textEncryptionIsRequired\" id=\"GxY-st-TFJ\"/>\n                        <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.textEncryptionIsRequiredPreferenceEnabled\" id=\"sD8-2L-tLT\"/>\n                    </connections>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"318-ie-koO\">\n                    <rect key=\"frame\" x=\"108\" y=\"97\" width=\"452\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Automatically start an Off-the-Record conversation whenever possible\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"vuQ-Sk-fPF\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"offRecordMessagingPolicyChanged:\" target=\"-2\" id=\"dHa-Df-hCq\"/>\n                        <binding destination=\"-2\" name=\"value\" keyPath=\"self.textEncryptionIsOpportunistic\" id=\"vV4-Wd-SzN\"/>\n                        <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.textEncryptionIsOpportunisticPreferenceEnabled\" id=\"Xsf-ZT-s4O\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kwB-LQ-B19\">\n                    <rect key=\"frame\" x=\"126\" y=\"30\" width=\"345\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Do not allow messages to be sent unless an Off-the-Record conversation is active.\" id=\"Pzt-74-0SL\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"c2f-dF-OoT\" id=\"Qq7-Bw-LEp\"/>\n                    </connections>\n                </textField>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lYh-JG-BN5\">\n                    <rect key=\"frame\" x=\"108\" y=\"280\" width=\"233\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable Off-the-Record Messaging\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"Ebq-y2-sIl\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"offRecordMessagingPolicyChanged:\" target=\"-2\" id=\"Off-Gl-wab\"/>\n                        <binding destination=\"-2\" name=\"value\" keyPath=\"self.textEncryptionIsEnabled\" id=\"6xO-cN-Iea\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yGO-On-ZvN\">\n                    <rect key=\"frame\" x=\"126\" y=\"213\" width=\"437\" height=\"60\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"dGa-dE-wl9\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <string key=\"title\">Off-the-Record Messaging (OTR) increases the privacy of private messages by encrypting their contents so that only you and your chat partner can see what is written. It also provides a means to verify, with certainty, that the person you are communicating with are who they claim to be.</string>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"lYh-JG-BN5\" id=\"D3l-cP-SuS\"/>\n                    </connections>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u4s-fg-bNo\">\n                    <rect key=\"frame\" x=\"121\" y=\"174\" width=\"234\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Learn more from Official Website\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"45H-rX-vfm\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"offRecordMessagingOpenOfficialWebsite:\" target=\"-2\" id=\"Rln-xV-DfK\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"guD-BE-Zzc\">\n                    <rect key=\"frame\" x=\"121\" y=\"144\" width=\"281\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Learn more about how it works in Textual\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"8KP-Mk-tom\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"offRecordMessagingOpenHelpDocument:\" target=\"-2\" id=\"N6j-be-YVx\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"yGO-On-ZvN\" firstAttribute=\"leading\" secondItem=\"lYh-JG-BN5\" secondAttribute=\"leading\" constant=\"18\" id=\"1dF-VB-Zu9\"/>\n                <constraint firstItem=\"kwB-LQ-B19\" firstAttribute=\"leading\" secondItem=\"c2f-dF-OoT\" secondAttribute=\"leading\" constant=\"18\" id=\"6mp-U9-7u9\"/>\n                <constraint firstItem=\"kwB-LQ-B19\" firstAttribute=\"top\" secondItem=\"c2f-dF-OoT\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"7iI-bo-lEf\"/>\n                <constraint firstItem=\"lVR-sX-Fvg\" firstAttribute=\"top\" secondItem=\"guD-BE-Zzc\" secondAttribute=\"bottom\" constant=\"18\" id=\"BjB-po-Xmg\"/>\n                <constraint firstItem=\"lYh-JG-BN5\" firstAttribute=\"top\" secondItem=\"ZYk-23-zvA\" secondAttribute=\"top\" constant=\"30\" id=\"Bs8-VT-PLv\"/>\n                <constraint firstItem=\"lVR-sX-Fvg\" firstAttribute=\"leading\" secondItem=\"ZYk-23-zvA\" secondAttribute=\"leading\" constant=\"40\" id=\"EKG-ZG-0TJ\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"kwB-LQ-B19\" secondAttribute=\"trailing\" constant=\"20\" id=\"Evq-cT-4c7\"/>\n                <constraint firstItem=\"318-ie-koO\" firstAttribute=\"top\" secondItem=\"lVR-sX-Fvg\" secondAttribute=\"bottom\" constant=\"18\" id=\"Eyl-rW-vkH\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"yGO-On-ZvN\" secondAttribute=\"trailing\" constant=\"20\" id=\"IwK-MZ-nUH\"/>\n                <constraint firstItem=\"guD-BE-Zzc\" firstAttribute=\"leading\" secondItem=\"u4s-fg-bNo\" secondAttribute=\"leading\" id=\"KGA-1N-c4N\"/>\n                <constraint firstItem=\"u4s-fg-bNo\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"yGO-On-ZvN\" secondAttribute=\"trailing\" id=\"LIn-vf-16E\"/>\n                <constraint firstItem=\"c2f-dF-OoT\" firstAttribute=\"top\" secondItem=\"318-ie-koO\" secondAttribute=\"bottom\" constant=\"14\" id=\"N3o-wf-4q0\"/>\n                <constraint firstItem=\"guD-BE-Zzc\" firstAttribute=\"top\" secondItem=\"u4s-fg-bNo\" secondAttribute=\"bottom\" constant=\"10\" id=\"PMx-JX-Bu0\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"318-ie-koO\" secondAttribute=\"trailing\" constant=\"20\" id=\"QrJ-aH-ugh\"/>\n                <constraint firstItem=\"lYh-JG-BN5\" firstAttribute=\"leading\" secondItem=\"ZYk-23-zvA\" secondAttribute=\"leading\" constant=\"110\" id=\"Stq-SX-6sM\"/>\n                <constraint firstItem=\"guD-BE-Zzc\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"yGO-On-ZvN\" secondAttribute=\"trailing\" id=\"Z2a-8k-AL1\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"kwB-LQ-B19\" secondAttribute=\"bottom\" constant=\"30\" id=\"eeQ-Ja-LDM\"/>\n                <constraint firstItem=\"318-ie-koO\" firstAttribute=\"leading\" secondItem=\"c2f-dF-OoT\" secondAttribute=\"leading\" id=\"gLD-YE-ihs\"/>\n                <constraint firstItem=\"318-ie-koO\" firstAttribute=\"leading\" secondItem=\"ZYk-23-zvA\" secondAttribute=\"leading\" constant=\"110\" id=\"iIb-sE-07M\"/>\n                <constraint firstItem=\"yGO-On-ZvN\" firstAttribute=\"top\" secondItem=\"lYh-JG-BN5\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"ix3-hc-LpM\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"c2f-dF-OoT\" secondAttribute=\"trailing\" constant=\"20\" id=\"jJg-oA-7Xh\"/>\n                <constraint firstItem=\"u4s-fg-bNo\" firstAttribute=\"top\" secondItem=\"yGO-On-ZvN\" secondAttribute=\"bottom\" constant=\"12\" id=\"qNw-S5-dAz\"/>\n                <constraint firstItem=\"lVR-sX-Fvg\" firstAttribute=\"centerX\" secondItem=\"ZYk-23-zvA\" secondAttribute=\"centerX\" id=\"s4o-ck-4fB\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"lYh-JG-BN5\" secondAttribute=\"trailing\" constant=\"20\" id=\"vSL-I5-Epi\"/>\n                <constraint firstItem=\"u4s-fg-bNo\" firstAttribute=\"leading\" secondItem=\"yGO-On-ZvN\" secondAttribute=\"leading\" id=\"yHN-6v-ep2\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"329\" y=\"-416\"/>\n        </customView>\n        <arrayController alwaysUsesMultipleValuesMarker=\"YES\" id=\"4310\" userLabel=\"Keywords\">\n            <declaredKeys>\n                <string>string</string>\n            </declaredKeys>\n            <connections>\n                <binding destination=\"G2Q-fc-ddg\" name=\"contentArray\" keyPath=\"values.Highlight List -&gt; Primary Matches\" id=\"htt-qo-C7C\">\n                    <dictionary key=\"options\">\n                        <bool key=\"NSHandlesContentAsCompoundValue\" value=\"YES\"/>\n                    </dictionary>\n                </binding>\n            </connections>\n        </arrayController>\n        <arrayController alwaysUsesMultipleValuesMarker=\"YES\" id=\"4313\" userLabel=\"Excluded Keywords\">\n            <declaredKeys>\n                <string>string</string>\n            </declaredKeys>\n            <connections>\n                <binding destination=\"G2Q-fc-ddg\" name=\"contentArray\" keyPath=\"values.Highlight List -&gt; Excluded Matches\" id=\"0BN-r4-aR7\">\n                    <dictionary key=\"options\">\n                        <bool key=\"NSHandlesContentAsCompoundValue\" value=\"YES\"/>\n                    </dictionary>\n                </binding>\n            </connections>\n        </arrayController>\n        <arrayController preservesSelection=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"92m-WJ-gkY\" userLabel=\"Installed Scripts\">\n            <declaredKeys>\n                <string>string</string>\n            </declaredKeys>\n            <connections>\n                <binding destination=\"-2\" name=\"contentArray\" keyPath=\"installedScripts\" id=\"B7c-E1-tOE\"/>\n            </connections>\n        </arrayController>\n        <userDefaultsController id=\"G2Q-fc-ddg\" userLabel=\"Preferences User Defaults Controller\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dAH-Sl-d77\" userLabel=\"Hidden Preferences\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"466\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"V0L-wf-MX5\">\n                    <rect key=\"frame\" x=\"151\" y=\"30\" width=\"369\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Some preferences may require a restart of Textual to take effect.\" id=\"uly-It-UKM\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1g9-Qk-YQN\">\n                    <rect key=\"frame\" x=\"175\" y=\"367\" width=\"123\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable App Nap\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"2nA-D4-FnZ\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"value\" keyPath=\"self.appNapEnabled\" id=\"kVr-7F-VmC\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Bh-Ce-CLv\">\n                    <rect key=\"frame\" x=\"175\" y=\"337\" width=\"122\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable WebKit2\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"W5w-EG-kiD\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.UsesWebKit2WhenAvailable\" id=\"Xds-VT-o1A\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"adq-18-C3D\">\n                    <rect key=\"frame\" x=\"175\" y=\"307\" width=\"318\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Limit number of processes spawned by WebKit2\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"HKB-82-0XP\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.WebViewProcessPoolSizeIsLimited\" id=\"rPc-UM-cTW\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"r5x-9F-a6i\">\n                    <rect key=\"frame\" x=\"175\" y=\"277\" width=\"218\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable link previews in WebKit2\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"d67-Dk-gJt\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.WebViewPreviewLinks\" id=\"ONL-hI-tz0\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wM2-5T-Kcv\">\n                    <rect key=\"frame\" x=\"175\" y=\"247\" width=\"178\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable custom scrollbars\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"wiu-qq-etM\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.WebViewDoNotUsesCustomScrollers\" id=\"0SS-ZD-V6A\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p75-KN-Sms\">\n                    <rect key=\"frame\" x=\"175\" y=\"217\" width=\"135\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Load history lazily\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"xQW-RJ-brS\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.Optimizations -&gt; Load History Lazily\" id=\"4d0-ks-wbl\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xl2-g8-NiZ\">\n                    <rect key=\"frame\" x=\"175\" y=\"187\" width=\"284\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Server list and user list appear transparent\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"4Sf-cU-A93\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.DisableSidebarTranslucency\" id=\"QoU-AQ-Kep\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"b9a-MV-ff4\">\n                    <rect key=\"frame\" x=\"175\" y=\"157\" width=\"164\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Prefer modern sockets\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"mEq-pf-DPP\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"G2Q-fc-ddg\" name=\"value\" keyPath=\"values.PreferModernSockets\" id=\"b4l-BF-WXC\"/>\n                    </connections>\n                </button>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" spacing=\"10\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"84h-O7-xuk\">\n                    <rect key=\"frame\" x=\"147\" y=\"119\" width=\"376\" height=\"19\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fkh-ub-y9J\">\n                            <rect key=\"frame\" x=\"-2\" y=\"1\" width=\"148\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Scrollback Visible Limit:\" id=\"9Aa-8n-7T3\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <comboBox focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"79l-Tb-xQY\">\n                            <rect key=\"frame\" x=\"153\" y=\"-2\" width=\"104\" height=\"22\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"height\" constant=\"19\" id=\"FM9-g5-NsI\"/>\n                                <constraint firstAttribute=\"width\" constant=\"100\" id=\"TjQ-Vb-9kU\"/>\n                            </constraints>\n                            <comboBoxCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" completes=\"NO\" numberOfVisibleItems=\"5\" id=\"8gE-fC-w0O\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <objectValues>\n                                    <string>100</string>\n                                    <string>500</string>\n                                    <string>1000</string>\n                                    <string>1500</string>\n                                    <string>2000</string>\n                                    <string>2500</string>\n                                    <string>3000</string>\n                                    <string>3500</string>\n                                    <string>4000</string>\n                                    <string>4500</string>\n                                    <string>5000</string>\n                                </objectValues>\n                            </comboBoxCell>\n                            <connections>\n                                <action selector=\"onChangedScrollbackVisibleLimit:\" target=\"-2\" id=\"weG-cz-PwF\"/>\n                                <binding destination=\"-2\" name=\"value\" keyPath=\"scrollbackVisibleLimit\" id=\"2Xj-YZ-bJ8\">\n                                    <dictionary key=\"options\">\n                                        <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </comboBox>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Cl9-DF-vFp\">\n                            <rect key=\"frame\" x=\"262\" y=\"1\" width=\"116\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"0 = use default limit\" id=\"wMl-wz-NsN\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f8P-S1-YSA\">\n                    <rect key=\"frame\" x=\"185\" y=\"75\" width=\"300\" height=\"24\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"q3y-Yb-Su8\">\n                            <rect key=\"frame\" x=\"-2\" y=\"5\" width=\"248\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"User list no mode badge background color:\" id=\"MDs-d0-Vsf\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <colorWell tag=\"4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TME-nn-0HB\">\n                            <rect key=\"frame\" x=\"249\" y=\"-2\" width=\"54\" height=\"28\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"height\" constant=\"24\" id=\"9wm-sm-3re\"/>\n                                <constraint firstAttribute=\"width\" constant=\"48\" id=\"PjF-CW-dxo\"/>\n                            </constraints>\n                            <color key=\"color\" red=\"0.05813049898\" green=\"0.055541899059999997\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"q3y-Yb-Su8\" id=\"56v-co-5U0\"/>\n                                <action selector=\"onChangedUserListModeColor:\" target=\"-2\" id=\"1mr-Mm-7IP\"/>\n                                <binding destination=\"-2\" name=\"value\" keyPath=\"self.userListNoModeColor\" id=\"xQQ-6V-kdK\"/>\n                            </connections>\n                        </colorWell>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" spacing=\"4\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eAs-xY-p50\">\n                    <rect key=\"frame\" x=\"180\" y=\"404\" width=\"310\" height=\"32\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wnO-O0-7bL\">\n                            <rect key=\"frame\" x=\"-2\" y=\"16\" width=\"63\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Warning:\" id=\"rGr-Kp-IJJ\">\n                                <font key=\"font\" metaFont=\"systemBold\"/>\n                                <color key=\"textColor\" name=\"systemRedColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HLR-5q-A8j\">\n                            <rect key=\"frame\" x=\"61\" y=\"0.0\" width=\"251\" height=\"32\"/>\n                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Do not modify these preferences unless you know why you are doing so.\" id=\"g4m-Cw-DP6\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"V0L-wf-MX5\" secondAttribute=\"bottom\" constant=\"30\" id=\"0Fr-aZ-e5g\"/>\n                <constraint firstItem=\"1g9-Qk-YQN\" firstAttribute=\"leading\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"leading\" constant=\"177\" id=\"1CJ-7V-YNV\"/>\n                <constraint firstItem=\"2Bh-Ce-CLv\" firstAttribute=\"leading\" secondItem=\"1g9-Qk-YQN\" secondAttribute=\"leading\" id=\"5rh-fw-QlF\"/>\n                <constraint firstItem=\"wM2-5T-Kcv\" firstAttribute=\"leading\" secondItem=\"r5x-9F-a6i\" secondAttribute=\"leading\" id=\"6Dq-GT-HFz\"/>\n                <constraint firstItem=\"V0L-wf-MX5\" firstAttribute=\"top\" secondItem=\"f8P-S1-YSA\" secondAttribute=\"bottom\" constant=\"30\" id=\"6vT-lm-ST7\"/>\n                <constraint firstItem=\"Xl2-g8-NiZ\" firstAttribute=\"top\" secondItem=\"p75-KN-Sms\" secondAttribute=\"bottom\" constant=\"14\" id=\"7Ne-Xm-P3m\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Xl2-g8-NiZ\" secondAttribute=\"trailing\" constant=\"20\" id=\"8Bm-6k-qGz\"/>\n                <constraint firstItem=\"Xl2-g8-NiZ\" firstAttribute=\"leading\" secondItem=\"p75-KN-Sms\" secondAttribute=\"leading\" id=\"8T5-Jf-1tN\"/>\n                <constraint firstItem=\"r5x-9F-a6i\" firstAttribute=\"top\" secondItem=\"adq-18-C3D\" secondAttribute=\"bottom\" constant=\"14\" id=\"FCc-GZ-gYS\"/>\n                <constraint firstItem=\"1g9-Qk-YQN\" firstAttribute=\"top\" secondItem=\"eAs-xY-p50\" secondAttribute=\"bottom\" constant=\"20\" id=\"HMb-sy-AN0\"/>\n                <constraint firstItem=\"adq-18-C3D\" firstAttribute=\"top\" secondItem=\"2Bh-Ce-CLv\" secondAttribute=\"bottom\" constant=\"14\" id=\"J1W-A9-0fe\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"1g9-Qk-YQN\" secondAttribute=\"trailing\" constant=\"20\" id=\"Lb5-wb-qfE\"/>\n                <constraint firstItem=\"p75-KN-Sms\" firstAttribute=\"top\" secondItem=\"wM2-5T-Kcv\" secondAttribute=\"bottom\" constant=\"14\" id=\"N4f-uj-Iz9\"/>\n                <constraint firstItem=\"f8P-S1-YSA\" firstAttribute=\"top\" secondItem=\"84h-O7-xuk\" secondAttribute=\"bottom\" constant=\"20\" id=\"O4J-YF-RNM\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"r5x-9F-a6i\" secondAttribute=\"trailing\" constant=\"20\" id=\"R9Q-hl-OIQ\"/>\n                <constraint firstItem=\"b9a-MV-ff4\" firstAttribute=\"leading\" secondItem=\"Xl2-g8-NiZ\" secondAttribute=\"leading\" id=\"U90-po-07Z\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"wM2-5T-Kcv\" secondAttribute=\"trailing\" constant=\"20\" id=\"ZFf-wU-k9n\"/>\n                <constraint firstItem=\"eAs-xY-p50\" firstAttribute=\"leading\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"leading\" constant=\"180\" id=\"aKK-Ts-ebc\"/>\n                <constraint firstItem=\"2Bh-Ce-CLv\" firstAttribute=\"top\" secondItem=\"1g9-Qk-YQN\" secondAttribute=\"bottom\" constant=\"14\" id=\"aLP-1I-qPp\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"2Bh-Ce-CLv\" secondAttribute=\"trailing\" constant=\"20\" id=\"aSY-hh-GGq\"/>\n                <constraint firstItem=\"r5x-9F-a6i\" firstAttribute=\"leading\" secondItem=\"adq-18-C3D\" secondAttribute=\"leading\" id=\"aqP-MD-gGa\"/>\n                <constraint firstItem=\"V0L-wf-MX5\" firstAttribute=\"centerX\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"centerX\" id=\"b3i-fV-DOR\"/>\n                <constraint firstItem=\"adq-18-C3D\" firstAttribute=\"leading\" secondItem=\"2Bh-Ce-CLv\" secondAttribute=\"leading\" id=\"bde-YN-Yv0\"/>\n                <constraint firstItem=\"p75-KN-Sms\" firstAttribute=\"leading\" secondItem=\"wM2-5T-Kcv\" secondAttribute=\"leading\" id=\"e4k-oI-brN\"/>\n                <constraint firstItem=\"b9a-MV-ff4\" firstAttribute=\"top\" secondItem=\"Xl2-g8-NiZ\" secondAttribute=\"bottom\" constant=\"14\" id=\"gmW-wv-0i4\"/>\n                <constraint firstItem=\"84h-O7-xuk\" firstAttribute=\"top\" secondItem=\"b9a-MV-ff4\" secondAttribute=\"bottom\" constant=\"20\" id=\"hSG-4J-THF\"/>\n                <constraint firstItem=\"eAs-xY-p50\" firstAttribute=\"centerX\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"centerX\" id=\"hdQ-gY-9vm\"/>\n                <constraint firstItem=\"84h-O7-xuk\" firstAttribute=\"centerX\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"centerX\" id=\"iXb-YZ-e1Y\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"p75-KN-Sms\" secondAttribute=\"trailing\" constant=\"20\" id=\"sfB-ps-xYd\"/>\n                <constraint firstItem=\"eAs-xY-p50\" firstAttribute=\"top\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"top\" constant=\"30\" id=\"sp6-Xk-TNz\"/>\n                <constraint firstItem=\"f8P-S1-YSA\" firstAttribute=\"centerX\" secondItem=\"dAH-Sl-d77\" secondAttribute=\"centerX\" id=\"vVU-lv-eZ3\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"adq-18-C3D\" secondAttribute=\"trailing\" constant=\"20\" id=\"w0h-VN-UgA\"/>\n                <constraint firstItem=\"wM2-5T-Kcv\" firstAttribute=\"top\" secondItem=\"r5x-9F-a6i\" secondAttribute=\"bottom\" constant=\"14\" id=\"yJy-do-LTO\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"b9a-MV-ff4\" secondAttribute=\"trailing\" constant=\"20\" id=\"zLm-GZ-r0m\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"318\" y=\"395\"/>\n        </customView>\n        <customObject id=\"k8n-cT-p4s\" customClass=\"TVCNotificationConfigurationViewController\"/>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"18\" height=\"17\"/>\n        <image name=\"NSRemoveTemplate\" width=\"18\" height=\"5\"/>\n        <image name=\"TPWTB_Addons\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Advanced\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Controls\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_General\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Highlights\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Interface\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Notifications\" width=\"32\" height=\"32\"/>\n        <image name=\"TPWTB_Style\" width=\"32\" height=\"32\"/>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCPreferencesUserStyleSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCPreferencesUserStyleSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"oqB-ts-Ci1\" id=\"FFf-Qf-IaG\"/>\n                <outlet property=\"okButton\" destination=\"R62-Gq-GYv\" id=\"gf3-2J-2o7\"/>\n                <outlet property=\"rulesTextView\" destination=\"JXg-rs-7MF\" id=\"nsw-vZ-us6\"/>\n                <outlet property=\"sheet\" destination=\"rKH-mU-cHB\" id=\"LB2-XQ-HxV\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Custom Style Sheet Rules\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"rKH-mU-cHB\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"207\" width=\"480\" height=\"348\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1415\"/>\n            <view key=\"contentView\" id=\"0hQ-Ce-Oet\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"480\" height=\"348\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"R62-Gq-GYv\">\n                        <rect key=\"frame\" x=\"403\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"imu-oU-gSh\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"rGk-v0-cbv\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oqB-ts-Ci1\">\n                        <rect key=\"frame\" x=\"329\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"sLE-U1-Q3L\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"UPp-yR-kbO\"/>\n                        </connections>\n                    </button>\n                    <scrollView horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ut5-0A-XXN\">\n                        <rect key=\"frame\" x=\"20\" y=\"60\" width=\"440\" height=\"244\"/>\n                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"rRP-WY-EZw\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"438\" height=\"242\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <textView importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" smartInsertDelete=\"YES\" id=\"JXg-rs-7MF\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"438\" height=\"242\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <size key=\"minSize\" width=\"438\" height=\"242\"/>\n                                    <size key=\"maxSize\" width=\"440\" height=\"10000000\"/>\n                                    <color key=\"insertionPointColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"qCl-Ay-YnJ\"/>\n                                    </connections>\n                                </textView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"242\" id=\"FHA-dc-o3O\"/>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"440\" id=\"MoR-ab-0wO\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"Uub-jY-m9k\">\n                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"240\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"kQD-yZ-kuG\">\n                            <rect key=\"frame\" x=\"423\" y=\"1\" width=\"16\" height=\"242\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                    </scrollView>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vmy-l2-xRs\">\n                        <rect key=\"frame\" x=\"19\" y=\"312\" width=\"306\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" title=\"Enter one or more rules to modify the active style.\" id=\"IwR-xy-eUH\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"Ut5-0A-XXN\" firstAttribute=\"top\" secondItem=\"vmy-l2-xRs\" secondAttribute=\"bottom\" constant=\"8\" id=\"5N9-Dz-gG6\"/>\n                    <constraint firstItem=\"oqB-ts-Ci1\" firstAttribute=\"firstBaseline\" secondItem=\"R62-Gq-GYv\" secondAttribute=\"firstBaseline\" id=\"5xO-qo-wNH\"/>\n                    <constraint firstItem=\"vmy-l2-xRs\" firstAttribute=\"leading\" secondItem=\"JXg-rs-7MF\" secondAttribute=\"leading\" id=\"8rS-49-fDE\"/>\n                    <constraint firstItem=\"oqB-ts-Ci1\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"0hQ-Ce-Oet\" secondAttribute=\"leading\" constant=\"20\" id=\"FhZ-B2-Axe\"/>\n                    <constraint firstItem=\"vmy-l2-xRs\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"JXg-rs-7MF\" secondAttribute=\"trailing\" constant=\"20\" id=\"JCZ-PF-xue\"/>\n                    <constraint firstItem=\"R62-Gq-GYv\" firstAttribute=\"leading\" secondItem=\"oqB-ts-Ci1\" secondAttribute=\"trailing\" constant=\"12\" id=\"MsP-Zb-EHv\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"R62-Gq-GYv\" secondAttribute=\"trailing\" constant=\"20\" id=\"Tg7-AS-xbN\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"R62-Gq-GYv\" secondAttribute=\"bottom\" constant=\"20\" id=\"cAg-fH-npM\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Ut5-0A-XXN\" secondAttribute=\"trailing\" constant=\"20\" id=\"mEG-iM-XKX\"/>\n                    <constraint firstItem=\"vmy-l2-xRs\" firstAttribute=\"top\" secondItem=\"0hQ-Ce-Oet\" secondAttribute=\"top\" constant=\"20\" id=\"tSw-0D-FYZ\"/>\n                    <constraint firstItem=\"R62-Gq-GYv\" firstAttribute=\"top\" secondItem=\"Ut5-0A-XXN\" secondAttribute=\"bottom\" constant=\"20\" id=\"uxM-QX-Lul\"/>\n                    <constraint firstItem=\"Ut5-0A-XXN\" firstAttribute=\"leading\" secondItem=\"0hQ-Ce-Oet\" secondAttribute=\"leading\" constant=\"20\" id=\"vjZ-21-BFF\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"gEe-J5-PzQ\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"156\" y=\"69\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCProgressIndicatorSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCProgressIndicatorSheet\">\n            <connections>\n                <outlet property=\"progressIndicator\" destination=\"nX8-Wu-d5N\" id=\"dzn-Vg-Jb7\"/>\n                <outlet property=\"sheet\" destination=\"6sk-kp-nIv\" id=\"7Bv-gL-hkW\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"6sk-kp-nIv\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"406\" height=\"60\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"WV3-RL-BkV\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"406\" height=\"60\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <stackView distribution=\"equalSpacing\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"20\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"653-Q6-e7G\">\n                        <rect key=\"frame\" x=\"20\" y=\"14\" width=\"366\" height=\"32\"/>\n                        <subviews>\n                            <progressIndicator horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" maxValue=\"100\" bezeled=\"NO\" indeterminate=\"YES\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nX8-Wu-d5N\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"32\" height=\"32\"/>\n                            </progressIndicator>\n                            <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"44f-oq-qcQ\">\n                                <rect key=\"frame\" x=\"50\" y=\"8\" width=\"318\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Please wait a moment while this task is completed…\" id=\"Wtt-QE-OE3\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </subviews>\n                        <visibilityPriorities>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                        </visibilityPriorities>\n                        <customSpacing>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                        </customSpacing>\n                    </stackView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"653-Q6-e7G\" firstAttribute=\"centerX\" secondItem=\"WV3-RL-BkV\" secondAttribute=\"centerX\" id=\"LgP-DR-EUU\"/>\n                    <constraint firstItem=\"44f-oq-qcQ\" firstAttribute=\"centerY\" secondItem=\"WV3-RL-BkV\" secondAttribute=\"centerY\" id=\"UeS-oJ-78n\"/>\n                    <constraint firstItem=\"653-Q6-e7G\" firstAttribute=\"top\" secondItem=\"WV3-RL-BkV\" secondAttribute=\"top\" constant=\"14\" id=\"fIb-Tb-zyB\"/>\n                    <constraint firstItem=\"653-Q6-e7G\" firstAttribute=\"centerY\" secondItem=\"WV3-RL-BkV\" secondAttribute=\"centerY\" id=\"jDN-wc-LJJ\"/>\n                    <constraint firstItem=\"653-Q6-e7G\" firstAttribute=\"leading\" secondItem=\"WV3-RL-BkV\" secondAttribute=\"leading\" constant=\"20\" id=\"mmp-xu-oJn\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"394\" y=\"418\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCServerChangeNicknameSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCServerChangeNicknameSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"16\" id=\"41\"/>\n                <outlet property=\"okButton\" destination=\"15\" id=\"29\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"37\"/>\n                <outlet property=\"tnewNicknameTextField\" destination=\"9\" id=\"Q6Z-8O-jEC\"/>\n                <outlet property=\"toldNicknameTextField\" destination=\"8\" id=\"4GK-8k-7ol\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"765\" y=\"571\" width=\"350\" height=\"131\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1280\" height=\"720\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"350\" height=\"130\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nly-w9-qBD\">\n                        <rect key=\"frame\" x=\"20\" y=\"60\" width=\"310\" height=\"50\"/>\n                        <rows>\n                            <gridRow id=\"ppz-rq-TUu\"/>\n                            <gridRow id=\"dKL-HV-I1m\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn xPlacement=\"fill\" id=\"3xi-Rc-Hat\"/>\n                            <gridColumn xPlacement=\"fill\" id=\"6xP-6q-U70\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"ppz-rq-TUu\" column=\"3xi-Rc-Hat\" id=\"1bX-nw-L4J\">\n                                <textField key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"34\" width=\"116\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Current nickname:\" id=\"21\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"ppz-rq-TUu\" column=\"6xP-6q-U70\" id=\"3Ug-p0-42P\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8\">\n                                    <rect key=\"frame\" x=\"118\" y=\"34\" width=\"194\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Nickname\" id=\"22\">\n                                        <font key=\"font\" metaFont=\"systemBold\"/>\n                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"7\" id=\"vl7-Yc-7VP\"/>\n                                    </connections>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"dKL-HV-I1m\" column=\"3xi-Rc-Hat\" id=\"hFl-cB-10P\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"10\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"116\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"New nickname:\" id=\"24\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"dKL-HV-I1m\" column=\"6xP-6q-U70\" id=\"aU4-9P-AoB\">\n                                <textField key=\"contentView\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9\" customClass=\"TVCValidatedTextField\">\n                                    <rect key=\"frame\" x=\"120\" y=\"0.0\" width=\"190\" height=\"22\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"8PY-qp-M8c\"/>\n                                    </constraints>\n                                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"23\" customClass=\"TVCValidatedTextFieldCell\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                    </textFieldCell>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"10\" id=\"0D2-UX-54T\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"35\"/>\n                                    </connections>\n                                </textField>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"15\">\n                        <rect key=\"frame\" x=\"192\" y=\"13\" width=\"145\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Change Nickname\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"25\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Change Nickname\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"30\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"16\">\n                        <rect key=\"frame\" x=\"118\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"26\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"31\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"16\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"2bq-Vf-84Z\"/>\n                    <constraint firstItem=\"15\" firstAttribute=\"top\" secondItem=\"Nly-w9-qBD\" secondAttribute=\"bottom\" constant=\"20\" id=\"9zY-Yo-jjt\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Nly-w9-qBD\" secondAttribute=\"trailing\" constant=\"20\" id=\"CMh-bk-HPo\"/>\n                    <constraint firstItem=\"Nly-w9-qBD\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"Crq-ej-ThU\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"15\" secondAttribute=\"trailing\" constant=\"20\" id=\"K6U-kV-8HI\"/>\n                    <constraint firstItem=\"15\" firstAttribute=\"firstBaseline\" secondItem=\"16\" secondAttribute=\"firstBaseline\" id=\"SxL-Go-4Lh\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"15\" secondAttribute=\"bottom\" constant=\"20\" id=\"jHU-7O-esr\"/>\n                    <constraint firstItem=\"15\" firstAttribute=\"leading\" secondItem=\"16\" secondAttribute=\"trailing\" constant=\"12\" id=\"nvG-d0-F6m\"/>\n                    <constraint firstItem=\"Nly-w9-qBD\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"20\" id=\"zea-BU-g5k\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"36\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"407\" y=\"324\"/>\n        </window>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCServerChannelListDialog.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCServerChannelListDialog\">\n            <connections>\n                <outlet property=\"channelListController\" destination=\"gJL-Lo-AKT\" id=\"NLh-Wh-ISB\"/>\n                <outlet property=\"channelListTable\" destination=\"fir-Vj-Dlr\" id=\"GeF-8A-eTo\"/>\n                <outlet property=\"networkNameTextField\" destination=\"132\" id=\"GUU-qy-Vpo\"/>\n                <outlet property=\"searchTextField\" destination=\"103\" id=\"m09-ig-hTb\"/>\n                <outlet property=\"updateButton\" destination=\"76\" id=\"121\"/>\n                <outlet property=\"window\" destination=\"5\" id=\"128\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Channel List\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <rect key=\"contentRect\" x=\"934\" y=\"498\" width=\"600\" height=\"312\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"1024\" height=\"720\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"600\" height=\"312\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <scrollView wantsLayer=\"YES\" autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"m9z-1h-faf\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"48\" width=\"600\" height=\"220\"/>\n                        <clipView key=\"contentView\" id=\"6OO-R3-f55\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"598\" height=\"218\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" usesAutomaticRowHeights=\"YES\" headerView=\"XYU-kz-qVy\" viewBased=\"YES\" id=\"fir-Vj-Dlr\" customClass=\"TVCBasicTableView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"598\" height=\"190\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"channelName\" editable=\"NO\" width=\"111\" minWidth=\"40\" maxWidth=\"1000\" id=\"PaN-OT-TPX\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Channel Name\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"OgI-gX-mC8\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Channel Name\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"channelName\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"088-fI-26f\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"116\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LAi-KB-a4L\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"116\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"iAr-vI-1Jn\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"088-fI-26f\" name=\"value\" keyPath=\"objectValue.channelName\" id=\"mfe-UI-61a\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"LAi-KB-a4L\" firstAttribute=\"leading\" secondItem=\"088-fI-26f\" secondAttribute=\"leading\" constant=\"2\" id=\"WK6-jg-jz1\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"LAi-KB-a4L\" secondAttribute=\"bottom\" id=\"ax5-LK-kTV\"/>\n                                                        <constraint firstItem=\"LAi-KB-a4L\" firstAttribute=\"top\" secondItem=\"088-fI-26f\" secondAttribute=\"top\" id=\"y54-1Q-Sg8\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"LAi-KB-a4L\" secondAttribute=\"trailing\" constant=\"2\" id=\"zXk-hk-rBF\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"LAi-KB-a4L\" id=\"ZMa-Dd-YhQ\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"channelMemberCount\" editable=\"NO\" width=\"91\" minWidth=\"40\" maxWidth=\"1000\" id=\"iqK-MO-gQw\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Member Count\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"mMW-qu-HSl\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Member Count\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"channelMemberCount\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"65a-1B-tHU\">\n                                                    <rect key=\"frame\" x=\"120\" y=\"1\" width=\"91\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9UU-Fz-GXc\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"91\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"TaT-zx-zgK\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"65a-1B-tHU\" name=\"value\" keyPath=\"objectValue.channelMemberCount\" id=\"GP7-TZ-7DS\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"9UU-Fz-GXc\" firstAttribute=\"leading\" secondItem=\"65a-1B-tHU\" secondAttribute=\"leading\" constant=\"2\" id=\"8Gt-nD-wni\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"9UU-Fz-GXc\" secondAttribute=\"trailing\" constant=\"2\" id=\"feh-ef-O53\"/>\n                                                        <constraint firstItem=\"9UU-Fz-GXc\" firstAttribute=\"top\" secondItem=\"65a-1B-tHU\" secondAttribute=\"top\" id=\"i7n-zp-SeQ\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"9UU-Fz-GXc\" secondAttribute=\"bottom\" id=\"zkt-6R-1j3\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"9UU-Fz-GXc\" id=\"IdQ-tp-oeZ\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"channelTopic\" editable=\"NO\" width=\"378\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"exA-K8-ozT\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Topic\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"seI-iZ-zcH\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <accessibility description=\"Topic\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"caseInsensitiveCompare:\" sortKey=\"channelTopicUnformatted\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lXg-AU-UCu\">\n                                                    <rect key=\"frame\" x=\"214\" y=\"1\" width=\"382\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tvH-QA-89d\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"382\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" truncatesLastVisibleLine=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"oPQ-I2-Zqm\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"lXg-AU-UCu\" name=\"value\" keyPath=\"objectValue.channelTopicFormatted\" id=\"rGL-us-Xnl\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"tvH-QA-89d\" secondAttribute=\"bottom\" id=\"U1x-9f-JGE\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"tvH-QA-89d\" secondAttribute=\"trailing\" constant=\"2\" id=\"bhw-3W-lIw\"/>\n                                                        <constraint firstItem=\"tvH-QA-89d\" firstAttribute=\"top\" secondItem=\"lXg-AU-UCu\" secondAttribute=\"top\" id=\"cYv-ug-abn\"/>\n                                                        <constraint firstItem=\"tvH-QA-89d\" firstAttribute=\"leading\" secondItem=\"lXg-AU-UCu\" secondAttribute=\"leading\" constant=\"2\" id=\"fcG-Wn-GfG\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"tvH-QA-89d\" id=\"JKb-FS-GQW\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <binding destination=\"gJL-Lo-AKT\" name=\"content\" keyPath=\"arrangedObjects\" id=\"52X-ys-8XF\"/>\n                                        <binding destination=\"gJL-Lo-AKT\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"52X-ys-8XF\" id=\"zq3-si-kb2\"/>\n                                        <binding destination=\"gJL-Lo-AKT\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"zq3-si-kb2\" id=\"9Rn-KF-1bQ\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"agf-xc-8d4\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"rJx-Wd-ijQ\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"600\" id=\"fHu-ho-lZA\"/>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"220\" id=\"gad-i5-vCs\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"Zxi-WW-aZs\">\n                            <rect key=\"frame\" x=\"1\" y=\"203\" width=\"598\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"ZtW-M5-gFM\">\n                            <rect key=\"frame\" x=\"764\" y=\"16\" width=\"15\" height=\"230\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"XYU-kz-qVy\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"598\" height=\"28\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                        <accessibility description=\"Channel List\"/>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"74\">\n                        <rect key=\"frame\" x=\"517\" y=\"7\" width=\"70\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"111\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Close\"/>\n                        <connections>\n                            <action selector=\"onClose:\" target=\"-2\" id=\"123\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"76\">\n                        <rect key=\"frame\" x=\"415\" y=\"7\" width=\"104\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Update List\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"112\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Update List\"/>\n                        <connections>\n                            <action selector=\"onUpdate:\" target=\"-2\" id=\"122\"/>\n                        </connections>\n                    </button>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"132\">\n                        <rect key=\"frame\" x=\"18\" y=\"282\" width=\"108\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"My IRC Network\" id=\"133\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"139\">\n                        <rect key=\"frame\" x=\"13\" y=\"7\" width=\"176\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Join Selected Channels\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"140\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Join Selected Channels\"/>\n                        <connections>\n                            <action selector=\"onJoinChannels:\" target=\"-2\" id=\"142\"/>\n                        </connections>\n                    </button>\n                    <searchField wantsLayer=\"YES\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"103\">\n                        <rect key=\"frame\" x=\"380\" y=\"279\" width=\"200\" height=\"22\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"200\" id=\"fg4-E2-QNl\"/>\n                        </constraints>\n                        <searchFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" borderStyle=\"bezel\" bezelStyle=\"round\" sendsSearchStringImmediately=\"YES\" maximumRecents=\"0\" recentsAutosaveName=\"\" id=\"113\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </searchFieldCell>\n                        <accessibility description=\"Channel List Search\"/>\n                        <connections>\n                            <binding destination=\"gJL-Lo-AKT\" name=\"predicate\" keyPath=\"filterPredicate\" id=\"wAJ-2T-bDW\">\n                                <dictionary key=\"options\">\n                                    <string key=\"NSDisplayName\">predicate</string>\n                                    <string key=\"NSPredicateFormat\">(channelName contains[c] $value OR channelTopicUnformatted contains[c] $value)</string>\n                                </dictionary>\n                            </binding>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"105\"/>\n                        </connections>\n                    </searchField>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"74\" secondAttribute=\"bottom\" constant=\"14\" id=\"2TH-qs-jWK\"/>\n                    <constraint firstItem=\"132\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"14\" id=\"Bt8-hJ-xrj\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"103\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"Cz5-Bb-inG\"/>\n                    <constraint firstItem=\"103\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"132\" secondAttribute=\"trailing\" constant=\"20\" id=\"Few-xO-gBE\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"74\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ku9-ei-0zH\"/>\n                    <constraint firstItem=\"74\" firstAttribute=\"leading\" secondItem=\"76\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"NqQ-Of-1y7\"/>\n                    <constraint firstItem=\"139\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" id=\"Qca-Mp-mnz\"/>\n                    <constraint firstItem=\"76\" firstAttribute=\"firstBaseline\" secondItem=\"74\" secondAttribute=\"firstBaseline\" id=\"ew2-ax-kv3\"/>\n                    <constraint firstItem=\"m9z-1h-faf\" firstAttribute=\"top\" secondItem=\"132\" secondAttribute=\"bottom\" constant=\"14\" id=\"fpy-Fb-loa\"/>\n                    <constraint firstItem=\"103\" firstAttribute=\"centerY\" secondItem=\"132\" secondAttribute=\"centerY\" id=\"hMc-j2-bmX\"/>\n                    <constraint firstItem=\"74\" firstAttribute=\"top\" secondItem=\"m9z-1h-faf\" secondAttribute=\"bottom\" constant=\"14\" id=\"jy2-r7-H7m\"/>\n                    <constraint firstItem=\"m9z-1h-faf\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" id=\"nw8-14-FJp\"/>\n                    <constraint firstItem=\"132\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"od9-bj-Cfd\"/>\n                    <constraint firstItem=\"m9z-1h-faf\" firstAttribute=\"centerX\" secondItem=\"6\" secondAttribute=\"centerX\" id=\"t1H-hc-5Wj\"/>\n                    <constraint firstItem=\"76\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"139\" secondAttribute=\"trailing\" constant=\"20\" id=\"vWb-Qf-IzU\"/>\n                    <constraint firstItem=\"139\" firstAttribute=\"firstBaseline\" secondItem=\"76\" secondAttribute=\"firstBaseline\" id=\"vck-zb-Gav\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"118\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"496\" y=\"415\"/>\n        </window>\n        <arrayController objectClassName=\"TDCServerChannelListDialogEntry\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" clearsFilterPredicateOnInsertion=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"gJL-Lo-AKT\">\n            <declaredKeys>\n                <string>channelName</string>\n                <string>channelMemberCount</string>\n                <string>channelTopicFormatted</string>\n                <string>channelTopicUnformatted</string>\n            </declaredKeys>\n        </arrayController>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCServerEndpointListSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCServerEndpointListSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"xvV-vQ-BBH\" id=\"vaM-81-VRg\"/>\n                <outlet property=\"entryActionsSegmentedControl\" destination=\"ThC-su-OJ3\" id=\"IaG-5n-oiX\"/>\n                <outlet property=\"entryTable\" destination=\"gbv-2u-rHi\" id=\"ODa-gE-K7o\"/>\n                <outlet property=\"entryTableController\" destination=\"Cq5-Tc-eTe\" id=\"zjK-p9-tl5\"/>\n                <outlet property=\"okButton\" destination=\"8yj-vj-S3P\" id=\"sf1-0X-duu\"/>\n                <outlet property=\"sheet\" destination=\"223-Sc-uJ1\" id=\"JjV-WQ-uF6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <arrayController objectClassName=\"IRCServerMutable\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"Cq5-Tc-eTe\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"223-Sc-uJ1\" userLabel=\"Alternate Servers\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"213\" width=\"695\" height=\"326\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <view key=\"contentView\" id=\"rOf-7y-CFb\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"695\" height=\"358\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <segmentedControl verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ThC-su-OJ3\">\n                        <rect key=\"frame\" x=\"17\" y=\"12\" width=\"71\" height=\"24\"/>\n                        <segmentedCell key=\"cell\" borderStyle=\"border\" alignment=\"left\" style=\"rounded\" trackingMode=\"momentary\" id=\"dUS-P9-b7z\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <segments>\n                                <segment image=\"NSAddTemplate\" width=\"32\"/>\n                                <segment image=\"NSRemoveTemplate\" width=\"32\" tag=\"1\"/>\n                            </segments>\n                        </segmentedCell>\n                        <accessibility description=\"Add Entry or Remove Entry\"/>\n                        <connections>\n                            <action selector=\"entryActionsSegmentedControlClicked:\" target=\"-2\" id=\"mor-eT-ZoC\"/>\n                        </connections>\n                    </segmentedControl>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pOF-VD-WZg\">\n                        <rect key=\"frame\" x=\"18\" y=\"296\" width=\"659\" height=\"48\"/>\n                        <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"qeA-Ep-V8r\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"title\">The order of this table, from top to bottom, determines the order in which Textual connects to each server.  Drag and drop servers to change the order. The top-most server is always the primary.</string>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"18\" horizontalPageScroll=\"10\" verticalLineScroll=\"18\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4Gy-fQ-L47\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"48\" width=\"695\" height=\"234\"/>\n                        <clipView key=\"contentView\" id=\"gPE-lA-8q0\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"693\" height=\"232\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" alternatingRowBackgroundColors=\"YES\" autosaveColumns=\"NO\" rowHeight=\"16\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" headerView=\"kSR-Qb-wye\" viewBased=\"YES\" id=\"gbv-2u-rHi\" customClass=\"TVCBasicTableView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"693\" height=\"204\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"serverAddress\" width=\"278\" minWidth=\"40\" maxWidth=\"1000\" id=\"3Rd-8U-Cxh\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Server Address\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"vfj-CR-Lov\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rBl-zY-fY2\" customClass=\"TDCServerEndpointListSheetTableCellView\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"283\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField identifier=\"serverAddressTextField\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NZ5-1k-jqr\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"283\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"irc.example.com\" id=\"DC0-dd-X4r\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Server Address\"/>\n                                                            <connections>\n                                                                <binding destination=\"rBl-zY-fY2\" name=\"value\" keyPath=\"serverAddress\" id=\"HuD-zu-joo\">\n                                                                    <dictionary key=\"options\">\n                                                                        <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                                    </dictionary>\n                                                                </binding>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"NZ5-1k-jqr\" firstAttribute=\"top\" secondItem=\"rBl-zY-fY2\" secondAttribute=\"top\" id=\"Duw-IC-XbN\"/>\n                                                        <constraint firstItem=\"NZ5-1k-jqr\" firstAttribute=\"leading\" secondItem=\"rBl-zY-fY2\" secondAttribute=\"leading\" constant=\"2\" id=\"FxW-Hs-Yna\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"NZ5-1k-jqr\" secondAttribute=\"bottom\" id=\"w96-s0-eK9\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"NZ5-1k-jqr\" secondAttribute=\"trailing\" constant=\"2\" id=\"wuc-kK-Fvy\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"NZ5-1k-jqr\" id=\"ciU-kB-gAm\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"serverPort\" width=\"85\" minWidth=\"85\" maxWidth=\"85\" id=\"W8o-NA-OQA\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Server Port\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"M7E-PR-Kbt\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SNH-fJ-rxe\" customClass=\"TDCServerEndpointListSheetTableCellView\">\n                                                    <rect key=\"frame\" x=\"287\" y=\"1\" width=\"85\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField identifier=\"serverPortTextField\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"N3x-SV-fcf\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"85\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"65535\" id=\"llo-Jr-fJz\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Server Port\"/>\n                                                            <connections>\n                                                                <binding destination=\"SNH-fJ-rxe\" name=\"value\" keyPath=\"serverPort\" id=\"AHi-3o-OL1\">\n                                                                    <dictionary key=\"options\">\n                                                                        <bool key=\"NSValidatesImmediately\" value=\"YES\"/>\n                                                                    </dictionary>\n                                                                </binding>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"N3x-SV-fcf\" firstAttribute=\"top\" secondItem=\"SNH-fJ-rxe\" secondAttribute=\"top\" id=\"aDV-Mp-lUR\"/>\n                                                        <constraint firstItem=\"N3x-SV-fcf\" firstAttribute=\"leading\" secondItem=\"SNH-fJ-rxe\" secondAttribute=\"leading\" constant=\"2\" id=\"bab-fQ-8p0\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"N3x-SV-fcf\" secondAttribute=\"bottom\" id=\"dJ0-MF-n15\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"N3x-SV-fcf\" secondAttribute=\"trailing\" constant=\"2\" id=\"q28-tx-SXP\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"N3x-SV-fcf\" id=\"yhX-TN-xSp\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"prefersSecuredConnection\" width=\"100\" minWidth=\"100\" maxWidth=\"100\" id=\"cqT-uh-Sy9\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Connect Securely\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"AuZ-P5-4ZF\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <string key=\"headerToolTip\">Attempt to secure the connection by performing a Transport Layer Security (TLS) negotiation. TLS is the modern equivalent of SSL (Secure Sockets Layer)</string>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vQA-g2-tD4\" customClass=\"TDCServerEndpointListSheetTableCellView\">\n                                                    <rect key=\"frame\" x=\"375\" y=\"1\" width=\"100\" height=\"17\"/>\n                                                    <subviews>\n                                                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jha-5I-0JH\">\n                                                            <rect key=\"frame\" x=\"41\" y=\"0.0\" width=\"18\" height=\"18\"/>\n                                                            <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"ik6-LW-mE0\">\n                                                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                            </buttonCell>\n                                                            <accessibility description=\"Connect Securely\"/>\n                                                            <connections>\n                                                                <binding destination=\"vQA-g2-tD4\" name=\"value\" keyPath=\"prefersSecuredConnection\" id=\"ETO-vb-Siw\"/>\n                                                            </connections>\n                                                        </button>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"Jha-5I-0JH\" firstAttribute=\"centerX\" secondItem=\"vQA-g2-tD4\" secondAttribute=\"centerX\" id=\"EdS-td-inM\"/>\n                                                        <constraint firstItem=\"Jha-5I-0JH\" firstAttribute=\"top\" secondItem=\"vQA-g2-tD4\" secondAttribute=\"top\" constant=\"1\" id=\"PiL-3s-6u2\"/>\n                                                    </constraints>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"serverPassword\" width=\"209\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" headerToolTip=\"Password to be sent using the PASS command. This is NOT your password for NickServ.\" id=\"RDl-mf-DIn\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Server Password\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"eOR-Yk-u79\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hJg-qX-ZVv\" customClass=\"TDCServerEndpointListSheetTableCellView\">\n                                                    <rect key=\"frame\" x=\"478\" y=\"1\" width=\"213\" height=\"16\"/>\n                                                    <subviews>\n                                                        <secureTextField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cB8-GH-3UE\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"213\" height=\"16\"/>\n                                                            <secureTextFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"YHA-fW-1Az\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <allowedInputSourceLocales>\n                                                                    <string>NSAllRomanInputSourcesLocaleIdentifier</string>\n                                                                </allowedInputSourceLocales>\n                                                            </secureTextFieldCell>\n                                                            <accessibility description=\"Server Password\"/>\n                                                            <connections>\n                                                                <binding destination=\"hJg-qX-ZVv\" name=\"value\" keyPath=\"serverPassword\" id=\"gxH-wC-xIT\"/>\n                                                            </connections>\n                                                        </secureTextField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"cB8-GH-3UE\" firstAttribute=\"leading\" secondItem=\"hJg-qX-ZVv\" secondAttribute=\"leading\" constant=\"2\" id=\"0Qg-W7-46R\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"cB8-GH-3UE\" secondAttribute=\"trailing\" constant=\"2\" id=\"END-a1-z4s\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"cB8-GH-3UE\" secondAttribute=\"bottom\" id=\"cso-PW-6b3\"/>\n                                                        <constraint firstItem=\"cB8-GH-3UE\" firstAttribute=\"top\" secondItem=\"hJg-qX-ZVv\" secondAttribute=\"top\" id=\"lhk-D7-uBN\"/>\n                                                    </constraints>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <accessibility description=\"Server List\"/>\n                                    <connections>\n                                        <binding destination=\"Cq5-Tc-eTe\" name=\"content\" keyPath=\"arrangedObjects\" id=\"DId-eq-eOU\"/>\n                                        <binding destination=\"Cq5-Tc-eTe\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"DId-eq-eOU\" id=\"Nbn-NS-kCL\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"f1X-tB-ald\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"wsM-bn-5m5\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"234\" id=\"1qX-UJ-yt8\"/>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"600\" id=\"GlZ-te-D98\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"40M-Hd-Yvu\">\n                            <rect key=\"frame\" x=\"1\" y=\"217\" width=\"693\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"CI1-ir-VDh\">\n                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"kSR-Qb-wye\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"693\" height=\"28\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xvV-vQ-BBH\">\n                        <rect key=\"frame\" x=\"544\" y=\"7\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"uLP-la-kWC\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"ztf-N5-eU7\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8yj-vj-S3P\">\n                        <rect key=\"frame\" x=\"618\" y=\"7\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"8Fn-em-09T\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"XwI-bQ-MkI\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"8yj-vj-S3P\" secondAttribute=\"bottom\" constant=\"14\" id=\"3Lm-m1-SxN\"/>\n                    <constraint firstItem=\"8yj-vj-S3P\" firstAttribute=\"top\" secondItem=\"4Gy-fQ-L47\" secondAttribute=\"bottom\" constant=\"14\" id=\"8pp-C2-M7v\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"pOF-VD-WZg\" secondAttribute=\"trailing\" constant=\"20\" id=\"DMO-j4-bjp\"/>\n                    <constraint firstItem=\"pOF-VD-WZg\" firstAttribute=\"leading\" secondItem=\"rOf-7y-CFb\" secondAttribute=\"leading\" constant=\"20\" id=\"EWm-cg-xPW\"/>\n                    <constraint firstItem=\"xvV-vQ-BBH\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"ThC-su-OJ3\" secondAttribute=\"trailing\" constant=\"20\" id=\"Eqv-6V-D5t\"/>\n                    <constraint firstItem=\"4Gy-fQ-L47\" firstAttribute=\"top\" secondItem=\"pOF-VD-WZg\" secondAttribute=\"bottom\" constant=\"14\" id=\"LMR-wr-Rxa\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"4Gy-fQ-L47\" secondAttribute=\"trailing\" id=\"PVF-ga-z6L\"/>\n                    <constraint firstItem=\"ThC-su-OJ3\" firstAttribute=\"leading\" secondItem=\"rOf-7y-CFb\" secondAttribute=\"leading\" constant=\"20\" id=\"T03-Wi-3PA\"/>\n                    <constraint firstItem=\"pOF-VD-WZg\" firstAttribute=\"top\" secondItem=\"rOf-7y-CFb\" secondAttribute=\"top\" constant=\"14\" id=\"fTm-yf-ce7\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"ThC-su-OJ3\" secondAttribute=\"bottom\" constant=\"14\" id=\"hm5-rL-vUR\"/>\n                    <constraint firstItem=\"8yj-vj-S3P\" firstAttribute=\"leading\" secondItem=\"xvV-vQ-BBH\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"hnh-6u-e16\"/>\n                    <constraint firstItem=\"xvV-vQ-BBH\" firstAttribute=\"firstBaseline\" secondItem=\"8yj-vj-S3P\" secondAttribute=\"firstBaseline\" id=\"l5E-db-ucq\"/>\n                    <constraint firstItem=\"ThC-su-OJ3\" firstAttribute=\"top\" secondItem=\"4Gy-fQ-L47\" secondAttribute=\"bottom\" constant=\"14\" id=\"r4Z-jy-Wv6\"/>\n                    <constraint firstItem=\"4Gy-fQ-L47\" firstAttribute=\"leading\" secondItem=\"rOf-7y-CFb\" secondAttribute=\"leading\" id=\"yEg-C6-EQz\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"8yj-vj-S3P\" secondAttribute=\"trailing\" constant=\"20\" id=\"zLI-ex-3ov\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"Ng7-YB-dWH\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"2497.5\" y=\"948.5\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"15\" height=\"13\"/>\n        <image name=\"NSRemoveTemplate\" width=\"15\" height=\"4\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCServerHighlightListSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCServerHighlightListSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"248\" id=\"283\"/>\n                <outlet property=\"headerTitleTextField\" destination=\"249\" id=\"TUM-zE-uVx\"/>\n                <outlet property=\"highlightListController\" destination=\"5mx-Dm-tKI\" id=\"cnS-P6-nfo\"/>\n                <outlet property=\"highlightListTable\" destination=\"255\" id=\"286\"/>\n                <outlet property=\"okButton\" destination=\"248\" id=\"287\"/>\n                <outlet property=\"sheet\" destination=\"243\" id=\"288\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"243\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" resizable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"196\" y=\"160\" width=\"164\" height=\"162\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1440\"/>\n            <value key=\"maxSize\" type=\"size\" width=\"1024\" height=\"720\"/>\n            <view key=\"contentView\" id=\"244\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"650\" height=\"322\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <scrollView wantsLayer=\"YES\" autohidesScrollers=\"YES\" horizontalLineScroll=\"18\" horizontalPageScroll=\"10\" verticalLineScroll=\"18\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"246\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"40\" width=\"650\" height=\"240\"/>\n                        <clipView key=\"contentView\" id=\"xsl-1y-XOT\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"648\" height=\"238\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                            <subviews>\n                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowHeight=\"16\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" headerView=\"OL3-le-5Xg\" viewBased=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"255\" customClass=\"TVCBasicTableView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"648\" height=\"210\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"channelName\" editable=\"NO\" width=\"97\" minWidth=\"40\" maxWidth=\"1000\" id=\"257\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Channel Name\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" alignment=\"left\" title=\"Text Cell\" id=\"262\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"caseInsensitiveCompare:\" sortKey=\"channelName\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PzI-yP-71o\">\n                                                    <rect key=\"frame\" x=\"1\" y=\"1\" width=\"102\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"a2j-l0-XuC\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"102\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"81x-z5-fVG\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Channel Name\"/>\n                                                            <connections>\n                                                                <binding destination=\"PzI-yP-71o\" name=\"value\" keyPath=\"objectValue.channelName\" id=\"IRo-Fj-e9u\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"a2j-l0-XuC\" firstAttribute=\"leading\" secondItem=\"PzI-yP-71o\" secondAttribute=\"leading\" constant=\"2\" id=\"3Gq-t8-OjU\"/>\n                                                        <constraint firstItem=\"a2j-l0-XuC\" firstAttribute=\"top\" secondItem=\"PzI-yP-71o\" secondAttribute=\"top\" id=\"Jbt-6A-PUw\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"a2j-l0-XuC\" secondAttribute=\"bottom\" id=\"fEm-us-UnI\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"a2j-l0-XuC\" secondAttribute=\"trailing\" constant=\"2\" id=\"i4Q-5d-zjv\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"a2j-l0-XuC\" id=\"hua-YF-yl6\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"renderedMessage\" width=\"417\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"264\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Message\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" alignment=\"left\" title=\"Text Cell\" id=\"265\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView identifier=\"renderedMessage\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EgS-Pq-f28\">\n                                                    <rect key=\"frame\" x=\"106\" y=\"1\" width=\"417\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4NS-3M-szX\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"417\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" truncatesLastVisibleLine=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"tu1-iW-sWg\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Original Message\"/>\n                                                            <connections>\n                                                                <binding destination=\"EgS-Pq-f28\" name=\"value\" keyPath=\"objectValue.renderedMessage\" id=\"LvU-FV-bn6\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"4NS-3M-szX\" secondAttribute=\"trailing\" constant=\"2\" id=\"05Z-Rn-0qn\"/>\n                                                        <constraint firstItem=\"4NS-3M-szX\" firstAttribute=\"leading\" secondItem=\"EgS-Pq-f28\" secondAttribute=\"leading\" constant=\"2\" id=\"GK1-od-It4\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"4NS-3M-szX\" secondAttribute=\"bottom\" id=\"Ppz-GB-IIA\"/>\n                                                        <constraint firstItem=\"4NS-3M-szX\" firstAttribute=\"top\" secondItem=\"EgS-Pq-f28\" secondAttribute=\"top\" id=\"j6S-Sa-HcC\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"4NS-3M-szX\" id=\"R6J-wU-tvK\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                        <tableColumn identifier=\"timeLogged\" editable=\"NO\" width=\"115.56134033203125\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"259\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Time\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" alignment=\"left\" title=\"Text Cell\" id=\"260\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <sortDescriptor key=\"sortDescriptorPrototype\" selector=\"compare:\" sortKey=\"timeLogged\"/>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HW9-VK-fBZ\">\n                                                    <rect key=\"frame\" x=\"526\" y=\"1\" width=\"120\" height=\"16\"/>\n                                                    <subviews>\n                                                        <textField horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5km-53-sUf\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"120\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"fvp-ca-N2k\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <accessibility description=\"Time\"/>\n                                                            <connections>\n                                                                <binding destination=\"HW9-VK-fBZ\" name=\"value\" keyPath=\"objectValue.timeLoggedFormatted\" id=\"yFW-sb-DFV\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"5km-53-sUf\" secondAttribute=\"bottom\" id=\"4iI-8W-qGW\"/>\n                                                        <constraint firstItem=\"5km-53-sUf\" firstAttribute=\"top\" secondItem=\"HW9-VK-fBZ\" secondAttribute=\"top\" id=\"Hci-4P-abe\"/>\n                                                        <constraint firstItem=\"5km-53-sUf\" firstAttribute=\"leading\" secondItem=\"HW9-VK-fBZ\" secondAttribute=\"leading\" constant=\"2\" id=\"jih-nP-kyk\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"5km-53-sUf\" secondAttribute=\"trailing\" constant=\"2\" id=\"xEX-78-WMe\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"5km-53-sUf\" id=\"vCE-iI-gqx\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <binding destination=\"5mx-Dm-tKI\" name=\"content\" keyPath=\"arrangedObjects\" id=\"M5g-wY-hdp\"/>\n                                        <binding destination=\"5mx-Dm-tKI\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"M5g-wY-hdp\" id=\"rvL-gc-QAb\"/>\n                                        <binding destination=\"5mx-Dm-tKI\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"rvL-gc-QAb\" id=\"per-fb-UTI\"/>\n                                        <outlet property=\"dataSource\" destination=\"-2\" id=\"275\"/>\n                                        <outlet property=\"delegate\" destination=\"-2\" id=\"276\"/>\n                                    </connections>\n                                </tableView>\n                            </subviews>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"650\" id=\"VST-Jv-89L\"/>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"240\" id=\"bBU-Jp-427\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"254\">\n                            <rect key=\"frame\" x=\"1\" y=\"232\" width=\"646\" height=\"16\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"253\">\n                            <rect key=\"frame\" x=\"764\" y=\"16\" width=\"15\" height=\"230\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"OL3-le-5Xg\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"648\" height=\"28\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </tableHeaderView>\n                        <accessibility description=\"Highlight List\"/>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"247\">\n                        <rect key=\"frame\" x=\"477\" y=\"3\" width=\"92\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Clear List\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"252\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Clear List\"/>\n                        <connections>\n                            <action selector=\"onClearList:\" target=\"-2\" id=\"284\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"248\">\n                        <rect key=\"frame\" x=\"567\" y=\"3\" width=\"70\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Close\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"251\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Close\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"282\"/>\n                        </connections>\n                    </button>\n                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"249\">\n                        <rect key=\"frame\" x=\"18\" y=\"293\" width=\"180\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"List of Highlights for &quot;%@&quot;\" id=\"250\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"277\">\n                        <rect key=\"frame\" x=\"18\" y=\"12\" width=\"351\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Messages that begin with a bullet (•) represent an action.\" id=\"278\">\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"277\" firstAttribute=\"leading\" secondItem=\"244\" secondAttribute=\"leading\" constant=\"20\" id=\"9QX-LB-5Wf\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"249\" secondAttribute=\"trailing\" constant=\"20\" id=\"Icy-sJ-SEY\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"248\" secondAttribute=\"bottom\" constant=\"10\" id=\"Qlf-2Y-QUR\"/>\n                    <constraint firstItem=\"247\" firstAttribute=\"firstBaseline\" secondItem=\"248\" secondAttribute=\"firstBaseline\" id=\"R8L-kg-ypT\"/>\n                    <constraint firstItem=\"248\" firstAttribute=\"leading\" secondItem=\"247\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"UhY-2I-PFH\"/>\n                    <constraint firstItem=\"277\" firstAttribute=\"centerY\" secondItem=\"247\" secondAttribute=\"centerY\" id=\"dle-O4-bMh\"/>\n                    <constraint firstItem=\"247\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"277\" secondAttribute=\"trailing\" constant=\"20\" id=\"dys-lh-nPv\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"248\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"iFS-I2-HQM\"/>\n                    <constraint firstItem=\"246\" firstAttribute=\"centerX\" secondItem=\"244\" secondAttribute=\"centerX\" id=\"n2A-Ou-C5Z\"/>\n                    <constraint firstItem=\"249\" firstAttribute=\"top\" secondItem=\"244\" secondAttribute=\"top\" constant=\"13\" id=\"oHc-Jd-kBt\"/>\n                    <constraint firstItem=\"249\" firstAttribute=\"leading\" secondItem=\"244\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"oYF-cz-qoa\"/>\n                    <constraint firstItem=\"248\" firstAttribute=\"top\" secondItem=\"246\" secondAttribute=\"bottom\" constant=\"10\" id=\"ocI-Av-3pC\"/>\n                    <constraint firstItem=\"246\" firstAttribute=\"top\" secondItem=\"249\" secondAttribute=\"bottom\" constant=\"13\" id=\"rvE-Lq-nus\"/>\n                    <constraint firstItem=\"246\" firstAttribute=\"leading\" secondItem=\"244\" secondAttribute=\"leading\" id=\"ypx-IL-Ez0\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"289\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-57\" y=\"-290\"/>\n        </window>\n        <arrayController objectClassName=\"IRCHighlightLogEntry\" preservesSelection=\"NO\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"5mx-Dm-tKI\">\n            <declaredKeys>\n                <string>channelName</string>\n                <string>renderedMessage</string>\n                <string>timeLoggedFormatted</string>\n            </declaredKeys>\n        </arrayController>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCServerPropertiesSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23077.2\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23077.2\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCServerPropertiesSheet\">\n            <connections>\n                <outlet property=\"addAddressBookEntryButton\" destination=\"1843\" id=\"Yfy-Fb-eH2\"/>\n                <outlet property=\"addAddressBookEntryMenu\" destination=\"yYJ-qd-Dm2\" id=\"cVa-bu-jqf\"/>\n                <outlet property=\"addChannelButton\" destination=\"1794\" id=\"1947\"/>\n                <outlet property=\"addHighlightButton\" destination=\"2449\" id=\"2478\"/>\n                <outlet property=\"addressBookArrayController\" destination=\"aez-lt-zBV\" id=\"BOQ-aO-HOI\"/>\n                <outlet property=\"addressBookTable\" destination=\"1851\" id=\"wZ4-il-0gh\"/>\n                <outlet property=\"alternateNicknamesTextField\" destination=\"1602\" id=\"vN7-KA-LFN\"/>\n                <outlet property=\"autoConnectCheck\" destination=\"1531\" id=\"1935\"/>\n                <outlet property=\"autoDisconnectOnSleepCheck\" destination=\"2250\" id=\"2253\"/>\n                <outlet property=\"autoReconnectCheck\" destination=\"1532\" id=\"1936\"/>\n                <outlet property=\"autojoinWaitsForNickServCheck\" destination=\"B1u-e0-30u\" id=\"44s-dS-Pu5\"/>\n                <outlet property=\"awayNicknameTextField\" destination=\"2335\" id=\"eE8-0s-KKE\"/>\n                <outlet property=\"cancelButton\" destination=\"1456\" id=\"1463\"/>\n                <outlet property=\"channelListArrayController\" destination=\"XlX-J4-ZJt\" id=\"EMw-nK-7vi\"/>\n                <outlet property=\"channelListTable\" destination=\"1805\" id=\"ex0-5N-btj\"/>\n                <outlet property=\"clientCertificateChangeCertificateButton\" destination=\"l36-PJ-JBU\" id=\"vUq-tL-9aS\"/>\n                <outlet property=\"clientCertificateCommonNameField\" destination=\"nly-3d-FIq\" id=\"OGc-7I-cMH\"/>\n                <outlet property=\"clientCertificateMD5FingerprintCopyButton\" destination=\"KJ9-QR-tAv\" id=\"xCY-zF-PWK\"/>\n                <outlet property=\"clientCertificateMD5FingerprintField\" destination=\"Grr-p8-MOF\" id=\"E7G-dk-8gX\"/>\n                <outlet property=\"clientCertificateResetCertificateButton\" destination=\"sab-tw-7nn\" id=\"dNc-7S-cf1\"/>\n                <outlet property=\"clientCertificateSHA1FingerprintCopyButton\" destination=\"f9F-WF-ubf\" id=\"e62-bc-Pb2\"/>\n                <outlet property=\"clientCertificateSHA1FingerprintField\" destination=\"nFm-83-7HQ\" id=\"8QY-ha-rQf\"/>\n                <outlet property=\"clientCertificateSHA2FingerprintCopyButton\" destination=\"758-2B-Ka3\" id=\"zlF-cP-CFR\"/>\n                <outlet property=\"clientCertificateSHA2FingerprintField\" destination=\"2ie-9H-xb2\" id=\"D1L-7P-ktW\"/>\n                <outlet property=\"clientCertificateSHA512FingerprintCopyButton\" destination=\"YAo-Ly-Sf7\" id=\"sHk-oB-HCl\"/>\n                <outlet property=\"clientCertificateSHA512FingerprintField\" destination=\"Ou1-Bl-kz1\" id=\"V4S-rO-XS4\"/>\n                <outlet property=\"connectCommandsField\" destination=\"2310\" id=\"2Ht-9D-ef5\"/>\n                <outlet property=\"connectionDefaultAddressTypeCheck\" destination=\"zOI-7i-HTQ\" id=\"atT-V9-DBS\"/>\n                <outlet property=\"connectionIPv4AddressTypeCheck\" destination=\"Doi-rA-9aF\" id=\"wyV-Fd-Ii1\"/>\n                <outlet property=\"connectionIPv6AddressTypeCheck\" destination=\"dd4-fZ-E2b\" id=\"6Eh-9M-sx5\"/>\n                <outlet property=\"connectionNameTextField\" destination=\"1539\" id=\"f2G-5T-09V\"/>\n                <outlet property=\"contentViewAddressBook\" destination=\"1817\" id=\"d5R-wV-sv5\"/>\n                <outlet property=\"contentViewAutojoin\" destination=\"1738\" id=\"GdW-S9-Mmc\"/>\n                <outlet property=\"contentViewClientCertificate\" destination=\"Ti4-Q4-cYX\" id=\"dRg-gZ-hNm\"/>\n                <outlet property=\"contentViewConnectCommands\" destination=\"1860\" id=\"dva-TR-IFP\"/>\n                <outlet property=\"contentViewDisconnectMessages\" destination=\"1627\" id=\"gWi-wY-SNi\"/>\n                <outlet property=\"contentViewEncoding\" destination=\"1675\" id=\"m4X-ZN-3GX\"/>\n                <outlet property=\"contentViewFloodControl\" destination=\"2078\" id=\"FYp-t2-8yg\"/>\n                <outlet property=\"contentViewGeneral\" destination=\"1469\" id=\"USi-gD-XZz\"/>\n                <outlet property=\"contentViewHighlights\" destination=\"2445\" id=\"9h8-1O-lMv\"/>\n                <outlet property=\"contentViewIdentity\" destination=\"1563\" id=\"J9a-mN-3KM\"/>\n                <outlet property=\"contentViewNetworkSocket\" destination=\"2488\" id=\"x1c-Rp-XjX\"/>\n                <outlet property=\"contentViewProxyServer\" destination=\"1887\" id=\"Y6r-hB-Lvd\"/>\n                <outlet property=\"contentViewProxyServerInputView\" destination=\"KJ6-gu-xq3\" id=\"KFA-jY-wHm\"/>\n                <outlet property=\"contentViewProxyServerSystemSocksView\" destination=\"GFp-Qd-4ck\" id=\"i2R-4V-oBi\"/>\n                <outlet property=\"contentViewProxyServerTorBrowserView\" destination=\"yql-kd-PP5\" id=\"uIe-fo-kbw\"/>\n                <outlet property=\"contentViewRedundancy\" destination=\"O3J-xl-nwg\" id=\"cB8-PX-TAQ\"/>\n                <outlet property=\"contentViewZncBouncer\" destination=\"2542\" id=\"qzo-1Y-6rw\"/>\n                <outlet property=\"deleteAddressBookEntryButton\" destination=\"1845\" id=\"YMJ-qA-DaM\"/>\n                <outlet property=\"deleteChannelButton\" destination=\"1796\" id=\"1948\"/>\n                <outlet property=\"deleteHighlightButton\" destination=\"2447\" id=\"2477\"/>\n                <outlet property=\"disconnectOnReachabilityChangeCheck\" destination=\"w5K-aH-URS\" id=\"8N7-xY-lax\"/>\n                <outlet property=\"editAddressBookEntryButton\" destination=\"1844\" id=\"LTq-3U-HnM\"/>\n                <outlet property=\"editChannelButton\" destination=\"1795\" id=\"1949\"/>\n                <outlet property=\"editHighlightButton\" destination=\"2448\" id=\"2476\"/>\n                <outlet property=\"fallbackEncodingButton\" destination=\"1685\" id=\"2275\"/>\n                <outlet property=\"floodControlDelayTimerSlider\" destination=\"O6l-eN-3Uc\" id=\"l2j-Kb-PsN\"/>\n                <outlet property=\"floodControlMessageCountSlider\" destination=\"RXW-HB-aEa\" id=\"whf-jb-XgS\"/>\n                <outlet property=\"hideAutojoinDelayedWarningsCheck\" destination=\"ptP-ZP-JAf\" id=\"LXI-a8-mzH\"/>\n                <outlet property=\"highlightListArrayController\" destination=\"XVW-tl-Aro\" id=\"yo0-76-qlh\"/>\n                <outlet property=\"highlightsTable\" destination=\"2454\" id=\"2474\"/>\n                <outlet property=\"navigationOutlineView\" destination=\"Uj0-Wm-eox\" id=\"9jc-dy-sjg\"/>\n                <outlet property=\"nicknamePasswordTextField\" destination=\"1601\" id=\"i9R-Eg-aTO\"/>\n                <outlet property=\"nicknameTextField\" destination=\"1595\" id=\"BL9-gX-P5G\"/>\n                <outlet property=\"normalLeavingCommentTextField\" destination=\"2290\" id=\"Fhf-Py-Njw\"/>\n                <outlet property=\"okButton\" destination=\"1455\" id=\"1464\"/>\n                <outlet property=\"performDisconnectOnPongTimerCheck\" destination=\"2536\" id=\"rFn-Dj-NOb\"/>\n                <outlet property=\"pongTimerCheck\" destination=\"2531\" id=\"2541\"/>\n                <outlet property=\"preferredCipherSuitesButton\" destination=\"xo6-bb-4qn\" id=\"nt3-Ps-mHp\"/>\n                <outlet property=\"prefersSecuredConnectionCheck\" destination=\"1545\" id=\"yZI-S9-E8V\"/>\n                <outlet property=\"primaryEncodingButton\" destination=\"1684\" id=\"2276\"/>\n                <outlet property=\"proxyAddressTextField\" destination=\"1901\" id=\"RIc-hP-gu6\"/>\n                <outlet property=\"proxyPasswordTextField\" destination=\"1902\" id=\"yHw-1g-b0t\"/>\n                <outlet property=\"proxyPortTextField\" destination=\"84A-gQ-HPC\" id=\"6IV-ig-nxs\"/>\n                <outlet property=\"proxyTypeButton\" destination=\"1905\" id=\"2279\"/>\n                <outlet property=\"proxyUsernameTextField\" destination=\"1904\" id=\"2Og-K9-Fm0\"/>\n                <outlet property=\"realNameTextField\" destination=\"1599\" id=\"rND-lL-Vwa\"/>\n                <outlet property=\"serverAddressComboBox\" destination=\"1548\" id=\"KiZ-Pe-JGR\"/>\n                <outlet property=\"serverListArrayController\" destination=\"Wea-hF-mxO\" id=\"7g1-J3-n15\"/>\n                <outlet property=\"serverPasswordTextField\" destination=\"1543\" id=\"QPw-Zo-tGM\"/>\n                <outlet property=\"serverPortTextField\" destination=\"1541\" id=\"gpo-Oq-ZnG\"/>\n                <outlet property=\"setInvisibleModeOnConnectCheck\" destination=\"1879\" id=\"avU-NB-X0a\"/>\n                <outlet property=\"sheet\" destination=\"5\" id=\"1059\"/>\n                <outlet property=\"sleepModeQuitMessageTextField\" destination=\"2294\" id=\"2t1-Uk-WKU\"/>\n                <outlet property=\"usernameTextField\" destination=\"1597\" id=\"cJp-Y2-VLI\"/>\n                <outlet property=\"validateServerCertificateChainCheck\" destination=\"7Re-Oa-iNx\" id=\"8ll-Xe-9Sy\"/>\n                <outlet property=\"viewListOfPreferredCipherSuitesButton\" destination=\"BoR-WW-sT2\" id=\"iUd-E9-N2y\"/>\n                <outlet property=\"zncIgnoreConfiguredAutojoinCheck\" destination=\"75N-79-v1S\" id=\"thL-o4-SqJ\"/>\n                <outlet property=\"zncIgnorePlaybackNotificationsCheck\" destination=\"2580\" id=\"2583\"/>\n                <outlet property=\"zncOnlyPlaybackLatestCheck\" destination=\"mgv-QS-XMc\" id=\"Scd-8o-aKm\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Server Properties\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"5\" userLabel=\"Window\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <rect key=\"contentRect\" x=\"382\" y=\"280\" width=\"706\" height=\"350\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"6\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"706\" height=\"350\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"22\" horizontalPageScroll=\"10\" verticalLineScroll=\"22\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dW6-eC-jo9\">\n                        <rect key=\"frame\" x=\"10\" y=\"10\" width=\"156\" height=\"330\"/>\n                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"c7A-uX-FoM\">\n                            <rect key=\"frame\" x=\"1\" y=\"1\" width=\"154\" height=\"328\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                            <subviews>\n                                <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" tableStyle=\"fullWidth\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"19\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" viewBased=\"YES\" floatsGroupRows=\"NO\" indentationPerLevel=\"15\" outlineTableColumn=\"9ke-X4-49Z\" id=\"Uj0-Wm-eox\" customClass=\"TVCContentNavigationOutlineView\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"154\" height=\"328\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <size key=\"intercellSpacing\" width=\"2\" height=\"3\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <tableColumns>\n                                        <tableColumn identifier=\"navEntry\" width=\"142\" minWidth=\"40\" maxWidth=\"1000\" id=\"9ke-X4-49Z\">\n                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tableHeaderCell>\n                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"rPg-fR-uab\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                            <prototypeCellViews>\n                                                <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yDz-eI-nqa\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"152\" height=\"19\"/>\n                                                    <subviews>\n                                                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L6D-B7-wWc\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"2\" width=\"152\" height=\"15\"/>\n                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"VCb-YR-fs2\">\n                                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <binding destination=\"yDz-eI-nqa\" name=\"value\" keyPath=\"objectValue\" id=\"f8r-Ef-YMe\"/>\n                                                            </connections>\n                                                        </textField>\n                                                    </subviews>\n                                                    <constraints>\n                                                        <constraint firstItem=\"L6D-B7-wWc\" firstAttribute=\"top\" secondItem=\"yDz-eI-nqa\" secondAttribute=\"top\" constant=\"2\" id=\"8Q0-X5-Kvp\"/>\n                                                        <constraint firstItem=\"L6D-B7-wWc\" firstAttribute=\"leading\" secondItem=\"yDz-eI-nqa\" secondAttribute=\"leading\" constant=\"2\" id=\"Dtq-z1-Q63\"/>\n                                                        <constraint firstAttribute=\"trailing\" secondItem=\"L6D-B7-wWc\" secondAttribute=\"trailing\" constant=\"2\" id=\"ctT-N2-b5W\"/>\n                                                        <constraint firstAttribute=\"bottom\" secondItem=\"L6D-B7-wWc\" secondAttribute=\"bottom\" constant=\"2\" id=\"hSt-Gl-U3R\"/>\n                                                    </constraints>\n                                                    <connections>\n                                                        <outlet property=\"textField\" destination=\"L6D-B7-wWc\" id=\"2pk-nB-55V\"/>\n                                                    </connections>\n                                                </tableCellView>\n                                            </prototypeCellViews>\n                                        </tableColumn>\n                                    </tableColumns>\n                                    <connections>\n                                        <outlet property=\"contentView\" destination=\"PXC-XT-7RY\" id=\"7Fy-9O-W2f\"/>\n                                    </connections>\n                                </outlineView>\n                            </subviews>\n                            <nil key=\"backgroundColor\"/>\n                        </clipView>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"156\" id=\"qnv-yT-fuS\"/>\n                        </constraints>\n                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"mUA-9Q-xgn\">\n                            <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"6Es-gk-o64\">\n                            <rect key=\"frame\" x=\"141\" y=\"2\" width=\"16\" height=\"336\"/>\n                            <autoresizingMask key=\"autoresizingMask\"/>\n                        </scroller>\n                        <accessibility description=\"Navigation\"/>\n                    </scrollView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1455\">\n                        <rect key=\"frame\" x=\"639\" y=\"3\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1458\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Save\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"1466\"/>\n                        </connections>\n                    </button>\n                    <box autoresizesSubviews=\"NO\" borderType=\"line\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Uo7-GS-DCO\">\n                        <rect key=\"frame\" x=\"173\" y=\"36\" width=\"526\" height=\"306\"/>\n                        <view key=\"contentView\" id=\"xFq-35-m2l\">\n                            <rect key=\"frame\" x=\"4\" y=\"5\" width=\"518\" height=\"298\"/>\n                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        </view>\n                    </box>\n                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PXC-XT-7RY\">\n                        <rect key=\"frame\" x=\"176\" y=\"40\" width=\"520\" height=\"300\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"300\" id=\"5dl-BV-3w8\"/>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"520\" id=\"haD-wg-EbG\"/>\n                        </constraints>\n                    </customView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1456\">\n                        <rect key=\"frame\" x=\"565\" y=\"3\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1457\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"1465\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"dW6-eC-jo9\" firstAttribute=\"leading\" secondItem=\"6\" secondAttribute=\"leading\" constant=\"10\" id=\"0YX-U9-vYj\"/>\n                    <constraint firstItem=\"1455\" firstAttribute=\"top\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"bottom\" constant=\"10\" id=\"5f6-YC-jcU\"/>\n                    <constraint firstItem=\"Uo7-GS-DCO\" firstAttribute=\"leading\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"leading\" id=\"Kh2-PR-M57\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"trailing\" constant=\"10\" id=\"LNf-TZ-DCF\"/>\n                    <constraint firstItem=\"1456\" firstAttribute=\"firstBaseline\" secondItem=\"1455\" secondAttribute=\"firstBaseline\" id=\"LQB-fo-Ith\"/>\n                    <constraint firstItem=\"PXC-XT-7RY\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"10\" id=\"Tbw-kd-vse\"/>\n                    <constraint firstItem=\"PXC-XT-7RY\" firstAttribute=\"leading\" secondItem=\"dW6-eC-jo9\" secondAttribute=\"trailing\" constant=\"10\" id=\"UAS-8i-0rJ\"/>\n                    <constraint firstItem=\"Uo7-GS-DCO\" firstAttribute=\"top\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"top\" id=\"Y6w-Sn-uyb\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"1455\" secondAttribute=\"trailing\" constant=\"10\" id=\"ZIb-5J-NMR\"/>\n                    <constraint firstItem=\"1455\" firstAttribute=\"leading\" secondItem=\"1456\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"ZQh-W7-qYp\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"1455\" secondAttribute=\"bottom\" constant=\"10\" id=\"iZe-YE-Xj3\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"dW6-eC-jo9\" secondAttribute=\"bottom\" constant=\"10\" id=\"oBZ-5D-A6Z\"/>\n                    <constraint firstItem=\"Uo7-GS-DCO\" firstAttribute=\"bottom\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"bottom\" id=\"rFk-j7-7mI\"/>\n                    <constraint firstItem=\"1456\" firstAttribute=\"leading\" relation=\"lessThanOrEqual\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"trailing\" id=\"vZp-3d-RYZ\"/>\n                    <constraint firstItem=\"dW6-eC-jo9\" firstAttribute=\"top\" secondItem=\"6\" secondAttribute=\"top\" constant=\"10\" id=\"wwa-re-HeH\"/>\n                    <constraint firstItem=\"Uo7-GS-DCO\" firstAttribute=\"trailing\" secondItem=\"PXC-XT-7RY\" secondAttribute=\"trailing\" id=\"zva-xk-h9a\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"2302\"/>\n                <outlet property=\"initialFirstResponder\" destination=\"1456\" id=\"1467\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"449\" y=\"232\"/>\n        </window>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1469\" userLabel=\"General View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"314\"/>\n            <subviews>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"14\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eEd-eF-L1L\">\n                    <rect key=\"frame\" x=\"80\" y=\"149\" width=\"360\" height=\"130\"/>\n                    <rows>\n                        <gridRow id=\"uAb-uY-dJ9\"/>\n                        <gridRow id=\"hUK-uO-DWz\"/>\n                        <gridRow id=\"akK-h8-k22\"/>\n                        <gridRow id=\"FhT-p4-Yz2\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"4RY-Yh-h0w\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"kwW-4Q-r7S\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"uAb-uY-dJ9\" column=\"4RY-Yh-h0w\" id=\"vk7-v2-TLn\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1538\">\n                                <rect key=\"frame\" x=\"-2\" y=\"112\" width=\"117\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Connection Name:\" id=\"1559\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"uAb-uY-dJ9\" column=\"kwW-4Q-r7S\" id=\"xlG-iw-qu0\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1539\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"121\" y=\"108\" width=\"239\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"9j5-dY-0rN\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Example IRC Network\" id=\"1558\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1538\" id=\"TQ6-9b-XVp\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"hUK-uO-DWz\" column=\"4RY-Yh-h0w\" id=\"NPD-Vl-B1D\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1540\">\n                                <rect key=\"frame\" x=\"-2\" y=\"76\" width=\"117\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Server Address:\" id=\"1557\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"hUK-uO-DWz\" column=\"kwW-4Q-r7S\" id=\"ZvZ-NZ-lR2\">\n                            <comboBox key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1548\" customClass=\"TVCValidatedComboBox\">\n                                <rect key=\"frame\" x=\"120\" y=\"70\" width=\"243\" height=\"25\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"6ls-al-2Lu\"/>\n                                </constraints>\n                                <comboBoxCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" placeholderString=\"irc.example.com\" usesSingleLineMode=\"YES\" numberOfVisibleItems=\"5\" id=\"1549\" customClass=\"TVCValidatedComboBoxCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </comboBoxCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1540\" id=\"Vek-86-p4Z\"/>\n                                </connections>\n                            </comboBox>\n                        </gridCell>\n                        <gridCell row=\"akK-h8-k22\" column=\"4RY-Yh-h0w\" id=\"Eny-p2-RoM\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1542\">\n                                <rect key=\"frame\" x=\"-2\" y=\"40\" width=\"117\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Port:\" id=\"1555\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"akK-h8-k22\" column=\"kwW-4Q-r7S\" id=\"VDu-lo-rfW\">\n                            <stackView key=\"contentView\" distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A6k-ee-dum\">\n                                <rect key=\"frame\" x=\"121\" y=\"36\" width=\"239\" height=\"22\"/>\n                                <subviews>\n                                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1541\" customClass=\"TVCValidatedTextField\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"60\" id=\"PuT-pr-arX\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"RFQ-60-n62\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" alignment=\"left\" title=\"6667\" placeholderString=\"6667\" id=\"1556\" customClass=\"TVCValidatedTextFieldCell\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <allowedInputSourceLocales>\n                                                <string>NSAllRomanInputSourcesLocaleIdentifier</string>\n                                            </allowedInputSourceLocales>\n                                        </textFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"1542\" id=\"15n-da-FwL\"/>\n                                            <outlet property=\"delegate\" destination=\"-2\" id=\"1560\"/>\n                                        </connections>\n                                    </textField>\n                                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1545\">\n                                        <rect key=\"frame\" x=\"66\" y=\"3\" width=\"173\" height=\"18\"/>\n                                        <string key=\"toolTip\">Attempt to secure the connection by performing a Transport Layer Security (TLS) negotiation. TLS is the modern equivalent of SSL (Secure Sockets Layer)</string>\n                                        <buttonCell key=\"cell\" type=\"check\" title=\"Connect Securely\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"1552\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                        </buttonCell>\n                                        <connections>\n                                            <action selector=\"useSSLCheckChanged:\" target=\"-2\" id=\"IhZ-Nw-b7g\"/>\n                                        </connections>\n                                    </button>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                        </gridCell>\n                        <gridCell row=\"FhT-p4-Yz2\" column=\"4RY-Yh-h0w\" id=\"h1R-6C-hYu\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1544\">\n                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"117\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Server Password:\" id=\"1553\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"FhT-p4-Yz2\" column=\"kwW-4Q-r7S\" id=\"3cc-iU-xNw\">\n                            <textField key=\"contentView\" toolTip=\"Password to be sent using the PASS command. This is NOT your password for NickServ.\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1543\" customClass=\"NSSecureTextField\">\n                                <rect key=\"frame\" x=\"121\" y=\"0.0\" width=\"239\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"KsP-sC-2yd\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" drawsBackground=\"YES\" id=\"1554\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1544\" id=\"RNc-08-gOk\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"6EP-Qu-3Of\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"6\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z7k-zB-mgb\">\n                    <rect key=\"frame\" x=\"116\" y=\"69\" width=\"288\" height=\"60\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1531\">\n                            <rect key=\"frame\" x=\"-2\" y=\"43\" width=\"201\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Connect when Textual opens\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"1536\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1532\">\n                            <rect key=\"frame\" x=\"-2\" y=\"21\" width=\"229\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Perform reconnect on disconnect\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"1535\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2250\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"290\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Perform reconnect when waking from sleep\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"2251\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"eEd-eF-L1L\" firstAttribute=\"centerX\" secondItem=\"1469\" secondAttribute=\"centerX\" id=\"0fF-50-zeK\"/>\n                <constraint firstItem=\"Z7k-zB-mgb\" firstAttribute=\"centerX\" secondItem=\"1469\" secondAttribute=\"centerX\" id=\"5mO-e2-X2p\"/>\n                <constraint firstItem=\"eEd-eF-L1L\" firstAttribute=\"top\" secondItem=\"1469\" secondAttribute=\"top\" constant=\"35\" id=\"8dl-FF-yZx\"/>\n                <constraint firstItem=\"Z7k-zB-mgb\" firstAttribute=\"top\" secondItem=\"eEd-eF-L1L\" secondAttribute=\"bottom\" constant=\"20\" id=\"MGf-Kp-m0S\"/>\n                <constraint firstItem=\"eEd-eF-L1L\" firstAttribute=\"leading\" secondItem=\"1469\" secondAttribute=\"leading\" constant=\"80\" id=\"xyP-at-d8i\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"664\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1563\" userLabel=\"Identity View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"397\"/>\n            <subviews>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"14\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tzn-BP-yin\">\n                    <rect key=\"frame\" x=\"80\" y=\"268\" width=\"360\" height=\"94\"/>\n                    <rows>\n                        <gridRow id=\"Zcw-cx-v0b\"/>\n                        <gridRow id=\"O4O-Ig-L5p\"/>\n                        <gridRow id=\"H9A-aR-nQi\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"Lbn-2W-5bD\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"w3Z-Ld-gYr\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"Zcw-cx-v0b\" column=\"Lbn-2W-5bD\" id=\"0yd-CU-QAD\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1596\">\n                                <rect key=\"frame\" x=\"-2\" y=\"76\" width=\"144\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Nickname:\" id=\"1618\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"Zcw-cx-v0b\" column=\"w3Z-Ld-gYr\" id=\"CPp-os-0C3\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1595\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"148\" y=\"72\" width=\"212\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"8E0-IE-YRt\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Guest\" usesSingleLineMode=\"YES\" id=\"1619\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1596\" id=\"DbG-3n-Xx2\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"1620\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"O4O-Ig-L5p\" column=\"Lbn-2W-5bD\" id=\"gAl-oa-fGd\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2336\">\n                                <rect key=\"frame\" x=\"-2\" y=\"40\" width=\"144\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Away Nickname:\" id=\"2341\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"O4O-Ig-L5p\" column=\"w3Z-Ld-gYr\" id=\"kkb-Ih-JRo\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2335\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"148\" y=\"36\" width=\"212\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"zpG-Ug-YZW\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Guest[away]\" usesSingleLineMode=\"YES\" id=\"2342\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"2336\" id=\"eN3-Ll-UUN\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"H9A-aR-nQi\" column=\"Lbn-2W-5bD\" id=\"p1Q-6y-hrB\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1603\">\n                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"144\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Alternative Nicknames:\" id=\"1611\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"H9A-aR-nQi\" column=\"w3Z-Ld-gYr\" id=\"oh0-Rt-XDV\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1602\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"148\" y=\"0.0\" width=\"212\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"uTp-8Y-0uU\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" usesSingleLineMode=\"YES\" id=\"1612\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1603\" id=\"8Cw-4R-Knw\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1601\" customClass=\"NSSecureTextField\">\n                    <rect key=\"frame\" x=\"228\" y=\"98\" width=\"212\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"gox-5X-KFr\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"NickServ or SASL Password\" drawsBackground=\"YES\" id=\"1613\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"1623\" id=\"9pE-K8-oT9\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1623\">\n                    <rect key=\"frame\" x=\"100\" y=\"102\" width=\"122\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Personal Password:\" id=\"1626\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Zg-jJ-evU\">\n                    <rect key=\"frame\" x=\"100\" y=\"139\" width=\"320\" height=\"5\"/>\n                </box>\n                <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"B1u-e0-30u\">\n                    <rect key=\"frame\" x=\"109\" y=\"56\" width=\"300\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Wait for identification before joining channels\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"8B6-j5-4cs\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"autojoinWaitsForNickServChanged:\" target=\"-2\" id=\"wKA-i6-6CL\"/>\n                    </connections>\n                </button>\n                <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ptP-ZP-JAf\">\n                    <rect key=\"frame\" x=\"127\" y=\"34\" width=\"220\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Warn if channels can't be joined\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"9Uc-VR-STk\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A3c-XH-Q30\">\n                    <rect key=\"frame\" x=\"100\" y=\"234\" width=\"320\" height=\"5\"/>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1604\">\n                    <rect key=\"frame\" x=\"226\" y=\"249\" width=\"166\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"This field is space separated\" id=\"1610\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"1602\" id=\"Pgs-P5-4s5\"/>\n                    </connections>\n                </textField>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"14\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7sG-7N-mzK\">\n                    <rect key=\"frame\" x=\"80\" y=\"160\" width=\"360\" height=\"58\"/>\n                    <rows>\n                        <gridRow id=\"hv7-1e-ySA\"/>\n                        <gridRow id=\"DVI-Kz-YNY\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"s8y-m2-ky8\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"UoC-5W-n5F\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"hv7-1e-ySA\" column=\"s8y-m2-ky8\" id=\"ODW-v7-wHU\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1598\">\n                                <rect key=\"frame\" x=\"-2\" y=\"40\" width=\"144\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Username:\" id=\"1616\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"hv7-1e-ySA\" column=\"UoC-5W-n5F\" id=\"cWe-EP-PjO\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1597\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"148\" y=\"36\" width=\"212\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"uho-Mt-WUG\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"textual\" usesSingleLineMode=\"YES\" id=\"1617\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1598\" id=\"YBC-KR-Lno\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"DVI-Kz-YNY\" column=\"s8y-m2-ky8\" id=\"8cf-Vq-00Y\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1600\">\n                                <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"144\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Real name:\" id=\"1614\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"DVI-Kz-YNY\" column=\"UoC-5W-n5F\" id=\"Rhp-1d-fOQ\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1599\" customClass=\"TVCValidatedTextField\">\n                                <rect key=\"frame\" x=\"148\" y=\"0.0\" width=\"212\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"nEL-Vg-sf4\"/>\n                                </constraints>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Textual User\" usesSingleLineMode=\"YES\" id=\"1615\" customClass=\"TVCValidatedTextFieldCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1600\" id=\"Y9Q-hW-UWv\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"7sG-7N-mzK\" firstAttribute=\"trailing\" secondItem=\"tzn-BP-yin\" secondAttribute=\"trailing\" id=\"1rr-ED-ZEX\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ptP-ZP-JAf\" secondAttribute=\"trailing\" constant=\"20\" id=\"3T7-NP-1co\"/>\n                <constraint firstItem=\"1601\" firstAttribute=\"trailing\" secondItem=\"7sG-7N-mzK\" secondAttribute=\"trailing\" id=\"3UI-x1-mWt\"/>\n                <constraint firstItem=\"2Zg-jJ-evU\" firstAttribute=\"leading\" secondItem=\"A3c-XH-Q30\" secondAttribute=\"leading\" id=\"40V-JA-hR7\"/>\n                <constraint firstItem=\"A3c-XH-Q30\" firstAttribute=\"leading\" secondItem=\"1563\" secondAttribute=\"leading\" constant=\"100\" id=\"5Bg-qa-iNb\"/>\n                <constraint firstItem=\"1623\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"1563\" secondAttribute=\"leading\" constant=\"20\" id=\"Dw8-MU-1so\"/>\n                <constraint firstItem=\"1598\" firstAttribute=\"trailing\" secondItem=\"1603\" secondAttribute=\"trailing\" id=\"FNL-Kj-p4o\"/>\n                <constraint firstItem=\"1604\" firstAttribute=\"leading\" secondItem=\"1602\" secondAttribute=\"leading\" id=\"FzD-Hp-iQa\"/>\n                <constraint firstItem=\"1623\" firstAttribute=\"trailing\" secondItem=\"1600\" secondAttribute=\"trailing\" id=\"GOw-a6-ODD\"/>\n                <constraint firstItem=\"ptP-ZP-JAf\" firstAttribute=\"top\" secondItem=\"B1u-e0-30u\" secondAttribute=\"bottom\" constant=\"6\" symbolic=\"YES\" id=\"IuK-ad-UDf\"/>\n                <constraint firstItem=\"1604\" firstAttribute=\"top\" secondItem=\"tzn-BP-yin\" secondAttribute=\"bottom\" constant=\"4\" id=\"JKr-Xx-KHb\"/>\n                <constraint firstItem=\"1601\" firstAttribute=\"leading\" secondItem=\"1623\" secondAttribute=\"trailing\" constant=\"8\" id=\"JNn-Jx-8aX\"/>\n                <constraint firstItem=\"B1u-e0-30u\" firstAttribute=\"top\" secondItem=\"1601\" secondAttribute=\"bottom\" constant=\"25\" id=\"KTa-A7-fam\"/>\n                <constraint firstItem=\"2Zg-jJ-evU\" firstAttribute=\"top\" secondItem=\"7sG-7N-mzK\" secondAttribute=\"bottom\" constant=\"18\" id=\"M3g-xE-Eg8\"/>\n                <constraint firstItem=\"B1u-e0-30u\" firstAttribute=\"centerX\" secondItem=\"1563\" secondAttribute=\"centerX\" id=\"MVh-Xm-az8\"/>\n                <constraint firstItem=\"1623\" firstAttribute=\"firstBaseline\" secondItem=\"1601\" secondAttribute=\"firstBaseline\" id=\"Znp-dw-sXj\"/>\n                <constraint firstItem=\"tzn-BP-yin\" firstAttribute=\"leading\" secondItem=\"1563\" secondAttribute=\"leading\" constant=\"80\" id=\"ama-2t-vUE\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ptP-ZP-JAf\" secondAttribute=\"bottom\" constant=\"35\" id=\"bD4-Wl-er4\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"1604\" secondAttribute=\"trailing\" constant=\"20\" id=\"eXk-Wd-Lgf\"/>\n                <constraint firstItem=\"7sG-7N-mzK\" firstAttribute=\"top\" secondItem=\"A3c-XH-Q30\" secondAttribute=\"bottom\" constant=\"18\" id=\"f6k-va-7Hj\"/>\n                <constraint firstItem=\"2Zg-jJ-evU\" firstAttribute=\"trailing\" secondItem=\"A3c-XH-Q30\" secondAttribute=\"trailing\" id=\"hrg-nn-IWs\"/>\n                <constraint firstItem=\"A3c-XH-Q30\" firstAttribute=\"centerX\" secondItem=\"1563\" secondAttribute=\"centerX\" id=\"ixq-Gt-k6W\"/>\n                <constraint firstItem=\"A3c-XH-Q30\" firstAttribute=\"top\" secondItem=\"1604\" secondAttribute=\"bottom\" constant=\"12\" id=\"kBq-p2-4aR\"/>\n                <constraint firstItem=\"7sG-7N-mzK\" firstAttribute=\"centerX\" secondItem=\"1563\" secondAttribute=\"centerX\" id=\"lgf-2w-UN4\"/>\n                <constraint firstItem=\"tzn-BP-yin\" firstAttribute=\"top\" secondItem=\"1563\" secondAttribute=\"top\" constant=\"35\" id=\"no3-5w-Fn5\"/>\n                <constraint firstItem=\"1601\" firstAttribute=\"top\" secondItem=\"2Zg-jJ-evU\" secondAttribute=\"bottom\" constant=\"21\" id=\"o0c-9h-5Q4\"/>\n                <constraint firstItem=\"tzn-BP-yin\" firstAttribute=\"centerX\" secondItem=\"1563\" secondAttribute=\"centerX\" id=\"qpZ-lC-jSG\"/>\n                <constraint firstItem=\"ptP-ZP-JAf\" firstAttribute=\"leading\" secondItem=\"B1u-e0-30u\" secondAttribute=\"leading\" constant=\"18\" id=\"yIp-SN-oqt\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"1102\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1627\" userLabel=\"Messages View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1656\">\n                    <rect key=\"frame\" x=\"33\" y=\"224\" width=\"132\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Part &amp; Quit Message:\" id=\"1668\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1671\">\n                    <rect key=\"frame\" x=\"33\" y=\"125\" width=\"193\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Computer Sleep Quit Message:\" id=\"1674\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2290\" customClass=\"TVCValidatedTextField\">\n                    <rect key=\"frame\" x=\"35\" y=\"159\" width=\"450\" height=\"57\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"57\" id=\"rHd-qc-Mnq\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" id=\"2291\" customClass=\"TVCValidatedTextFieldCell\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"1656\" id=\"9XF-4w-7xl\"/>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2294\" customClass=\"TVCValidatedTextField\">\n                    <rect key=\"frame\" x=\"35\" y=\"60\" width=\"450\" height=\"57\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"57\" id=\"cao-zF-kqD\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Optional\" id=\"2295\" customClass=\"TVCValidatedTextFieldCell\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"1671\" id=\"y7q-o0-o8y\"/>\n                    </connections>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"1671\" firstAttribute=\"leading\" secondItem=\"2294\" secondAttribute=\"leading\" id=\"2jw-6M-2hZ\"/>\n                <constraint firstItem=\"1656\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"2290\" secondAttribute=\"trailing\" id=\"5i9-HK-qUl\"/>\n                <constraint firstItem=\"1656\" firstAttribute=\"leading\" secondItem=\"2290\" secondAttribute=\"leading\" id=\"AdY-ai-p99\"/>\n                <constraint firstItem=\"1671\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"2294\" secondAttribute=\"trailing\" id=\"EC7-qQ-eud\"/>\n                <constraint firstItem=\"2294\" firstAttribute=\"top\" secondItem=\"1671\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"HEO-T1-dws\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"2290\" secondAttribute=\"trailing\" constant=\"35\" id=\"K6r-10-Wq0\"/>\n                <constraint firstItem=\"2294\" firstAttribute=\"trailing\" secondItem=\"2290\" secondAttribute=\"trailing\" id=\"KbP-Hm-MsM\"/>\n                <constraint firstItem=\"2290\" firstAttribute=\"leading\" secondItem=\"1627\" secondAttribute=\"leading\" constant=\"35\" id=\"SPE-Di-dNC\"/>\n                <constraint firstItem=\"1671\" firstAttribute=\"top\" secondItem=\"2290\" secondAttribute=\"bottom\" constant=\"18\" id=\"UbW-ab-seB\"/>\n                <constraint firstItem=\"2290\" firstAttribute=\"top\" secondItem=\"1656\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"ZbV-ho-y0G\"/>\n                <constraint firstItem=\"1656\" firstAttribute=\"top\" secondItem=\"1627\" secondAttribute=\"top\" constant=\"60\" id=\"ipe-M5-nAB\"/>\n                <constraint firstItem=\"2294\" firstAttribute=\"leading\" secondItem=\"2290\" secondAttribute=\"leading\" id=\"xLZ-Qu-gBK\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"1531\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1675\" userLabel=\"Encoding View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"12\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"We0-hP-1KB\">\n                    <rect key=\"frame\" x=\"100\" y=\"153\" width=\"320\" height=\"52\"/>\n                    <rows>\n                        <gridRow id=\"HQO-PZ-kkO\"/>\n                        <gridRow id=\"ZX4-Aw-6qI\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" id=\"x37-9J-r9J\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"VoC-9t-4Jn\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"HQO-PZ-kkO\" column=\"x37-9J-r9J\" id=\"ORJ-7a-we5\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1687\">\n                                <rect key=\"frame\" x=\"-2\" y=\"35\" width=\"65\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Encoding:\" id=\"1690\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"HQO-PZ-kkO\" column=\"VoC-9t-4Jn\" id=\"Vbl-SS-VS0\">\n                            <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1684\">\n                                <rect key=\"frame\" x=\"66\" y=\"28\" width=\"258\" height=\"25\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" inset=\"2\" arrowPosition=\"arrowAtCenter\" preferredEdge=\"maxY\" id=\"1714\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                    <menu key=\"menu\" title=\"OtherViews\" id=\"1715\"/>\n                                </popUpButtonCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1687\" id=\"0mM-Zf-1Gq\"/>\n                                </connections>\n                            </popUpButton>\n                        </gridCell>\n                        <gridCell row=\"ZX4-Aw-6qI\" column=\"x37-9J-r9J\" id=\"y4D-Wl-eCA\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1686\">\n                                <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"65\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Fallback:\" id=\"1691\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"ZX4-Aw-6qI\" column=\"VoC-9t-4Jn\" id=\"wEs-0H-zdj\">\n                            <popUpButton key=\"contentView\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1685\">\n                                <rect key=\"frame\" x=\"66\" y=\"-4\" width=\"258\" height=\"25\"/>\n                                <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" inset=\"2\" arrowPosition=\"arrowAtCenter\" preferredEdge=\"maxY\" id=\"1692\">\n                                    <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                    <menu key=\"menu\" title=\"OtherViews\" id=\"1693\"/>\n                                </popUpButtonCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"1686\" id=\"DVJ-X7-jMy\"/>\n                                </connections>\n                            </popUpButton>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2315\">\n                    <rect key=\"frame\" x=\"102\" y=\"118\" width=\"314\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Encoding list includes all possible combinations\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"2316\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"toggleAdvancedEncodings:\" target=\"-2\" id=\"2319\"/>\n                        <binding destination=\"iuc-Sg-eeB\" name=\"value\" keyPath=\"values.Server Properties Window Sheet -&gt; Include Advanced Encodings\" id=\"lpH-1O-kyB\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"We0-hP-1KB\" firstAttribute=\"centerX\" secondItem=\"1675\" secondAttribute=\"centerX\" id=\"7zh-3o-mpI\"/>\n                <constraint firstItem=\"2315\" firstAttribute=\"top\" secondItem=\"We0-hP-1KB\" secondAttribute=\"bottom\" constant=\"18\" id=\"ALh-io-95B\"/>\n                <constraint firstItem=\"2315\" firstAttribute=\"centerX\" secondItem=\"1675\" secondAttribute=\"centerX\" id=\"JOs-Q6-9VC\"/>\n                <constraint firstItem=\"We0-hP-1KB\" firstAttribute=\"top\" secondItem=\"1675\" secondAttribute=\"top\" constant=\"95\" id=\"YGM-5t-Qms\"/>\n                <constraint firstItem=\"We0-hP-1KB\" firstAttribute=\"leading\" secondItem=\"1675\" secondAttribute=\"leading\" constant=\"100\" id=\"eHJ-Dg-99e\"/>\n                <constraint firstAttribute=\"width\" constant=\"520\" id=\"k7z-IA-p7B\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"1944\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2542\" userLabel=\"ZNC View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2590\">\n                    <rect key=\"frame\" x=\"84\" y=\"133\" width=\"352\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Do not show notification bubbles or play sounds for messages that are part of the playback buffer.\" id=\"2591\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"2580\" id=\"cxc-qX-cGi\"/>\n                    </connections>\n                </textField>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"75N-79-v1S\">\n                    <rect key=\"frame\" x=\"66\" y=\"200\" width=\"305\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Do not automatically join channels on connect\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"TH5-0C-MeB\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2580\">\n                    <rect key=\"frame\" x=\"66\" y=\"170\" width=\"322\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Do not show notifications for the playback buffer\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"2581\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mgv-QS-XMc\">\n                    <rect key=\"frame\" x=\"66\" y=\"108\" width=\"252\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Only play back messages you missed\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"e2u-k3-3Ur\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JCf-aC-VgE\">\n                    <rect key=\"frame\" x=\"84\" y=\"86\" width=\"252\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"This option requires the “playback” module.\" id=\"DES-Fw-k4c\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"2580\" id=\"fVS-Kr-rN7\"/>\n                    </connections>\n                </textField>\n                <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pKk-0J-UQ0\">\n                    <rect key=\"frame\" x=\"35\" y=\"238\" width=\"450\" height=\"31\"/>\n                    <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"Fx0-Yf-kbO\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"450\" height=\"31\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" allowsNonContiguousLayout=\"YES\" id=\"ujo-Zq-Cf1\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"450\" height=\"31\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <size key=\"minSize\" width=\"450\" height=\"31\"/>\n                                <size key=\"maxSize\" width=\"1155\" height=\"10000000\"/>\n                                <attributedString key=\"textStorage\">\n                                    <fragment content=\"The following options will automatically take effect when Textual detects that it is connecting to \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"system\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"ZNC\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"system\"/>\n                                            <url key=\"NSLink\" string=\"http://znc.in/\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\".\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"system\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                </attributedString>\n                                <color key=\"insertionPointColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"31\" id=\"kAS-h9-aTw\"/>\n                    </constraints>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"5aN-9T-pUi\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"NO\" id=\"4F7-mN-S31\">\n                        <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2599\">\n                    <rect key=\"frame\" x=\"120\" y=\"20\" width=\"281\" height=\"14\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"These options target version 1.2 of ZNC and later.\" id=\"2600\">\n                        <font key=\"font\" metaFont=\"smallSystemBold\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"2599\" secondAttribute=\"bottom\" constant=\"20\" symbolic=\"YES\" id=\"4VY-ob-oHy\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"JCf-aC-VgE\" secondAttribute=\"trailing\" constant=\"20\" id=\"60b-GK-EiY\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"mgv-QS-XMc\" secondAttribute=\"trailing\" constant=\"20\" id=\"8co-Mi-9HF\"/>\n                <constraint firstItem=\"2590\" firstAttribute=\"top\" secondItem=\"2580\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"C1H-0R-rhw\"/>\n                <constraint firstItem=\"pKk-0J-UQ0\" firstAttribute=\"top\" secondItem=\"2542\" secondAttribute=\"top\" constant=\"31\" id=\"Gpi-bg-PTb\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"2590\" secondAttribute=\"trailing\" constant=\"20\" id=\"IWe-nh-0k8\"/>\n                <constraint firstItem=\"pKk-0J-UQ0\" firstAttribute=\"leading\" secondItem=\"2542\" secondAttribute=\"leading\" constant=\"35\" id=\"LFh-o9-uep\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"pKk-0J-UQ0\" secondAttribute=\"trailing\" constant=\"35\" id=\"RHi-42-74e\"/>\n                <constraint firstItem=\"mgv-QS-XMc\" firstAttribute=\"leading\" secondItem=\"2580\" secondAttribute=\"leading\" id=\"Sfu-jK-OAj\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"75N-79-v1S\" secondAttribute=\"trailing\" constant=\"20\" id=\"TyJ-Oh-rdE\"/>\n                <constraint firstItem=\"2599\" firstAttribute=\"top\" relation=\"greaterThanOrEqual\" secondItem=\"JCf-aC-VgE\" secondAttribute=\"bottom\" constant=\"20\" id=\"bnN-mS-xUg\"/>\n                <constraint firstItem=\"2580\" firstAttribute=\"top\" secondItem=\"75N-79-v1S\" secondAttribute=\"bottom\" constant=\"14\" id=\"dt7-N4-fPR\"/>\n                <constraint firstItem=\"2599\" firstAttribute=\"centerX\" secondItem=\"2542\" secondAttribute=\"centerX\" id=\"fTc-Wr-NXq\"/>\n                <constraint firstItem=\"2599\" firstAttribute=\"centerX\" secondItem=\"2590\" secondAttribute=\"centerX\" id=\"fpr-ef-r5g\"/>\n                <constraint firstItem=\"2590\" firstAttribute=\"leading\" secondItem=\"2580\" secondAttribute=\"leading\" constant=\"18\" id=\"kpi-oi-SLb\"/>\n                <constraint firstItem=\"75N-79-v1S\" firstAttribute=\"leading\" secondItem=\"2542\" secondAttribute=\"leading\" constant=\"68\" id=\"oCx-fp-eU9\"/>\n                <constraint firstItem=\"JCf-aC-VgE\" firstAttribute=\"leading\" secondItem=\"mgv-QS-XMc\" secondAttribute=\"leading\" constant=\"18\" id=\"poF-uR-hpi\"/>\n                <constraint firstItem=\"75N-79-v1S\" firstAttribute=\"leading\" secondItem=\"2580\" secondAttribute=\"leading\" id=\"rhF-3O-ghC\"/>\n                <constraint firstItem=\"mgv-QS-XMc\" firstAttribute=\"top\" secondItem=\"2590\" secondAttribute=\"bottom\" constant=\"8\" id=\"sFB-NE-rWd\"/>\n                <constraint firstItem=\"75N-79-v1S\" firstAttribute=\"top\" secondItem=\"pKk-0J-UQ0\" secondAttribute=\"bottom\" constant=\"21\" id=\"ta7-ZW-K0o\"/>\n                <constraint firstItem=\"JCf-aC-VgE\" firstAttribute=\"top\" secondItem=\"mgv-QS-XMc\" secondAttribute=\"bottom\" constant=\"8\" id=\"vLM-C0-bec\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"2580\" secondAttribute=\"trailing\" constant=\"20\" id=\"xmz-qd-kfu\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"540\" y=\"2383\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1738\" userLabel=\"Autojoin View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1796\">\n                    <rect key=\"frame\" x=\"85\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1799\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Remove Selected Channel\"/>\n                    <connections>\n                        <action selector=\"deleteChannel:\" target=\"-2\" id=\"1814\"/>\n                    </connections>\n                </button>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" allowsMagnification=\"YES\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1793\">\n                    <rect key=\"frame\" x=\"54\" y=\"54\" width=\"412\" height=\"220\"/>\n                    <clipView key=\"contentView\" id=\"LcR-Dy-bmD\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"410\" height=\"218\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"firstColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" headerView=\"Lh4-PC-UuF\" id=\"1805\" customClass=\"TVCBasicTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"190\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"name\" editable=\"NO\" width=\"219\" minWidth=\"40\" maxWidth=\"1000\" id=\"1808\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Channel Name\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"1809\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Channel Name\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"pass\" editable=\"NO\" width=\"108\" minWidth=\"10\" maxWidth=\"1000\" id=\"1807\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Password\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"1810\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Channel Password\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"join\" editable=\"NO\" width=\"36\" minWidth=\"10\" maxWidth=\"1000\" id=\"1806\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Join\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <buttonCell key=\"dataCell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"only\" alignment=\"left\" inset=\"2\" id=\"1811\">\n                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"titleBar\" size=\"12\" textStyle=\"headline\"/>\n                                            <accessibility description=\"Join Channel on Connect\"/>\n                                        </buttonCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"XlX-J4-ZJt\" name=\"content\" keyPath=\"arrangedObjects\" id=\"eN6-1G-Wto\"/>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"1812\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"1813\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"1803\">\n                        <rect key=\"frame\" x=\"1\" y=\"203\" width=\"410\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"1804\">\n                        <rect key=\"frame\" x=\"405\" y=\"17\" width=\"15\" height=\"154\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"Lh4-PC-UuF\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"28\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                    <accessibility description=\"Channel List\"/>\n                </scrollView>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1794\">\n                    <rect key=\"frame\" x=\"54\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1801\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"nWC-2d-INa\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"tD6-C7-slm\"/>\n                    </constraints>\n                    <accessibility description=\"Add Channel\"/>\n                    <connections>\n                        <action selector=\"addChannel:\" target=\"-2\" id=\"1815\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1795\">\n                    <rect key=\"frame\" x=\"416\" y=\"24\" width=\"50\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Edit\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1800\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"50\" id=\"KWH-oA-T2h\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"tgl-Uf-iCk\"/>\n                    </constraints>\n                    <accessibility description=\"Edit Selected Channel\"/>\n                    <connections>\n                        <action selector=\"editChannel:\" target=\"-2\" id=\"1816\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"1796\" firstAttribute=\"bottom\" secondItem=\"1794\" secondAttribute=\"bottom\" id=\"3CB-cO-9Wm\"/>\n                <constraint firstItem=\"1793\" firstAttribute=\"leading\" secondItem=\"1738\" secondAttribute=\"leading\" constant=\"54\" id=\"7P5-yt-Gy7\"/>\n                <constraint firstItem=\"1796\" firstAttribute=\"leading\" secondItem=\"1794\" secondAttribute=\"trailing\" constant=\"1\" id=\"AhU-jJ-QCP\"/>\n                <constraint firstItem=\"1793\" firstAttribute=\"top\" secondItem=\"1738\" secondAttribute=\"top\" constant=\"26\" id=\"Cg3-9G-9AE\"/>\n                <constraint firstItem=\"1794\" firstAttribute=\"leading\" secondItem=\"1793\" secondAttribute=\"leading\" id=\"QPA-me-Cad\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"1794\" secondAttribute=\"bottom\" constant=\"25\" id=\"RYG-k2-25d\"/>\n                <constraint firstItem=\"1793\" firstAttribute=\"centerX\" secondItem=\"1738\" secondAttribute=\"centerX\" id=\"TQZ-eV-n5G\"/>\n                <constraint firstItem=\"1796\" firstAttribute=\"width\" secondItem=\"1794\" secondAttribute=\"width\" id=\"VZJ-av-h0X\"/>\n                <constraint firstItem=\"1796\" firstAttribute=\"top\" secondItem=\"1794\" secondAttribute=\"top\" id=\"dhU-XE-MRV\"/>\n                <constraint firstItem=\"1795\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"1796\" secondAttribute=\"trailing\" constant=\"20\" id=\"f3u-Fq-vmd\"/>\n                <constraint firstItem=\"1795\" firstAttribute=\"trailing\" secondItem=\"1793\" secondAttribute=\"trailing\" id=\"lgN-jH-Ueo\"/>\n                <constraint firstItem=\"1794\" firstAttribute=\"top\" secondItem=\"1793\" secondAttribute=\"bottom\" constant=\"8\" id=\"yTY-mh-QIc\"/>\n                <constraint firstItem=\"1795\" firstAttribute=\"top\" secondItem=\"1793\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"yTc-nj-WbL\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"2825\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2445\" userLabel=\"Highlights View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2449\">\n                    <rect key=\"frame\" x=\"54\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"2461\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"GCR-iJ-hff\"/>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"iT9-DQ-Ye7\"/>\n                    </constraints>\n                    <accessibility description=\"Add Highlight Match\"/>\n                    <connections>\n                        <action selector=\"addHighlight:\" target=\"-2\" id=\"2481\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2447\">\n                    <rect key=\"frame\" x=\"85\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"2463\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Remove Selected Highlight Match\"/>\n                    <connections>\n                        <action selector=\"deleteHighlight:\" target=\"-2\" id=\"2483\"/>\n                    </connections>\n                </button>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2450\">\n                    <rect key=\"frame\" x=\"54\" y=\"54\" width=\"412\" height=\"220\"/>\n                    <clipView key=\"contentView\" id=\"txe-Gd-Uvj\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"410\" height=\"218\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"firstColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" headerView=\"Gzo-0n-LCU\" id=\"2454\" customClass=\"TVCBasicTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"190\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"keyword\" editable=\"NO\" width=\"151\" minWidth=\"40\" maxWidth=\"1000\" id=\"2456\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Keyword\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"2459\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Highlight Keyword\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"type\" editable=\"NO\" width=\"80\" minWidth=\"10\" maxWidth=\"1000\" id=\"2457\" userLabel=\"Table Column - Entry Type\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Entry Type\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"2458\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Highlight Match Type\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"channel\" editable=\"NO\" width=\"132\" minWidth=\"10\" maxWidth=\"1000\" id=\"2455\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Channel\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"2460\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Channel Highlight Match is Restricted To\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"XVW-tl-Aro\" name=\"content\" keyPath=\"arrangedObjects\" id=\"Qdv-Df-SW6\"/>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"2469\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"2468\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"2452\">\n                        <rect key=\"frame\" x=\"1\" y=\"203\" width=\"410\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"2453\">\n                        <rect key=\"frame\" x=\"405\" y=\"17\" width=\"15\" height=\"154\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"Gzo-0n-LCU\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"28\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                    <accessibility description=\"Highlight Match Table\"/>\n                </scrollView>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2448\">\n                    <rect key=\"frame\" x=\"416\" y=\"24\" width=\"50\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Edit\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"2462\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"50\" id=\"MuU-HJ-RlZ\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"TKi-UE-9Bc\"/>\n                    </constraints>\n                    <accessibility description=\"Edit Selected Highlight Match\"/>\n                    <connections>\n                        <action selector=\"editHighlight:\" target=\"-2\" id=\"2482\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"2448\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"2447\" secondAttribute=\"trailing\" constant=\"20\" id=\"0ku-ns-r90\"/>\n                <constraint firstItem=\"2449\" firstAttribute=\"leading\" secondItem=\"2450\" secondAttribute=\"leading\" id=\"5yE-f7-nQa\"/>\n                <constraint firstItem=\"2447\" firstAttribute=\"top\" secondItem=\"2449\" secondAttribute=\"top\" id=\"CGm-la-UE1\"/>\n                <constraint firstItem=\"2450\" firstAttribute=\"centerX\" secondItem=\"2445\" secondAttribute=\"centerX\" id=\"QIC-47-BcF\"/>\n                <constraint firstItem=\"2449\" firstAttribute=\"top\" secondItem=\"2450\" secondAttribute=\"bottom\" constant=\"8\" id=\"Wzs-A3-HoP\"/>\n                <constraint firstItem=\"2447\" firstAttribute=\"width\" secondItem=\"2449\" secondAttribute=\"width\" id=\"jMv-Cc-vXT\"/>\n                <constraint firstItem=\"2450\" firstAttribute=\"top\" secondItem=\"2445\" secondAttribute=\"top\" constant=\"26\" id=\"pQz-Md-S0m\"/>\n                <constraint firstItem=\"2448\" firstAttribute=\"top\" secondItem=\"2450\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"pbg-Nb-XC1\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"2449\" secondAttribute=\"bottom\" constant=\"25\" id=\"qde-FB-0Rv\"/>\n                <constraint firstItem=\"2447\" firstAttribute=\"bottom\" secondItem=\"2449\" secondAttribute=\"bottom\" id=\"rIG-3n-2DT\"/>\n                <constraint firstItem=\"2447\" firstAttribute=\"leading\" secondItem=\"2449\" secondAttribute=\"trailing\" constant=\"1\" id=\"uGv-Ro-tW3\"/>\n                <constraint firstItem=\"2450\" firstAttribute=\"leading\" secondItem=\"2445\" secondAttribute=\"leading\" constant=\"54\" id=\"uWX-aV-Mxo\"/>\n                <constraint firstItem=\"2448\" firstAttribute=\"trailing\" secondItem=\"2450\" secondAttribute=\"trailing\" id=\"wG9-PY-Mbb\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"3246\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1817\" userLabel=\"Ignores View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2358\">\n                    <rect key=\"frame\" x=\"52\" y=\"259\" width=\"223\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Ignore or track the following people:\" id=\"2359\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1843\">\n                    <rect key=\"frame\" x=\"54\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1848\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"Z2m-Ok-I61\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"d1y-UR-sxL\"/>\n                    </constraints>\n                    <accessibility description=\"Add Address Book Entry\"/>\n                    <connections>\n                        <action selector=\"showAddAddressBookEntryMenu:\" target=\"-2\" id=\"88b-Ti-Qfj\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1845\">\n                    <rect key=\"frame\" x=\"85\" y=\"24\" width=\"30\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1846\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Remove Selected Address Book Entry\"/>\n                    <connections>\n                        <action selector=\"deleteAddressBookEntry:\" target=\"-2\" id=\"xzf-1d-ibA\"/>\n                    </connections>\n                </button>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" allowsMagnification=\"YES\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1842\">\n                    <rect key=\"frame\" x=\"54\" y=\"54\" width=\"412\" height=\"197\"/>\n                    <clipView key=\"contentView\" id=\"wXW-Pe-W5j\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"410\" height=\"195\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" headerView=\"NHj-wb-YWi\" id=\"1851\" customClass=\"TVCBasicTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"167\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"_sourceListBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"hostmask\" editable=\"NO\" width=\"299\" minWidth=\"40\" maxWidth=\"1000\" id=\"1853\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Entry Mask\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"1854\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Address Book Entry\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"type\" width=\"67\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"1982\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Entry Type\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" alignment=\"left\" title=\"Text Cell\" id=\"1983\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <accessibility description=\"Address Book Entry Type\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"aez-lt-zBV\" name=\"content\" keyPath=\"arrangedObjects\" id=\"Fiz-Rr-whz\"/>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"1858\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"1859\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"1850\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"308\" height=\"15\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"1849\">\n                        <rect key=\"frame\" x=\"294\" y=\"16\" width=\"15\" height=\"340\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"NHj-wb-YWi\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"28\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                    <accessibility description=\"Address Book List\"/>\n                </scrollView>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1844\">\n                    <rect key=\"frame\" x=\"416\" y=\"24\" width=\"50\" height=\"23\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Edit\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1847\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"50\" id=\"3PF-wb-buW\"/>\n                        <constraint firstAttribute=\"height\" constant=\"21\" id=\"Kwr-aI-8Mt\"/>\n                    </constraints>\n                    <accessibility description=\"Edit Selected Address Book Entry\"/>\n                    <connections>\n                        <action selector=\"editAddressBookEntry:\" target=\"-2\" id=\"IB0-cr-GDM\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"1843\" secondAttribute=\"bottom\" constant=\"25\" id=\"2Gi-2g-Nwu\"/>\n                <constraint firstItem=\"1845\" firstAttribute=\"leading\" secondItem=\"1843\" secondAttribute=\"trailing\" constant=\"1\" id=\"2qb-yz-69l\"/>\n                <constraint firstItem=\"2358\" firstAttribute=\"top\" secondItem=\"1817\" secondAttribute=\"top\" constant=\"25\" id=\"9z4-Kb-aMe\"/>\n                <constraint firstItem=\"1845\" firstAttribute=\"top\" secondItem=\"1843\" secondAttribute=\"top\" id=\"BOv-nN-UoS\"/>\n                <constraint firstItem=\"1843\" firstAttribute=\"top\" secondItem=\"1842\" secondAttribute=\"bottom\" constant=\"8\" id=\"FUk-OU-ysM\"/>\n                <constraint firstItem=\"1844\" firstAttribute=\"top\" secondItem=\"1842\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"H7n-ny-Oa6\"/>\n                <constraint firstItem=\"2358\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"1842\" secondAttribute=\"trailing\" id=\"HJR-XB-yIn\"/>\n                <constraint firstItem=\"1845\" firstAttribute=\"width\" secondItem=\"1843\" secondAttribute=\"width\" id=\"Mld-X8-TVW\"/>\n                <constraint firstItem=\"1844\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"1845\" secondAttribute=\"trailing\" constant=\"20\" id=\"PyA-u7-Bx7\"/>\n                <constraint firstItem=\"1844\" firstAttribute=\"trailing\" secondItem=\"1842\" secondAttribute=\"trailing\" id=\"WVJ-uY-BnM\"/>\n                <constraint firstItem=\"1842\" firstAttribute=\"top\" secondItem=\"2358\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"o17-Ew-zWm\"/>\n                <constraint firstItem=\"1842\" firstAttribute=\"leading\" secondItem=\"1817\" secondAttribute=\"leading\" constant=\"54\" id=\"p2B-pY-CwL\"/>\n                <constraint firstItem=\"2358\" firstAttribute=\"leading\" secondItem=\"1842\" secondAttribute=\"leading\" id=\"r8y-Mt-bwu\"/>\n                <constraint firstItem=\"1845\" firstAttribute=\"bottom\" secondItem=\"1843\" secondAttribute=\"bottom\" id=\"tKH-Xg-wDW\"/>\n                <constraint firstItem=\"1842\" firstAttribute=\"centerX\" secondItem=\"1817\" secondAttribute=\"centerX\" id=\"uSN-bT-G7e\"/>\n                <constraint firstItem=\"1843\" firstAttribute=\"leading\" secondItem=\"1842\" secondAttribute=\"leading\" id=\"wno-Xo-qg1\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"3726\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1860\" userLabel=\"Commands View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1879\">\n                    <rect key=\"frame\" x=\"55\" y=\"29\" width=\"233\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Set invisible (+i) mode on connect\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"1886\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fNI-3k-yzt\">\n                    <rect key=\"frame\" x=\"313\" y=\"254\" width=\"152\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"This field is line separated\" id=\"Mnf-Uj-ov2\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <accessibilityConnection property=\"link\" destination=\"2310\" id=\"6AF-OO-L3i\"/>\n                    </connections>\n                </textField>\n                <scrollView focusRingType=\"exterior\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2309\">\n                    <rect key=\"frame\" x=\"57\" y=\"56\" width=\"406\" height=\"192\"/>\n                    <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"rH8-fa-Y7i\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"389\" height=\"190\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <subviews>\n                            <textView importsGraphics=\"NO\" richText=\"NO\" verticallyResizable=\"YES\" continuousSpellChecking=\"YES\" allowsUndo=\"YES\" allowsNonContiguousLayout=\"YES\" id=\"2310\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"389\" height=\"190\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <size key=\"minSize\" width=\"389\" height=\"190\"/>\n                                <size key=\"maxSize\" width=\"600\" height=\"10000000\"/>\n                                <color key=\"insertionPointColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textView>\n                        </subviews>\n                    </clipView>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"2311\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"2312\">\n                        <rect key=\"frame\" x=\"389\" y=\"1\" width=\"16\" height=\"190\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <connections>\n                        <accessibilityConnection property=\"title\" destination=\"1881\" id=\"LJb-a8-u9c\"/>\n                    </connections>\n                </scrollView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1881\">\n                    <rect key=\"frame\" x=\"55\" y=\"254\" width=\"199\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Perform commands on connect:\" id=\"1882\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"2309\" firstAttribute=\"trailing\" secondItem=\"fNI-3k-yzt\" secondAttribute=\"trailing\" id=\"1GV-Oo-pC3\"/>\n                <constraint firstItem=\"fNI-3k-yzt\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"1881\" secondAttribute=\"trailing\" constant=\"20\" id=\"1aO-P8-H8j\"/>\n                <constraint firstItem=\"2309\" firstAttribute=\"centerX\" secondItem=\"1860\" secondAttribute=\"centerX\" id=\"AU6-dh-3A4\"/>\n                <constraint firstItem=\"2309\" firstAttribute=\"leading\" secondItem=\"1860\" secondAttribute=\"leading\" constant=\"57\" id=\"JFf-4B-Pvh\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"1879\" secondAttribute=\"bottom\" constant=\"30\" id=\"Xj1-tL-MV5\"/>\n                <constraint firstItem=\"2309\" firstAttribute=\"top\" secondItem=\"1881\" secondAttribute=\"bottom\" constant=\"6\" id=\"Z6v-sY-lJc\"/>\n                <constraint firstItem=\"1879\" firstAttribute=\"top\" secondItem=\"2309\" secondAttribute=\"bottom\" constant=\"10\" id=\"Ziv-Ys-BIL\"/>\n                <constraint firstItem=\"1879\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"2309\" secondAttribute=\"trailing\" id=\"kzA-Pk-WbU\"/>\n                <constraint firstItem=\"1881\" firstAttribute=\"leading\" secondItem=\"2309\" secondAttribute=\"leading\" id=\"so4-qd-Y0a\"/>\n                <constraint firstItem=\"1879\" firstAttribute=\"leading\" secondItem=\"2309\" secondAttribute=\"leading\" id=\"tip-b3-D68\"/>\n                <constraint firstItem=\"fNI-3k-yzt\" firstAttribute=\"firstBaseline\" secondItem=\"1881\" secondAttribute=\"firstBaseline\" id=\"w9J-fK-jaJ\"/>\n                <constraint firstItem=\"1881\" firstAttribute=\"top\" secondItem=\"1860\" secondAttribute=\"top\" constant=\"30\" id=\"ySb-OF-cKm\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"535\" y=\"4219\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1887\" userLabel=\"Proxy Server View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"320\"/>\n            <subviews>\n                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KJ6-gu-xq3\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"73\" width=\"520\" height=\"176\"/>\n                    <subviews>\n                        <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"14\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"h5I-Rt-m0M\">\n                            <rect key=\"frame\" x=\"100\" y=\"23\" width=\"320\" height=\"130\"/>\n                            <rows>\n                                <gridRow id=\"Wux-ui-Afe\"/>\n                                <gridRow id=\"wAW-qX-GTz\"/>\n                                <gridRow id=\"Onw-AC-h2l\"/>\n                                <gridRow id=\"cWB-GJ-DxE\"/>\n                            </rows>\n                            <columns>\n                                <gridColumn xPlacement=\"fill\" id=\"UfM-t2-7vL\"/>\n                                <gridColumn xPlacement=\"fill\" id=\"GOB-Ox-jHY\"/>\n                            </columns>\n                            <gridCells>\n                                <gridCell row=\"Wux-ui-Afe\" column=\"UfM-t2-7vL\" id=\"utt-iw-5Mt\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1897\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"112\" width=\"70\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Address:\" id=\"1920\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"Wux-ui-Afe\" column=\"GOB-Ox-jHY\" id=\"Yfy-2w-str\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1901\" customClass=\"TVCValidatedTextField\">\n                                        <rect key=\"frame\" x=\"74\" y=\"108\" width=\"246\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"CHb-rL-Cpx\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"proxy.example.com\" usesSingleLineMode=\"YES\" id=\"1916\" customClass=\"TVCValidatedTextFieldCell\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"1897\" id=\"rwX-Bu-Yk3\"/>\n                                        </connections>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"wAW-qX-GTz\" column=\"UfM-t2-7vL\" id=\"ECM-tm-H1X\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1898\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"76\" width=\"70\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Port:\" id=\"1919\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"wAW-qX-GTz\" column=\"GOB-Ox-jHY\" id=\"Dow-Al-RGx\">\n                                    <stackView key=\"contentView\" distribution=\"fill\" orientation=\"horizontal\" alignment=\"top\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fud-jH-umc\">\n                                        <rect key=\"frame\" x=\"74\" y=\"72\" width=\"246\" height=\"22\"/>\n                                        <subviews>\n                                            <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"84A-gQ-HPC\" customClass=\"TVCValidatedTextField\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"3T9-ia-fvT\"/>\n                                                    <constraint firstAttribute=\"width\" constant=\"60\" id=\"r2f-yM-rkS\"/>\n                                                </constraints>\n                                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"1080\" usesSingleLineMode=\"YES\" id=\"bIe-e4-zYC\" customClass=\"TVCValidatedTextFieldCell\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                                <connections>\n                                                    <accessibilityConnection property=\"title\" destination=\"1898\" id=\"lBo-M2-yZw\"/>\n                                                </connections>\n                                            </textField>\n                                            <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"U3I-cD-Nje\">\n                                                <rect key=\"frame\" x=\"68\" y=\"0.0\" width=\"178\" height=\"22\"/>\n                                            </customView>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"U3I-cD-Nje\" firstAttribute=\"height\" secondItem=\"84A-gQ-HPC\" secondAttribute=\"height\" id=\"uZD-DP-eg0\"/>\n                                        </constraints>\n                                        <visibilityPriorities>\n                                            <integer value=\"1000\"/>\n                                            <integer value=\"1000\"/>\n                                        </visibilityPriorities>\n                                        <customSpacing>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                            <real value=\"3.4028234663852886e+38\"/>\n                                        </customSpacing>\n                                    </stackView>\n                                </gridCell>\n                                <gridCell row=\"Onw-AC-h2l\" column=\"UfM-t2-7vL\" id=\"SPp-ui-RaR\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1900\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"40\" width=\"70\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Username:\" id=\"1917\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"Onw-AC-h2l\" column=\"GOB-Ox-jHY\" id=\"RwZ-xF-727\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1904\">\n                                        <rect key=\"frame\" x=\"74\" y=\"36\" width=\"246\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"jly-CJ-SHw\"/>\n                                        </constraints>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"admin\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"1913\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"1900\" id=\"cyI-uw-QY9\"/>\n                                        </connections>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"cWB-GJ-DxE\" column=\"UfM-t2-7vL\" id=\"0Qw-1o-Faf\">\n                                    <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1899\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"70\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Password:\" id=\"1918\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                </gridCell>\n                                <gridCell row=\"cWB-GJ-DxE\" column=\"GOB-Ox-jHY\" id=\"e8B-zt-fSc\">\n                                    <secureTextField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1902\">\n                                        <rect key=\"frame\" x=\"74\" y=\"0.0\" width=\"246\" height=\"22\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"height\" constant=\"22\" id=\"EPx-uC-UQ3\"/>\n                                        </constraints>\n                                        <secureTextFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"1915\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <allowedInputSourceLocales>\n                                                <string>NSAllRomanInputSourcesLocaleIdentifier</string>\n                                            </allowedInputSourceLocales>\n                                        </secureTextFieldCell>\n                                        <connections>\n                                            <accessibilityConnection property=\"title\" destination=\"1899\" id=\"qu4-r8-JTc\"/>\n                                        </connections>\n                                    </secureTextField>\n                                </gridCell>\n                            </gridCells>\n                        </gridView>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"h5I-Rt-m0M\" firstAttribute=\"leading\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"leading\" constant=\"100\" id=\"2bW-ap-F6G\"/>\n                        <constraint firstItem=\"h5I-Rt-m0M\" firstAttribute=\"centerY\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"centerY\" id=\"9G2-ut-bdU\"/>\n                        <constraint firstAttribute=\"bottom\" relation=\"greaterThanOrEqual\" secondItem=\"h5I-Rt-m0M\" secondAttribute=\"bottom\" id=\"Mt9-sA-21A\"/>\n                        <constraint firstItem=\"h5I-Rt-m0M\" firstAttribute=\"top\" relation=\"greaterThanOrEqual\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"top\" id=\"Ujo-DW-AKS\"/>\n                        <constraint firstItem=\"h5I-Rt-m0M\" firstAttribute=\"centerX\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"centerX\" id=\"lZ2-bg-GPV\"/>\n                    </constraints>\n                </customView>\n                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yql-kd-PP5\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"73\" width=\"520\" height=\"176\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"P8N-qI-sG7\">\n                            <rect key=\"frame\" x=\"78\" y=\"76\" width=\"364\" height=\"48\"/>\n                            <textFieldCell key=\"cell\" controlSize=\"mini\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"voS-R3-3c7\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <string key=\"title\">Textual will attempt to connect to the Tor anonymity network using the SOCKS5 proxy on port 9150 that is available when the “Tor Browser” application is open.</string>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"P8N-qI-sG7\" firstAttribute=\"leading\" secondItem=\"yql-kd-PP5\" secondAttribute=\"leading\" constant=\"80\" id=\"Bas-dV-XdT\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"P8N-qI-sG7\" secondAttribute=\"bottom\" constant=\"76\" id=\"Owe-KO-Eno\"/>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"P8N-qI-sG7\" secondAttribute=\"trailing\" constant=\"80\" id=\"hJo-l3-fiV\"/>\n                        <constraint firstItem=\"P8N-qI-sG7\" firstAttribute=\"top\" secondItem=\"yql-kd-PP5\" secondAttribute=\"top\" constant=\"52\" id=\"iPC-W3-AGi\"/>\n                    </constraints>\n                </customView>\n                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GFp-Qd-4ck\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"73\" width=\"520\" height=\"176\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fFG-yi-lT4\">\n                            <rect key=\"frame\" x=\"78\" y=\"86\" width=\"364\" height=\"48\"/>\n                            <textFieldCell key=\"cell\" controlSize=\"mini\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"R86-j6-hCz\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <string key=\"title\">When enabled, the SOCKS proxy that can be configured in the Network section of System Settings will be used with the “Automatic” proxy type selected.</string>\n                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"h41-zX-k7q\">\n                            <rect key=\"frame\" x=\"176\" y=\"39\" width=\"169\" height=\"32\"/>\n                            <buttonCell key=\"cell\" type=\"push\" title=\"Open System Settings\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"j5N-EC-4uH\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"openProxySettingsInSystemPreferences:\" target=\"-2\" id=\"Pfm-LV-j2c\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"fFG-yi-lT4\" firstAttribute=\"top\" secondItem=\"GFp-Qd-4ck\" secondAttribute=\"top\" constant=\"42\" id=\"28w-GL-77J\"/>\n                        <constraint firstItem=\"h41-zX-k7q\" firstAttribute=\"top\" secondItem=\"fFG-yi-lT4\" secondAttribute=\"bottom\" constant=\"20\" id=\"Cgr-xO-25x\"/>\n                        <constraint firstItem=\"fFG-yi-lT4\" firstAttribute=\"leading\" secondItem=\"GFp-Qd-4ck\" secondAttribute=\"leading\" constant=\"80\" id=\"Efy-hc-gPW\"/>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"fFG-yi-lT4\" secondAttribute=\"trailing\" constant=\"80\" id=\"GMo-7J-c8z\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"h41-zX-k7q\" secondAttribute=\"bottom\" constant=\"46\" id=\"mzE-eB-Mx9\"/>\n                        <constraint firstItem=\"h41-zX-k7q\" firstAttribute=\"centerX\" secondItem=\"GFp-Qd-4ck\" secondAttribute=\"centerX\" id=\"n8M-sY-58X\"/>\n                    </constraints>\n                </customView>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Uxd-YG-qsq\">\n                    <rect key=\"frame\" x=\"118\" y=\"269\" width=\"284\" height=\"20\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1896\">\n                            <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"91\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Type of Proxy:\" id=\"1921\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1905\">\n                            <rect key=\"frame\" x=\"92\" y=\"-4\" width=\"196\" height=\"25\"/>\n                            <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"1906\">\n                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" title=\"OtherViews\" id=\"1907\">\n                                    <items>\n                                        <menuItem title=\"None\" id=\"1912\"/>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"1908\"/>\n                                        <menuItem title=\"Automatic\" tag=\"1\" id=\"1909\"/>\n                                        <menuItem title=\"SOCKS 4 Proxy\" tag=\"4\" id=\"1911\"/>\n                                        <menuItem title=\"SOCKS 5 Proxy\" tag=\"5\" id=\"1910\"/>\n                                        <menuItem title=\"HTTP Proxy (Anonymous)\" tag=\"6\" id=\"Fud-O2-fHR\"/>\n                                        <menuItem title=\"Tor Anonymity Network\" tag=\"8\" id=\"YN2-z6-RkW\"/>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"1896\" id=\"1gR-pC-1ht\"/>\n                                <action selector=\"proxyTypeChanged:\" target=\"-2\" id=\"2289\"/>\n                            </connections>\n                        </popUpButton>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1978\">\n                    <rect key=\"frame\" x=\"211\" y=\"249\" width=\"236\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"This option requires a reconnect to apply\" id=\"1979\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <scrollView borderType=\"none\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" hasVerticalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CGs-VH-G07\">\n                    <rect key=\"frame\" x=\"48\" y=\"30\" width=\"424\" height=\"43\"/>\n                    <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"Of6-s1-mF9\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"424\" height=\"43\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <textView editable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" findStyle=\"panel\" id=\"hIR-WT-lAK\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"42\" width=\"424\" height=\"43\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <color key=\"textColor\" red=\"1\" green=\"0.14913141730000001\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <size key=\"minSize\" width=\"424\" height=\"43\"/>\n                                <size key=\"maxSize\" width=\"500\" height=\"10000000\"/>\n                                <attributedString key=\"textStorage\">\n                                    <fragment content=\"Warning: \">\n                                        <attributes>\n                                            <color key=\"NSColor\" red=\"1\" green=\"0.14913141730000001\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"Images and other media that is displayed inline with chat uses whichever proxy, if any, is configured in the \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"Network section of System Settings\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                            <font key=\"NSOriginalFont\" metaFont=\"smallSystemBold\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\". It \">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\"does not\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystemBold\"/>\n                                            <font key=\"NSOriginalFont\" metaFont=\"smallSystemBold\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                            <integer key=\"NSUnderline\" value=\"1\"/>\n                                        </attributes>\n                                    </fragment>\n                                    <fragment content=\" pass through the proxy configured above.\">\n                                        <attributes>\n                                            <color key=\"NSColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <font key=\"NSFont\" metaFont=\"smallSystem\"/>\n                                            <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\"/>\n                                        </attributes>\n                                    </fragment>\n                                </attributedString>\n                                <color key=\"insertionPointColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"43\" id=\"zce-C9-Grj\"/>\n                    </constraints>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"POy-MI-Qzw\">\n                        <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"nDR-Ag-7ot\">\n                        <rect key=\"frame\" x=\"224\" y=\"1\" width=\"15\" height=\"133\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                </scrollView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"Uxd-YG-qsq\" firstAttribute=\"top\" secondItem=\"1887\" secondAttribute=\"top\" constant=\"31\" id=\"55m-8p-LBo\"/>\n                <constraint firstItem=\"1978\" firstAttribute=\"leading\" secondItem=\"1905\" secondAttribute=\"leading\" id=\"6qD-eN-6gX\"/>\n                <constraint firstItem=\"KJ6-gu-xq3\" firstAttribute=\"top\" secondItem=\"1978\" secondAttribute=\"bottom\" id=\"D0N-81-AYV\"/>\n                <constraint firstItem=\"yql-kd-PP5\" firstAttribute=\"top\" secondItem=\"1978\" secondAttribute=\"bottom\" id=\"G1q-Iw-zLv\"/>\n                <constraint firstItem=\"GFp-Qd-4ck\" firstAttribute=\"top\" secondItem=\"1978\" secondAttribute=\"bottom\" id=\"Jxf-3T-ZlL\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"GFp-Qd-4ck\" secondAttribute=\"trailing\" id=\"MKp-pg-Kjv\"/>\n                <constraint firstItem=\"Uxd-YG-qsq\" firstAttribute=\"centerX\" secondItem=\"1887\" secondAttribute=\"centerX\" id=\"Q4k-Bc-ucu\"/>\n                <constraint firstItem=\"GFp-Qd-4ck\" firstAttribute=\"leading\" secondItem=\"1887\" secondAttribute=\"leading\" id=\"RI6-SU-HdD\"/>\n                <constraint firstItem=\"CGs-VH-G07\" firstAttribute=\"top\" secondItem=\"yql-kd-PP5\" secondAttribute=\"bottom\" id=\"UNC-3p-YVo\"/>\n                <constraint firstItem=\"1978\" firstAttribute=\"top\" secondItem=\"Uxd-YG-qsq\" secondAttribute=\"bottom\" constant=\"5\" id=\"Vgn-Bq-eug\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"CGs-VH-G07\" secondAttribute=\"trailing\" constant=\"48\" id=\"Wvo-Vb-qx0\"/>\n                <constraint firstItem=\"CGs-VH-G07\" firstAttribute=\"top\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"bottom\" id=\"YMW-81-mvB\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"yql-kd-PP5\" secondAttribute=\"trailing\" id=\"dNg-Ep-EcJ\"/>\n                <constraint firstItem=\"KJ6-gu-xq3\" firstAttribute=\"leading\" secondItem=\"1887\" secondAttribute=\"leading\" id=\"gca-t1-d8e\"/>\n                <constraint firstItem=\"CGs-VH-G07\" firstAttribute=\"leading\" secondItem=\"1887\" secondAttribute=\"leading\" constant=\"48\" id=\"kRu-eF-vfK\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"CGs-VH-G07\" secondAttribute=\"bottom\" constant=\"30\" id=\"mKa-Wd-Ww9\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"1978\" secondAttribute=\"trailing\" constant=\"20\" id=\"srE-2H-sUb\"/>\n                <constraint firstItem=\"CGs-VH-G07\" firstAttribute=\"top\" secondItem=\"GFp-Qd-4ck\" secondAttribute=\"bottom\" id=\"u8w-9G-Ks5\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"KJ6-gu-xq3\" secondAttribute=\"trailing\" id=\"vQz-A4-oki\"/>\n                <constraint firstAttribute=\"width\" constant=\"520\" id=\"vYP-hQ-Hyo\"/>\n                <constraint firstItem=\"yql-kd-PP5\" firstAttribute=\"leading\" secondItem=\"1887\" secondAttribute=\"leading\" id=\"x6U-Nw-wHo\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"582\" y=\"4674.5\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2078\" userLabel=\"Flood Control\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1gq-lL-Ur6\">\n                    <rect key=\"frame\" x=\"93\" y=\"35\" width=\"335\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"The options presented above require a reconnect to apply.\" id=\"MJ0-IQ-dNi\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CGo-eo-J2e\">\n                    <rect key=\"frame\" x=\"33\" y=\"249\" width=\"376\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Do not send more than X number of commands in Y seconds.\" id=\"XQt-eN-ufQ\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rXs-B6-ItZ\">\n                    <rect key=\"frame\" x=\"400\" y=\"124\" width=\"85\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Current Value:\" id=\"U5o-dB-jmW\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"displayPatternValue1\" keyPath=\"self.floodControlDelayTimerSliderTempValue\" id=\"fUV-xU-dw1\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSDisplayPattern\">Current Value: %{value1}@</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"w11-kJ-IPr\">\n                    <rect key=\"frame\" x=\"402\" y=\"181\" width=\"85\" height=\"15\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Current Value:\" id=\"eMt-al-rqd\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                    <connections>\n                        <binding destination=\"-2\" name=\"displayPatternValue1\" keyPath=\"self.floodControlMessageCountSliderTempValue\" id=\"Iip-VB-iS5\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSDisplayPattern\">Current Value: %{value1}@</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Itb-Ee-5gX\">\n                    <rect key=\"frame\" x=\"45\" y=\"124\" width=\"142\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Y: Number of seconds:\" id=\"Jay-s8-9Xn\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" spacing=\"7\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bJz-Am-LvT\">\n                    <rect key=\"frame\" x=\"47\" y=\"96\" width=\"436\" height=\"20\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9b4-kF-7N0\">\n                            <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"10\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"1\" id=\"zP6-2E-iaW\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O6l-eN-3Uc\">\n                            <rect key=\"frame\" x=\"11\" y=\"-6\" width=\"404\" height=\"28\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" constant=\"400\" id=\"3g8-eg-PIY\"/>\n                            </constraints>\n                            <sliderCell key=\"cell\" state=\"on\" alignment=\"left\" minValue=\"1\" maxValue=\"60\" doubleValue=\"2\" tickMarkPosition=\"below\" numberOfTickMarks=\"60\" allowsTickMarkValuesOnly=\"YES\" sliderType=\"linear\" id=\"Suc-bU-9RU\"/>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"Itb-Ee-5gX\" id=\"1qV-pR-HOf\"/>\n                                <binding destination=\"-2\" name=\"value\" keyPath=\"self.floodControlDelayTimerSliderTempValue\" id=\"ICJ-8T-e2n\"/>\n                            </connections>\n                        </slider>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pDB-qm-dyE\">\n                            <rect key=\"frame\" x=\"418\" y=\"3\" width=\"20\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"60\" id=\"9bE-uW-eqe\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Lqs-Qy-WoE\">\n                    <rect key=\"frame\" x=\"47\" y=\"153\" width=\"438\" height=\"20\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kGJ-aW-aWu\">\n                            <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"10\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"1\" id=\"ZNS-JS-fS4\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <slider verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RXW-HB-aEa\">\n                            <rect key=\"frame\" x=\"12\" y=\"-6\" width=\"404\" height=\"28\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" constant=\"400\" id=\"LhT-4u-1nw\"/>\n                            </constraints>\n                            <sliderCell key=\"cell\" state=\"on\" alignment=\"left\" minValue=\"1\" maxValue=\"60\" doubleValue=\"10\" tickMarkPosition=\"below\" numberOfTickMarks=\"60\" allowsTickMarkValuesOnly=\"YES\" sliderType=\"linear\" id=\"nbd-xl-Ad6\"/>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"0Af-cs-B5g\" id=\"9rF-h2-yOy\"/>\n                                <binding destination=\"-2\" name=\"value\" keyPath=\"self.floodControlMessageCountSliderTempValue\" id=\"5Wa-WZ-Qhz\"/>\n                            </connections>\n                        </slider>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sAt-Ob-XHX\">\n                            <rect key=\"frame\" x=\"420\" y=\"3\" width=\"20\" height=\"15\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"60\" id=\"y5u-45-pvs\">\n                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Af-cs-B5g\">\n                    <rect key=\"frame\" x=\"45\" y=\"181\" width=\"159\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"X: Number of commands:\" id=\"jHb-Iz-2jU\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"rXs-B6-ItZ\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Itb-Ee-5gX\" secondAttribute=\"trailing\" constant=\"20\" id=\"7eg-pP-vVB\"/>\n                <constraint firstItem=\"Lqs-Qy-WoE\" firstAttribute=\"top\" secondItem=\"0Af-cs-B5g\" secondAttribute=\"bottom\" constant=\"8\" id=\"8bp-yu-9QD\"/>\n                <constraint firstItem=\"rXs-B6-ItZ\" firstAttribute=\"firstBaseline\" secondItem=\"Itb-Ee-5gX\" secondAttribute=\"firstBaseline\" id=\"B7s-75-ML4\"/>\n                <constraint firstItem=\"w11-kJ-IPr\" firstAttribute=\"firstBaseline\" secondItem=\"0Af-cs-B5g\" secondAttribute=\"firstBaseline\" id=\"CQP-hN-Xkb\"/>\n                <constraint firstItem=\"0Af-cs-B5g\" firstAttribute=\"leading\" secondItem=\"Lqs-Qy-WoE\" secondAttribute=\"leading\" id=\"Ffb-MP-GmW\"/>\n                <constraint firstItem=\"CGo-eo-J2e\" firstAttribute=\"top\" secondItem=\"2078\" secondAttribute=\"top\" constant=\"35\" id=\"H6j-Zf-wUX\"/>\n                <constraint firstItem=\"0Af-cs-B5g\" firstAttribute=\"leading\" secondItem=\"2078\" secondAttribute=\"leading\" constant=\"47\" id=\"P65-zu-vBd\"/>\n                <constraint firstItem=\"0Af-cs-B5g\" firstAttribute=\"top\" secondItem=\"CGo-eo-J2e\" secondAttribute=\"bottom\" constant=\"52\" id=\"SxS-cd-PDh\"/>\n                <constraint firstItem=\"Itb-Ee-5gX\" firstAttribute=\"leading\" secondItem=\"bJz-Am-LvT\" secondAttribute=\"leading\" id=\"WGm-Ht-1T5\"/>\n                <constraint firstItem=\"CGo-eo-J2e\" firstAttribute=\"leading\" secondItem=\"2078\" secondAttribute=\"leading\" constant=\"35\" id=\"Yn2-kb-Ij1\"/>\n                <constraint firstItem=\"1gq-lL-Ur6\" firstAttribute=\"centerX\" secondItem=\"2078\" secondAttribute=\"centerX\" id=\"aT5-KN-Bfy\"/>\n                <constraint firstItem=\"bJz-Am-LvT\" firstAttribute=\"top\" secondItem=\"Itb-Ee-5gX\" secondAttribute=\"bottom\" constant=\"8\" id=\"ach-re-70n\"/>\n                <constraint firstItem=\"w11-kJ-IPr\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"0Af-cs-B5g\" secondAttribute=\"trailing\" constant=\"20\" id=\"fZk-EO-2gz\"/>\n                <constraint firstItem=\"Itb-Ee-5gX\" firstAttribute=\"leading\" secondItem=\"0Af-cs-B5g\" secondAttribute=\"leading\" id=\"hwa-og-GfR\"/>\n                <constraint firstItem=\"Itb-Ee-5gX\" firstAttribute=\"top\" secondItem=\"Lqs-Qy-WoE\" secondAttribute=\"bottom\" constant=\"13\" id=\"lcw-q9-jo5\"/>\n                <constraint firstItem=\"w11-kJ-IPr\" firstAttribute=\"trailing\" secondItem=\"Lqs-Qy-WoE\" secondAttribute=\"trailing\" id=\"qLi-N8-kyw\"/>\n                <constraint firstItem=\"rXs-B6-ItZ\" firstAttribute=\"trailing\" secondItem=\"bJz-Am-LvT\" secondAttribute=\"trailing\" id=\"vWH-mg-odb\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"CGo-eo-J2e\" secondAttribute=\"trailing\" constant=\"35\" id=\"xcr-1J-iZh\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"1gq-lL-Ur6\" secondAttribute=\"bottom\" constant=\"35\" id=\"xrS-C0-31F\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"582\" y=\"5064\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2488\" userLabel=\"Networking View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7Re-Oa-iNx\">\n                    <rect key=\"frame\" x=\"33\" y=\"101\" width=\"306\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Validate the certificate chain when connecting\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"dz6-nj-V0I\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                </button>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"6\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p7D-wU-ocI\">\n                    <rect key=\"frame\" x=\"35\" y=\"138\" width=\"357\" height=\"60\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2531\">\n                            <rect key=\"frame\" x=\"-2\" y=\"43\" width=\"342\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Periodically PING the server to verify the connection\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"2532\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2536\">\n                            <rect key=\"frame\" x=\"-2\" y=\"21\" width=\"359\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Force a disconnect when no PING response is received\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"2537\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"w5K-aH-URS\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"306\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Force a disconnect when reachability changes\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"mLI-Vm-l2s\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"46W-2g-sYj\">\n                    <rect key=\"frame\" x=\"33\" y=\"71\" width=\"88\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Cipher suites:\" id=\"Qfh-rz-IdC\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xo6-bb-4qn\">\n                    <rect key=\"frame\" x=\"124\" y=\"64\" width=\"252\" height=\"25\"/>\n                    <popUpButtonCell key=\"cell\" type=\"push\" title=\"Default list of cipher suites\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"mVB-Hg-Fuc\" id=\"xlI-w6-ABl\">\n                        <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                        <menu key=\"menu\" id=\"nRK-8Z-6Pd\">\n                            <items>\n                                <menuItem title=\"Default list of cipher suites\" state=\"on\" id=\"mVB-Hg-Fuc\"/>\n                                <menuItem title=\"Version 7.0.0 list of cipher suites\" tag=\"2\" id=\"rag-NS-0Qi\"/>\n                                <menuItem title=\"Version 5.2.7 list of cipher suites\" tag=\"1\" id=\"DrH-DE-jbQ\"/>\n                                <menuItem title=\"Do not prefer specific cipher suites\" tag=\"100\" id=\"TY8-cf-i4B\"/>\n                            </items>\n                        </menu>\n                    </popUpButtonCell>\n                    <connections>\n                        <action selector=\"preferredCipherSuitesChanged:\" target=\"-2\" id=\"9Dg-uU-k8K\"/>\n                    </connections>\n                </popUpButton>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BoR-WW-sT2\">\n                    <rect key=\"frame\" x=\"373\" y=\"61\" width=\"89\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"View List\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"LuK-ZI-qT9\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"preferredCipherSuitesViewList:\" target=\"-2\" id=\"UQs-lq-m95\"/>\n                    </connections>\n                </button>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"T3E-ox-F6h\">\n                    <rect key=\"frame\" x=\"33\" y=\"216\" width=\"96\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Connect using:\" id=\"B8q-jl-QtB\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XTj-LM-sfF\">\n                    <rect key=\"frame\" x=\"135\" y=\"216\" width=\"272\" height=\"16\"/>\n                    <subviews>\n                        <button tag=\"1\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Doi-rA-9aF\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"53\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"IPv4\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"rrw-wu-OBL\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"preferredInternetProtocolChanged:\" target=\"-2\" id=\"IdA-5M-B2J\"/>\n                            </connections>\n                        </button>\n                        <button tag=\"2\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dd4-fZ-E2b\">\n                            <rect key=\"frame\" x=\"57\" y=\"-1\" width=\"53\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"IPv6\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"PI4-um-V5J\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"preferredInternetProtocolChanged:\" target=\"-2\" id=\"xAK-Lf-84J\"/>\n                            </connections>\n                        </button>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zOI-7i-HTQ\">\n                            <rect key=\"frame\" x=\"116\" y=\"-1\" width=\"156\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"radio\" title=\"Automatically choose\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"YkZ-0c-BeT\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"preferredInternetProtocolChanged:\" target=\"-2\" id=\"1Fm-cM-XZY\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"zOI-7i-HTQ\" firstAttribute=\"firstBaseline\" secondItem=\"dd4-fZ-E2b\" secondAttribute=\"firstBaseline\" id=\"80a-WI-2kx\"/>\n                        <constraint firstItem=\"zOI-7i-HTQ\" firstAttribute=\"leading\" secondItem=\"dd4-fZ-E2b\" secondAttribute=\"trailing\" constant=\"8\" id=\"8lF-EN-oGD\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"Doi-rA-9aF\" secondAttribute=\"bottom\" id=\"P3i-CI-pQr\"/>\n                        <constraint firstItem=\"Doi-rA-9aF\" firstAttribute=\"leading\" secondItem=\"XTj-LM-sfF\" secondAttribute=\"leading\" id=\"d0S-T3-z5I\"/>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"zOI-7i-HTQ\" secondAttribute=\"trailing\" id=\"jSF-lU-Vod\"/>\n                        <constraint firstItem=\"Doi-rA-9aF\" firstAttribute=\"top\" secondItem=\"XTj-LM-sfF\" secondAttribute=\"top\" id=\"odt-d6-y8f\"/>\n                        <constraint firstItem=\"dd4-fZ-E2b\" firstAttribute=\"firstBaseline\" secondItem=\"Doi-rA-9aF\" secondAttribute=\"firstBaseline\" id=\"qWG-r7-9lh\"/>\n                        <constraint firstItem=\"dd4-fZ-E2b\" firstAttribute=\"leading\" secondItem=\"Doi-rA-9aF\" secondAttribute=\"trailing\" constant=\"8\" id=\"zvR-y2-ngF\"/>\n                    </constraints>\n                </customView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"BoR-WW-sT2\" firstAttribute=\"leading\" secondItem=\"xo6-bb-4qn\" secondAttribute=\"trailing\" constant=\"8\" id=\"2F2-UY-sVm\"/>\n                <constraint firstItem=\"7Re-Oa-iNx\" firstAttribute=\"leading\" secondItem=\"2488\" secondAttribute=\"leading\" constant=\"35\" id=\"4S3-y7-p8d\"/>\n                <constraint firstItem=\"BoR-WW-sT2\" firstAttribute=\"firstBaseline\" secondItem=\"xo6-bb-4qn\" secondAttribute=\"firstBaseline\" id=\"6Ue-fC-FR7\"/>\n                <constraint firstItem=\"46W-2g-sYj\" firstAttribute=\"leading\" secondItem=\"2488\" secondAttribute=\"leading\" constant=\"35\" id=\"Dm9-Ps-yoM\"/>\n                <constraint firstItem=\"T3E-ox-F6h\" firstAttribute=\"firstBaseline\" secondItem=\"Doi-rA-9aF\" secondAttribute=\"firstBaseline\" id=\"Hor-qb-qLM\"/>\n                <constraint firstItem=\"p7D-wU-ocI\" firstAttribute=\"leading\" secondItem=\"2488\" secondAttribute=\"leading\" constant=\"35\" id=\"LAP-p1-YfY\"/>\n                <constraint firstItem=\"46W-2g-sYj\" firstAttribute=\"firstBaseline\" secondItem=\"xo6-bb-4qn\" secondAttribute=\"firstBaseline\" id=\"VYA-cR-MKi\"/>\n                <constraint firstItem=\"7Re-Oa-iNx\" firstAttribute=\"top\" secondItem=\"p7D-wU-ocI\" secondAttribute=\"bottom\" constant=\"20\" id=\"ZKw-NT-npB\"/>\n                <constraint firstItem=\"p7D-wU-ocI\" firstAttribute=\"top\" secondItem=\"XTj-LM-sfF\" secondAttribute=\"bottom\" constant=\"18\" id=\"ZPV-D4-mIq\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"BoR-WW-sT2\" secondAttribute=\"trailing\" constant=\"20\" id=\"ZmU-Gk-p56\"/>\n                <constraint firstItem=\"xo6-bb-4qn\" firstAttribute=\"leading\" secondItem=\"46W-2g-sYj\" secondAttribute=\"trailing\" constant=\"8\" id=\"d6Q-qc-hXF\"/>\n                <constraint firstItem=\"xo6-bb-4qn\" firstAttribute=\"top\" secondItem=\"7Re-Oa-iNx\" secondAttribute=\"bottom\" constant=\"14\" id=\"j43-Ga-Ckd\"/>\n                <constraint firstItem=\"XTj-LM-sfF\" firstAttribute=\"leading\" secondItem=\"T3E-ox-F6h\" secondAttribute=\"trailing\" constant=\"8\" id=\"lKT-kW-umO\"/>\n                <constraint firstItem=\"T3E-ox-F6h\" firstAttribute=\"leading\" secondItem=\"2488\" secondAttribute=\"leading\" constant=\"35\" id=\"o3v-dH-5fi\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"7Re-Oa-iNx\" secondAttribute=\"trailing\" constant=\"20\" id=\"tdl-t1-96o\"/>\n                <constraint firstItem=\"T3E-ox-F6h\" firstAttribute=\"top\" secondItem=\"2488\" secondAttribute=\"top\" constant=\"68\" id=\"vnj-fm-KQ5\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"582\" y=\"5520\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ti4-Q4-cYX\" userLabel=\"CertFP View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zU1-IR-zpt\">\n                    <rect key=\"frame\" x=\"33\" y=\"249\" width=\"339\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Select a certificate to send when you connect securely.\" id=\"rIl-yx-VEH\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" spacing=\"12\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"J9k-kO-pE8\">\n                    <rect key=\"frame\" x=\"131\" y=\"35\" width=\"259\" height=\"20\"/>\n                    <subviews>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sab-tw-7nn\">\n                            <rect key=\"frame\" x=\"-7\" y=\"-7\" width=\"136\" height=\"32\"/>\n                            <buttonCell key=\"cell\" type=\"push\" title=\"Reset Certificate\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"39U-39-9tk\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <accessibility description=\"Reset Certificate\"/>\n                            <connections>\n                                <action selector=\"onClientCertificateResetRequested:\" target=\"-2\" id=\"hl9-sg-Zmd\"/>\n                            </connections>\n                        </button>\n                        <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"l36-PJ-JBU\">\n                            <rect key=\"frame\" x=\"127\" y=\"-7\" width=\"139\" height=\"32\"/>\n                            <buttonCell key=\"cell\" type=\"push\" title=\"Select Certificate\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"uH8-BL-itx\">\n                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <accessibility description=\"Select Certificate\"/>\n                            <connections>\n                                <action selector=\"onClientCertificateChangeRequested:\" target=\"-2\" id=\"WPP-H2-sBy\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <gridView xPlacement=\"trailing\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GZe-xb-lrQ\">\n                    <rect key=\"frame\" x=\"20\" y=\"76\" width=\"480\" height=\"148\"/>\n                    <rows>\n                        <gridRow yPlacement=\"top\" height=\"36\" id=\"y0w-uO-wey\"/>\n                        <gridRow id=\"LVM-ri-oUP\"/>\n                        <gridRow id=\"mRF-0R-krg\"/>\n                        <gridRow id=\"1CG-bD-ulB\"/>\n                        <gridRow id=\"DDA-TD-JgL\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn xPlacement=\"fill\" width=\"137\" id=\"mzu-pc-PbB\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"bSr-v0-1FE\"/>\n                        <gridColumn xPlacement=\"fill\" id=\"70M-PD-rGb\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"y0w-uO-wey\" column=\"mzu-pc-PbB\" id=\"bNC-ND-dl8\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vOo-Hg-7M0\">\n                                <rect key=\"frame\" x=\"-2\" y=\"132\" width=\"141\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Certificate Name:\" usesSingleLineMode=\"YES\" id=\"pxF-PC-Aax\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"y0w-uO-wey\" column=\"bSr-v0-1FE\" id=\"rAb-fO-YcL\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nly-3d-FIq\">\n                                <rect key=\"frame\" x=\"143\" y=\"132\" width=\"279\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Label\" usesSingleLineMode=\"YES\" id=\"bvj-Qr-Ebk\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"vOo-Hg-7M0\" id=\"7hz-E0-Nax\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"y0w-uO-wey\" column=\"70M-PD-rGb\" id=\"0lV-42-QBZ\"/>\n                        <gridCell row=\"LVM-ri-oUP\" column=\"mzu-pc-PbB\" id=\"Pre-xR-cqo\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eya-pw-9DN\">\n                                <rect key=\"frame\" x=\"-2\" y=\"87\" width=\"141\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"SHA-512 Fingerprint:\" usesSingleLineMode=\"YES\" id=\"dJe-xa-bmY\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"LVM-ri-oUP\" column=\"bSr-v0-1FE\" id=\"7JN-IO-EJT\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ou1-Bl-kz1\">\n                                <rect key=\"frame\" x=\"143\" y=\"87\" width=\"279\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Label\" usesSingleLineMode=\"YES\" id=\"Cy6-oh-U2a\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"eya-pw-9DN\" id=\"SOi-tq-3BH\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"LVM-ri-oUP\" column=\"70M-PD-rGb\" id=\"wXb-Te-bHe\">\n                            <button key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YAo-Ly-Sf7\">\n                                <rect key=\"frame\" x=\"421\" y=\"77\" width=\"66\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Copy\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"305-Ff-AM7\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Copy SHA-1 Fingerprint\"/>\n                                <connections>\n                                    <action selector=\"onClientCertificateFingerprintSHA512CopyRequested:\" target=\"-2\" id=\"Vep-hQ-exc\"/>\n                                </connections>\n                            </button>\n                        </gridCell>\n                        <gridCell row=\"mRF-0R-krg\" column=\"mzu-pc-PbB\" id=\"fOI-GS-UCM\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fdC-a6-iNA\">\n                                <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"141\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"SHA-2 Fingerprint:\" usesSingleLineMode=\"YES\" id=\"jhF-Ix-th5\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"mRF-0R-krg\" column=\"bSr-v0-1FE\" id=\"QPa-gG-WYl\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2ie-9H-xb2\">\n                                <rect key=\"frame\" x=\"143\" y=\"59\" width=\"279\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Label\" usesSingleLineMode=\"YES\" id=\"Gbb-jh-4mY\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"fdC-a6-iNA\" id=\"e2A-FB-NXb\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"mRF-0R-krg\" column=\"70M-PD-rGb\" id=\"3tp-nU-Vew\">\n                            <button key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"758-2B-Ka3\">\n                                <rect key=\"frame\" x=\"421\" y=\"49\" width=\"66\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Copy\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"0nB-im-8PX\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Copy SHA-1 Fingerprint\"/>\n                                <connections>\n                                    <action selector=\"onClientCertificateFingerprintSHA2CopyRequested:\" target=\"-2\" id=\"LCp-4J-HEV\"/>\n                                </connections>\n                            </button>\n                        </gridCell>\n                        <gridCell row=\"1CG-bD-ulB\" column=\"mzu-pc-PbB\" id=\"IU7-Q5-HCF\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"h8M-bR-Uth\">\n                                <rect key=\"frame\" x=\"-2\" y=\"31\" width=\"141\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"SHA-1 Fingerprint:\" usesSingleLineMode=\"YES\" id=\"O13-rx-ewF\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"1CG-bD-ulB\" column=\"bSr-v0-1FE\" id=\"04Y-ei-D2h\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nFm-83-7HQ\">\n                                <rect key=\"frame\" x=\"143\" y=\"31\" width=\"279\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Label\" usesSingleLineMode=\"YES\" id=\"Sia-Zk-rSR\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"h8M-bR-Uth\" id=\"FA4-lA-8bN\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"1CG-bD-ulB\" column=\"70M-PD-rGb\" id=\"v42-Md-Umx\">\n                            <button key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f9F-WF-ubf\">\n                                <rect key=\"frame\" x=\"421\" y=\"21\" width=\"66\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Copy\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"rDo-70-T0D\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Copy MD5 Fingerprint\"/>\n                                <connections>\n                                    <action selector=\"onClientCertificateFingerprintSHA1CopyRequested:\" target=\"-2\" id=\"BkR-Tr-pMV\"/>\n                                </connections>\n                            </button>\n                        </gridCell>\n                        <gridCell row=\"DDA-TD-JgL\" column=\"mzu-pc-PbB\" id=\"Is8-DS-Eu3\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fm4-76-q5h\">\n                                <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"141\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"MD5 Fingerprint:\" usesSingleLineMode=\"YES\" id=\"Mmj-Ja-V8x\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"DDA-TD-JgL\" column=\"bSr-v0-1FE\" id=\"abJ-zN-WA0\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Grr-p8-MOF\">\n                                <rect key=\"frame\" x=\"143\" y=\"3\" width=\"279\" height=\"16\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" title=\"Label\" usesSingleLineMode=\"YES\" id=\"MCd-Ig-Szi\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"Fm4-76-q5h\" id=\"uCM-i6-5Tk\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"DDA-TD-JgL\" column=\"70M-PD-rGb\" id=\"l73-89-Bna\">\n                            <button key=\"contentView\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KJ9-QR-tAv\">\n                                <rect key=\"frame\" x=\"421\" y=\"-7\" width=\"66\" height=\"32\"/>\n                                <buttonCell key=\"cell\" type=\"push\" title=\"Copy\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ElY-gw-ZZB\">\n                                    <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                </buttonCell>\n                                <accessibility description=\"Copy MD5 Fingerprint\"/>\n                                <connections>\n                                    <action selector=\"onClientCertificateFingerprintMD5CopyRequested:\" target=\"-2\" id=\"fQM-JR-IE9\"/>\n                                </connections>\n                            </button>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"J9k-kO-pE8\" secondAttribute=\"bottom\" constant=\"35\" id=\"3V7-39-EdJ\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"GZe-xb-lrQ\" secondAttribute=\"trailing\" constant=\"20\" id=\"9Sk-PG-Z9d\"/>\n                <constraint firstItem=\"zU1-IR-zpt\" firstAttribute=\"top\" secondItem=\"Ti4-Q4-cYX\" secondAttribute=\"top\" constant=\"35\" id=\"C1v-NB-gRo\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"zU1-IR-zpt\" secondAttribute=\"trailing\" constant=\"35\" id=\"GTo-FS-aXG\"/>\n                <constraint firstItem=\"GZe-xb-lrQ\" firstAttribute=\"leading\" secondItem=\"Ti4-Q4-cYX\" secondAttribute=\"leading\" constant=\"20\" id=\"PpV-Z4-0E0\"/>\n                <constraint firstItem=\"GZe-xb-lrQ\" firstAttribute=\"centerY\" secondItem=\"Ti4-Q4-cYX\" secondAttribute=\"centerY\" id=\"Zye-gB-HMi\"/>\n                <constraint firstItem=\"zU1-IR-zpt\" firstAttribute=\"leading\" secondItem=\"Ti4-Q4-cYX\" secondAttribute=\"leading\" constant=\"35\" id=\"nF1-La-ZqG\"/>\n                <constraint firstItem=\"J9k-kO-pE8\" firstAttribute=\"centerX\" secondItem=\"Ti4-Q4-cYX\" secondAttribute=\"centerX\" id=\"pqd-xG-SJj\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"582\" y=\"5953\"/>\n        </customView>\n        <menu id=\"yYJ-qd-Dm2\">\n            <items>\n                <menuItem title=\"Add User Ignore Entry\" tag=\"3\" id=\"Mxd-76-s9L\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"addAddressBookEntry:\" target=\"-2\" id=\"5e0-v6-i7r\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Add User Tracking Entry\" tag=\"4\" id=\"Ju6-ey-oG4\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"addAddressBookEntry:\" target=\"-2\" id=\"4Ht-2r-Dp6\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"328.5\" y=\"557.5\"/>\n        </menu>\n        <userDefaultsController id=\"iuc-Sg-eeB\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O3J-xl-nwg\" userLabel=\"Redundancy\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"300\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I5e-l8-5t3\">\n                    <rect key=\"frame\" x=\"33\" y=\"217\" width=\"454\" height=\"48\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"SnQ-4b-NG2\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">Textual is capable of automatically connecting to one or more alternate servers if the primary server fails to connect. Click the button presented below to modify the alternate servers for this connection.</string>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"InI-Fw-HoN\">\n                    <rect key=\"frame\" x=\"168\" y=\"160\" width=\"185\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Modify Alternate Servers\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"8N1-4l-slN\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"editSeverEndpoints:\" target=\"-2\" id=\"p5S-03-DTi\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"I5e-l8-5t3\" firstAttribute=\"leading\" secondItem=\"O3J-xl-nwg\" secondAttribute=\"leading\" constant=\"35\" id=\"Cqb-qW-NO5\"/>\n                <constraint firstItem=\"I5e-l8-5t3\" firstAttribute=\"top\" secondItem=\"O3J-xl-nwg\" secondAttribute=\"top\" constant=\"35\" id=\"FVa-gl-UpL\"/>\n                <constraint firstItem=\"InI-Fw-HoN\" firstAttribute=\"top\" secondItem=\"I5e-l8-5t3\" secondAttribute=\"bottom\" constant=\"30\" id=\"Okx-lj-vGZ\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"I5e-l8-5t3\" secondAttribute=\"trailing\" constant=\"35\" id=\"fNj-YT-k5G\"/>\n                <constraint firstItem=\"InI-Fw-HoN\" firstAttribute=\"centerX\" secondItem=\"O3J-xl-nwg\" secondAttribute=\"centerX\" id=\"vRU-oE-jRr\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"582\" y=\"6373\"/>\n        </customView>\n        <arrayController objectClassName=\"IRCAddressBookEntry\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"aez-lt-zBV\">\n            <classReference key=\"objectClass\" className=\"IRCAddressBookEntry\"/>\n        </arrayController>\n        <arrayController objectClassName=\"IRCChannelConfig\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" clearsFilterPredicateOnInsertion=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"XlX-J4-ZJt\">\n            <classReference key=\"objectClass\" className=\"IRCChannelConfig\"/>\n        </arrayController>\n        <arrayController objectClassName=\"IRCHighlightMatchCondition\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"XVW-tl-Aro\">\n            <classReference key=\"objectClass\" className=\"IRCHighlightMatchCondition\"/>\n        </arrayController>\n        <arrayController objectClassName=\"IRCServer\" avoidsEmptySelection=\"NO\" clearsFilterPredicateOnInsertion=\"NO\" automaticallyRearrangesObjects=\"YES\" id=\"Wea-hF-mxO\">\n            <classReference key=\"objectClass\" className=\"IRCServer\"/>\n        </arrayController>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"18\" height=\"17\"/>\n        <image name=\"NSRemoveTemplate\" width=\"18\" height=\"5\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TDCWelcomeSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"32700.99.1234\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"22690\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TDCWelcomeSheet\">\n            <connections>\n                <outlet property=\"addChannelButton\" destination=\"154\" id=\"190\"/>\n                <outlet property=\"autoConnectCheck\" destination=\"151\" id=\"191\"/>\n                <outlet property=\"cancelButton\" destination=\"153\" id=\"192\"/>\n                <outlet property=\"channelTable\" destination=\"173\" id=\"193\"/>\n                <outlet property=\"deleteChannelButton\" destination=\"155\" id=\"194\"/>\n                <outlet property=\"nicknameTextField\" destination=\"146\" id=\"naM-zo-iUY\"/>\n                <outlet property=\"okButton\" destination=\"152\" id=\"197\"/>\n                <outlet property=\"serverAddressComboBox\" destination=\"216\" id=\"jpq-Eq-C7H\"/>\n                <outlet property=\"sheet\" destination=\"143\" id=\"208\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"143\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"821\" y=\"627\" width=\"400\" height=\"469\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"144\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"400\" height=\"482\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"154\">\n                        <rect key=\"frame\" x=\"109\" y=\"146\" width=\"30\" height=\"23\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"166\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" constant=\"21\" id=\"1MS-cr-HIs\"/>\n                            <constraint firstAttribute=\"width\" constant=\"30\" id=\"QKX-4x-XM5\"/>\n                        </constraints>\n                        <accessibility description=\"Add Channel\"/>\n                        <connections>\n                            <action selector=\"onAddChannel:\" target=\"-2\" id=\"189\"/>\n                        </connections>\n                    </button>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"201\">\n                        <rect key=\"frame\" x=\"20\" y=\"58\" width=\"360\" height=\"5\"/>\n                    </box>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"153\">\n                        <rect key=\"frame\" x=\"194\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"167\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <accessibility description=\"Cancel\"/>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"209\"/>\n                        </connections>\n                    </button>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zqh-Vb-fjj\">\n                        <rect key=\"frame\" x=\"20\" y=\"393\" width=\"69\" height=\"69\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"69\" id=\"3sw-im-CB0\"/>\n                            <constraint firstAttribute=\"width\" secondItem=\"zqh-Vb-fjj\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"udu-Tc-oQa\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"0YK-op-vRE\"/>\n                        <accessibility description=\"Textual Logo\"/>\n                    </imageView>\n                    <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"151\">\n                        <rect key=\"frame\" x=\"240\" y=\"149\" width=\"140\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Connect on launch\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"169\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"155\">\n                        <rect key=\"frame\" x=\"140\" y=\"146\" width=\"30\" height=\"23\"/>\n                        <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"only\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"165\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Remove Selected Channel(s)\"/>\n                        <connections>\n                            <action selector=\"onDeleteChannel:\" target=\"-2\" id=\"188\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"152\">\n                        <rect key=\"frame\" x=\"268\" y=\"13\" width=\"119\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Start Chatting\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"168\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <accessibility description=\"Finish Setup\"/>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"210\"/>\n                        </connections>\n                    </button>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"160\">\n                        <rect key=\"frame\" x=\"107\" y=\"79\" width=\"275\" height=\"60\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"left\" id=\"161\">\n                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                            <string key=\"title\">Additional options including NickServ password, username, real name, etc. can be edited later by control clicking the connection and opening “Server Properties”.</string>\n                            <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rdf-pc-4oE\">\n                        <rect key=\"frame\" x=\"20\" y=\"364\" width=\"360\" height=\"5\"/>\n                    </box>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I1L-Fi-uaP\">\n                        <rect key=\"frame\" x=\"111\" y=\"385\" width=\"267\" height=\"45\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"UqM-De-aP8\">\n                            <font key=\"font\" metaFont=\"cellTitle\"/>\n                            <string key=\"title\">To get started, select a network to connect to using the the control labeled “Destination”, or manually enter the desired server address.</string>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"157\">\n                        <rect key=\"frame\" x=\"146\" y=\"438\" width=\"198\" height=\"24\"/>\n                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" title=\"Welcome to Textual!\" id=\"163\">\n                            <font key=\"font\" metaFont=\"systemBold\" size=\"20\"/>\n                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <gridView xPlacement=\"fill\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ybn-lr-Sxh\">\n                        <rect key=\"frame\" x=\"28\" y=\"176\" width=\"352\" height=\"172\"/>\n                        <rows>\n                            <gridRow id=\"HT5-3A-iCq\"/>\n                            <gridRow id=\"TTO-Me-jbU\"/>\n                            <gridRow yPlacement=\"top\" rowAlignment=\"none\" id=\"nbT-Ef-ugk\"/>\n                        </rows>\n                        <columns>\n                            <gridColumn xPlacement=\"fill\" id=\"P0R-YZ-1Eo\"/>\n                            <gridColumn xPlacement=\"fill\" id=\"O86-lf-hU6\"/>\n                        </columns>\n                        <gridCells>\n                            <gridCell row=\"HT5-3A-iCq\" column=\"P0R-YZ-1Eo\" id=\"QmP-4Z-Hrh\">\n                                <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"148\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"154\" width=\"77\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Destination:\" id=\"176\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"HT5-3A-iCq\" column=\"O86-lf-hU6\" id=\"bzS-k7-Y6G\">\n                                <comboBox key=\"contentView\" focusRingType=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"216\" customClass=\"TVCValidatedComboBox\">\n                                    <rect key=\"frame\" x=\"80\" y=\"148\" width=\"275\" height=\"25\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"Rb3-E6-GR7\"/>\n                                    </constraints>\n                                    <comboBoxCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" borderStyle=\"bezel\" placeholderString=\"irc.example.com\" usesSingleLineMode=\"YES\" numberOfVisibleItems=\"5\" id=\"217\" customClass=\"TVCValidatedComboBoxCell\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </comboBoxCell>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"148\" id=\"SFX-7P-Cs7\"/>\n                                    </connections>\n                                </comboBox>\n                            </gridCell>\n                            <gridCell row=\"TTO-Me-jbU\" column=\"P0R-YZ-1Eo\" id=\"qPm-o6-YWz\">\n                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"751\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"145\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"124\" width=\"77\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Nickname:\" id=\"179\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"TTO-Me-jbU\" column=\"O86-lf-hU6\" id=\"7iN-nA-DA1\">\n                                <textField key=\"contentView\" focusRingType=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"146\" customClass=\"TVCValidatedTextField\">\n                                    <rect key=\"frame\" x=\"81\" y=\"120\" width=\"271\" height=\"22\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"o8z-xh-WN7\"/>\n                                    </constraints>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"Guest\" usesSingleLineMode=\"YES\" id=\"178\" customClass=\"TVCValidatedTextFieldCell\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"145\" id=\"5Xq-Kg-kdi\"/>\n                                    </connections>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"nbT-Ef-ugk\" column=\"P0R-YZ-1Eo\" id=\"ShC-7t-wLJ\">\n                                <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"150\">\n                                    <rect key=\"frame\" x=\"-2\" y=\"96\" width=\"77\" height=\"16\"/>\n                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Channels:\" id=\"170\">\n                                        <font key=\"font\" metaFont=\"system\"/>\n                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    </textFieldCell>\n                                </textField>\n                            </gridCell>\n                            <gridCell row=\"nbT-Ef-ugk\" column=\"O86-lf-hU6\" id=\"V3G-z0-mfn\">\n                                <scrollView key=\"contentView\" focusRingType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" allowsMagnification=\"YES\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"149\">\n                                    <rect key=\"frame\" x=\"81\" y=\"0.0\" width=\"271\" height=\"112\"/>\n                                    <clipView key=\"contentView\" id=\"UXg-Uw-XfU\">\n                                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"269\" height=\"110\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                        <subviews>\n                                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" columnSelection=\"YES\" multipleSelection=\"NO\" autosaveColumns=\"NO\" id=\"173\" customClass=\"TVCBasicTableView\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"269\" height=\"110\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <tableColumns>\n                                                    <tableColumn width=\"227\" minWidth=\"40\" maxWidth=\"1000\" id=\"174\">\n                                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                                        </tableHeaderCell>\n                                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"175\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <accessibility description=\"Channel Name\"/>\n                                                        </textFieldCell>\n                                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                    </tableColumn>\n                                                </tableColumns>\n                                                <connections>\n                                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"182\"/>\n                                                    <outlet property=\"delegate\" destination=\"-2\" id=\"181\"/>\n                                                    <outlet property=\"textDelegate\" destination=\"-2\" id=\"184\"/>\n                                                </connections>\n                                            </tableView>\n                                        </subviews>\n                                    </clipView>\n                                    <constraints>\n                                        <constraint firstAttribute=\"height\" constant=\"112\" id=\"M4L-ch-PqW\"/>\n                                    </constraints>\n                                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"171\">\n                                        <rect key=\"frame\" x=\"1\" y=\"95\" width=\"269\" height=\"16\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                    </scroller>\n                                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"172\">\n                                        <rect key=\"frame\" x=\"224\" y=\"0.0\" width=\"15\" height=\"119\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                    </scroller>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"150\" id=\"DgH-Xk-Dmu\"/>\n                                    </connections>\n                                </scrollView>\n                            </gridCell>\n                        </gridCells>\n                    </gridView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"155\" firstAttribute=\"top\" secondItem=\"154\" secondAttribute=\"top\" id=\"1H0-QS-r17\"/>\n                    <constraint firstItem=\"I1L-Fi-uaP\" firstAttribute=\"top\" secondItem=\"157\" secondAttribute=\"bottom\" constant=\"8\" id=\"25z-17-oOc\"/>\n                    <constraint firstItem=\"151\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"155\" secondAttribute=\"trailing\" constant=\"20\" id=\"4sh-mO-CZb\"/>\n                    <constraint firstItem=\"152\" firstAttribute=\"leading\" secondItem=\"153\" secondAttribute=\"trailing\" constant=\"12\" id=\"6a4-yX-GUD\"/>\n                    <constraint firstItem=\"153\" firstAttribute=\"firstBaseline\" secondItem=\"152\" secondAttribute=\"firstBaseline\" id=\"9e0-mB-P2G\"/>\n                    <constraint firstItem=\"154\" firstAttribute=\"leading\" secondItem=\"149\" secondAttribute=\"leading\" id=\"Atl-VW-Amn\"/>\n                    <constraint firstItem=\"155\" firstAttribute=\"leading\" secondItem=\"154\" secondAttribute=\"trailing\" constant=\"1\" id=\"BZW-Su-j2z\"/>\n                    <constraint firstItem=\"155\" firstAttribute=\"width\" secondItem=\"154\" secondAttribute=\"width\" id=\"BdA-Hf-ujs\"/>\n                    <constraint firstItem=\"157\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"zqh-Vb-fjj\" secondAttribute=\"trailing\" constant=\"20\" id=\"CoS-ew-Sgc\"/>\n                    <constraint firstItem=\"201\" firstAttribute=\"top\" secondItem=\"160\" secondAttribute=\"bottom\" constant=\"18\" id=\"Crc-IN-nzE\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"157\" secondAttribute=\"trailing\" constant=\"20\" id=\"EHk-Tu-mo3\"/>\n                    <constraint firstItem=\"157\" firstAttribute=\"top\" secondItem=\"144\" secondAttribute=\"top\" constant=\"20\" id=\"Gdr-h0-VpJ\"/>\n                    <constraint firstItem=\"157\" firstAttribute=\"centerX\" secondItem=\"I1L-Fi-uaP\" secondAttribute=\"centerX\" id=\"KIf-Je-pl7\"/>\n                    <constraint firstItem=\"151\" firstAttribute=\"trailing\" secondItem=\"149\" secondAttribute=\"trailing\" id=\"NKJ-3L-vMN\"/>\n                    <constraint firstItem=\"155\" firstAttribute=\"height\" secondItem=\"154\" secondAttribute=\"height\" id=\"NW1-SD-bZt\"/>\n                    <constraint firstItem=\"160\" firstAttribute=\"leading\" secondItem=\"154\" secondAttribute=\"leading\" id=\"Nls-eF-Y4Z\"/>\n                    <constraint firstItem=\"I1L-Fi-uaP\" firstAttribute=\"leading\" secondItem=\"zqh-Vb-fjj\" secondAttribute=\"trailing\" constant=\"24\" id=\"Ny1-94-0cP\"/>\n                    <constraint firstItem=\"zqh-Vb-fjj\" firstAttribute=\"top\" secondItem=\"144\" secondAttribute=\"top\" constant=\"20\" id=\"OnB-CL-bD3\"/>\n                    <constraint firstItem=\"Ybn-lr-Sxh\" firstAttribute=\"leading\" secondItem=\"144\" secondAttribute=\"leading\" constant=\"28\" id=\"QM1-0H-JT9\"/>\n                    <constraint firstItem=\"160\" firstAttribute=\"top\" secondItem=\"154\" secondAttribute=\"bottom\" constant=\"8\" id=\"QXa-2l-Qz0\"/>\n                    <constraint firstItem=\"201\" firstAttribute=\"trailing\" secondItem=\"Rdf-pc-4oE\" secondAttribute=\"trailing\" id=\"SpL-pU-aW5\"/>\n                    <constraint firstItem=\"153\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"144\" secondAttribute=\"leading\" constant=\"20\" id=\"TpP-LG-oTR\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Ybn-lr-Sxh\" secondAttribute=\"trailing\" constant=\"20\" id=\"UuZ-gY-6Dc\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"152\" secondAttribute=\"bottom\" constant=\"20\" id=\"W7g-XD-HX8\"/>\n                    <constraint firstItem=\"zqh-Vb-fjj\" firstAttribute=\"leading\" secondItem=\"144\" secondAttribute=\"leading\" constant=\"20\" id=\"XTR-Fi-0FS\"/>\n                    <constraint firstItem=\"160\" firstAttribute=\"trailing\" secondItem=\"151\" secondAttribute=\"trailing\" id=\"bWN-mz-pex\"/>\n                    <constraint firstItem=\"152\" firstAttribute=\"top\" secondItem=\"201\" secondAttribute=\"bottom\" constant=\"20\" id=\"ciT-EZ-l8k\"/>\n                    <constraint firstItem=\"Rdf-pc-4oE\" firstAttribute=\"top\" secondItem=\"I1L-Fi-uaP\" secondAttribute=\"bottom\" constant=\"18\" id=\"gln-mV-NKG\"/>\n                    <constraint firstItem=\"201\" firstAttribute=\"leading\" secondItem=\"Rdf-pc-4oE\" secondAttribute=\"leading\" id=\"juK-Vg-iQ1\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"I1L-Fi-uaP\" secondAttribute=\"trailing\" constant=\"24\" id=\"lCP-a1-GPo\"/>\n                    <constraint firstItem=\"Rdf-pc-4oE\" firstAttribute=\"centerX\" secondItem=\"144\" secondAttribute=\"centerX\" id=\"lG1-7D-Iie\"/>\n                    <constraint firstItem=\"Rdf-pc-4oE\" firstAttribute=\"leading\" secondItem=\"144\" secondAttribute=\"leading\" constant=\"20\" id=\"qB3-ND-CeN\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"152\" secondAttribute=\"trailing\" constant=\"20\" id=\"rIv-BO-piG\"/>\n                    <constraint firstItem=\"Ybn-lr-Sxh\" firstAttribute=\"top\" secondItem=\"Rdf-pc-4oE\" secondAttribute=\"bottom\" constant=\"18\" id=\"wxD-N4-HTb\"/>\n                    <constraint firstItem=\"151\" firstAttribute=\"centerY\" secondItem=\"155\" secondAttribute=\"centerY\" id=\"xEP-Ds-nnM\"/>\n                    <constraint firstItem=\"154\" firstAttribute=\"top\" secondItem=\"149\" secondAttribute=\"bottom\" constant=\"8\" id=\"y5h-29-ZEw\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"213\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"236\" y=\"233\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"18\" height=\"17\"/>\n        <image name=\"NSRemoveTemplate\" width=\"18\" height=\"5\"/>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TVCAlert.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23090\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23090\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TVCAlert\">\n            <connections>\n                <outlet property=\"firstButton\" destination=\"oPI-db-OzA\" id=\"JOm-yw-ibf\"/>\n                <outlet property=\"iconImageView\" destination=\"3\" id=\"97e-CJ-VFV\"/>\n                <outlet property=\"informativeTextField\" destination=\"7\" id=\"Le7-Va-H64\"/>\n                <outlet property=\"messageTextField\" destination=\"5\" id=\"i4G-bO-OfR\"/>\n                <outlet property=\"panel\" destination=\"pMN-4u-gqK\" id=\"UbP-kP-1xb\"/>\n                <outlet property=\"secondButton\" destination=\"Fv3-Bh-Zpr\" id=\"SMp-Mr-kL6\"/>\n                <outlet property=\"suppressionButton\" destination=\"ygL-Yb-5Mh\" id=\"CXb-ff-4AM\"/>\n                <outlet property=\"thirdButton\" destination=\"gz4-k0-7mW\" id=\"tuc-in-mBx\"/>\n                <outlet property=\"warningIconImageView\" destination=\"5kA-MY-GbC\" id=\"CLp-Sw-AQR\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Alert\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" titleVisibility=\"hidden\" id=\"pMN-4u-gqK\" customClass=\"NSPanel\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" documentModal=\"YES\"/>\n            <rect key=\"contentRect\" x=\"272\" y=\"172\" width=\"430\" height=\"140\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" id=\"xFR-rx-kmt\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"430\" height=\"148\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3\">\n                        <rect key=\"frame\" x=\"20\" y=\"65\" width=\"65\" height=\"65\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" secondItem=\"3\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"hwB-dK-k1H\"/>\n                            <constraint firstAttribute=\"width\" constant=\"65\" id=\"jJy-qZ-1jH\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"4\"/>\n                        <accessibility description=\"Textual Logo\"/>\n                    </imageView>\n                    <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5\">\n                        <rect key=\"frame\" x=\"103\" y=\"114\" width=\"309\" height=\"16\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"#infoTitle\" id=\"6\">\n                            <font key=\"font\" metaFont=\"systemBold\"/>\n                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7\">\n                        <rect key=\"frame\" x=\"103\" y=\"90\" width=\"309\" height=\"14\"/>\n                        <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"#InfoMessage\" id=\"8\">\n                            <font key=\"font\" metaFont=\"smallSystem\"/>\n                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        </textFieldCell>\n                    </textField>\n                    <button tag=\"1000\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oPI-db-OzA\">\n                        <rect key=\"frame\" x=\"323\" y=\"11\" width=\"94\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"OK\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ey2-K6-XER\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"80\" id=\"nBf-X1-zW3\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"buttonPressed:\" target=\"-2\" id=\"qhJ-l9-Ttz\"/>\n                        </connections>\n                    </button>\n                    <button hidden=\"YES\" tag=\"1001\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fv3-Bh-Zpr\">\n                        <rect key=\"frame\" x=\"232\" y=\"11\" width=\"94\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ZZc-F9-DOe\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"80\" id=\"Q4V-Jj-RmP\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"buttonPressed:\" target=\"-2\" id=\"x9z-AU-Ov2\"/>\n                        </connections>\n                    </button>\n                    <button hidden=\"YES\" tag=\"1002\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gz4-k0-7mW\">\n                        <rect key=\"frame\" x=\"98\" y=\"11\" width=\"94\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Button\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"7W2-c2-bfN\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"80\" id=\"i0R-bj-b2M\"/>\n                        </constraints>\n                        <connections>\n                            <action selector=\"buttonPressed:\" target=\"-2\" id=\"Wh3-6u-Oim\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ygL-Yb-5Mh\">\n                        <rect key=\"frame\" x=\"103\" y=\"57\" width=\"228\" height=\"18\"/>\n                        <buttonCell key=\"cell\" type=\"check\" title=\"Do not show this messasge again\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"lEw-jf-Cbx\">\n                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                    </button>\n                    <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5kA-MY-GbC\">\n                        <rect key=\"frame\" x=\"55\" y=\"65\" width=\"30\" height=\"30\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"width\" constant=\"30\" id=\"ESw-jX-OqJ\"/>\n                            <constraint firstAttribute=\"width\" secondItem=\"5kA-MY-GbC\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"mzK-py-jwW\"/>\n                        </constraints>\n                        <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"NSCaution\" id=\"oaW-1W-dL0\"/>\n                        <accessibility description=\"Textual Logo\"/>\n                    </imageView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"ygL-Yb-5Mh\" firstAttribute=\"top\" secondItem=\"7\" secondAttribute=\"bottom\" constant=\"16\" id=\"5Tc-UT-3lQ\"/>\n                    <constraint firstItem=\"gz4-k0-7mW\" firstAttribute=\"leading\" secondItem=\"xFR-rx-kmt\" secondAttribute=\"leading\" constant=\"105\" id=\"5eq-97-B9P\"/>\n                    <constraint firstItem=\"7\" firstAttribute=\"top\" secondItem=\"5\" secondAttribute=\"bottom\" constant=\"10\" id=\"8zW-HU-7Yp\"/>\n                    <constraint firstItem=\"7\" firstAttribute=\"leading\" secondItem=\"5\" secondAttribute=\"leading\" id=\"K9a-pN-Nsk\"/>\n                    <constraint firstItem=\"Fv3-Bh-Zpr\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"gz4-k0-7mW\" secondAttribute=\"trailing\" constant=\"50\" id=\"KU6-ql-rdi\"/>\n                    <constraint firstItem=\"Fv3-Bh-Zpr\" firstAttribute=\"firstBaseline\" secondItem=\"oPI-db-OzA\" secondAttribute=\"firstBaseline\" id=\"MKG-sB-q7g\"/>\n                    <constraint firstItem=\"ygL-Yb-5Mh\" firstAttribute=\"leading\" secondItem=\"7\" secondAttribute=\"leading\" id=\"NDe-j0-5og\"/>\n                    <constraint firstItem=\"oPI-db-OzA\" firstAttribute=\"top\" secondItem=\"ygL-Yb-5Mh\" secondAttribute=\"bottom\" constant=\"20\" id=\"YLV-pC-Wgo\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"7\" secondAttribute=\"trailing\" constant=\"20\" id=\"awG-JV-Mam\"/>\n                    <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ygL-Yb-5Mh\" secondAttribute=\"trailing\" constant=\"20\" id=\"axI-xQ-Dfh\"/>\n                    <constraint firstItem=\"oPI-db-OzA\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"gz4-k0-7mW\" secondAttribute=\"trailing\" constant=\"50\" id=\"gTp-bf-IsA\"/>\n                    <constraint firstItem=\"5kA-MY-GbC\" firstAttribute=\"trailing\" secondItem=\"3\" secondAttribute=\"trailing\" id=\"gTw-xr-ny5\"/>\n                    <constraint firstItem=\"5\" firstAttribute=\"leading\" secondItem=\"3\" secondAttribute=\"trailing\" constant=\"20\" id=\"iTR-5Z-72U\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"oPI-db-OzA\" secondAttribute=\"trailing\" constant=\"20\" id=\"jD4-M1-xU7\"/>\n                    <constraint firstItem=\"5\" firstAttribute=\"top\" secondItem=\"xFR-rx-kmt\" secondAttribute=\"top\" constant=\"18\" id=\"k4b-VK-fMd\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"top\" secondItem=\"xFR-rx-kmt\" secondAttribute=\"top\" constant=\"18\" id=\"kTZ-SL-ljH\"/>\n                    <constraint firstItem=\"gz4-k0-7mW\" firstAttribute=\"firstBaseline\" secondItem=\"oPI-db-OzA\" secondAttribute=\"firstBaseline\" id=\"ppq-BW-luc\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"oPI-db-OzA\" secondAttribute=\"bottom\" constant=\"18\" id=\"qc8-iz-wW8\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"5\" secondAttribute=\"trailing\" constant=\"20\" id=\"tAy-L1-8YY\"/>\n                    <constraint firstItem=\"3\" firstAttribute=\"leading\" secondItem=\"xFR-rx-kmt\" secondAttribute=\"leading\" constant=\"20\" id=\"vOf-RU-5xf\"/>\n                    <constraint firstItem=\"5kA-MY-GbC\" firstAttribute=\"bottom\" secondItem=\"3\" secondAttribute=\"bottom\" id=\"vlE-x3-JqZ\"/>\n                    <constraint firstItem=\"oPI-db-OzA\" firstAttribute=\"leading\" secondItem=\"Fv3-Bh-Zpr\" secondAttribute=\"trailing\" constant=\"11\" id=\"x9M-7p-RI5\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"xrA-ik-3E7\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-388\" y=\"416\"/>\n        </window>\n    </objects>\n    <resources>\n        <image name=\"NSCaution\" width=\"32\" height=\"32\"/>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TVCChannelSelectionView.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TVCChannelSelectionViewController\">\n            <connections>\n                <outlet property=\"outlineView\" destination=\"YUW-LN-mDa\" id=\"Y0x-ee-zWR\"/>\n                <outlet property=\"outlineViewScrollView\" destination=\"hay-Cp-vGf\" id=\"C8d-9J-ASg\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"18\" horizontalPageScroll=\"10\" verticalLineScroll=\"18\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hay-Cp-vGf\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"552\" height=\"290\"/>\n            <clipView key=\"contentView\" id=\"IW0-ao-gAh\">\n                <rect key=\"frame\" x=\"1\" y=\"1\" width=\"550\" height=\"288\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" tableStyle=\"fullWidth\" selectionHighlightStyle=\"none\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowHeight=\"18\" rowSizeStyle=\"automatic\" viewBased=\"YES\" floatsGroupRows=\"NO\" indentationMarkerFollowsCell=\"NO\" outlineTableColumn=\"nwZ-Am-U4H\" id=\"YUW-LN-mDa\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"288\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <tableColumns>\n                            <tableColumn width=\"538\" minWidth=\"40\" maxWidth=\"1000\" id=\"nwZ-Am-U4H\">\n                                <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\">\n                                    <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </tableHeaderCell>\n                                <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"q58-de-shn\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                <prototypeCellViews>\n                                    <tableCellView identifier=\"serverEntry\" id=\"tz7-a8-xMR\" userLabel=\"Server Cell\" customClass=\"TVCChannelSelectionOutlineCellView\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"550\" height=\"18\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O7s-3h-Zh7\">\n                                                <rect key=\"frame\" x=\"4\" y=\"0.0\" width=\"18\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" allowsMixedState=\"YES\" inset=\"2\" id=\"Xih-E8-b9W\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <accessibility description=\"Limit filter to item\"/>\n                                                <connections>\n                                                    <action selector=\"selectionCheckboxClicked:\" target=\"tz7-a8-xMR\" id=\"Nrh-FE-32E\"/>\n                                                </connections>\n                                            </button>\n                                            <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"myz-4S-cMH\">\n                                                <rect key=\"frame\" x=\"22\" y=\"2\" width=\"96\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"qI6-v7-m2V\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"myz-4S-cMH\" firstAttribute=\"leading\" secondItem=\"O7s-3h-Zh7\" secondAttribute=\"trailing\" constant=\"4\" id=\"8JQ-fU-Ohn\"/>\n                                            <constraint firstItem=\"myz-4S-cMH\" firstAttribute=\"top\" secondItem=\"tz7-a8-xMR\" secondAttribute=\"top\" id=\"9CN-xI-eNH\"/>\n                                            <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"myz-4S-cMH\" secondAttribute=\"trailing\" constant=\"4\" id=\"CtB-xB-BdD\"/>\n                                            <constraint firstItem=\"O7s-3h-Zh7\" firstAttribute=\"top\" secondItem=\"tz7-a8-xMR\" secondAttribute=\"top\" constant=\"2\" id=\"Nwh-k7-XSd\"/>\n                                            <constraint firstItem=\"O7s-3h-Zh7\" firstAttribute=\"leading\" secondItem=\"tz7-a8-xMR\" secondAttribute=\"leading\" constant=\"6\" id=\"zTh-Lw-loA\"/>\n                                        </constraints>\n                                        <connections>\n                                            <outlet property=\"selectedCheckbox\" destination=\"O7s-3h-Zh7\" id=\"hcW-LK-iIs\"/>\n                                            <outlet property=\"textField\" destination=\"myz-4S-cMH\" id=\"5wJ-Id-v0x\"/>\n                                        </connections>\n                                    </tableCellView>\n                                    <tableCellView identifier=\"channelEntry\" id=\"qui-zI-7Lr\" userLabel=\"Channel Cell\" customClass=\"TVCChannelSelectionOutlineCellView\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"18\" width=\"550\" height=\"18\"/>\n                                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                        <subviews>\n                                            <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KU9-QJ-egQ\">\n                                                <rect key=\"frame\" x=\"22\" y=\"0.0\" width=\"18\" height=\"18\"/>\n                                                <buttonCell key=\"cell\" type=\"check\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" allowsMixedState=\"YES\" inset=\"2\" id=\"i3R-8u-WOc\">\n                                                    <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                </buttonCell>\n                                                <accessibility description=\"Limit filter to item\"/>\n                                                <connections>\n                                                    <action selector=\"selectionCheckboxClicked:\" target=\"qui-zI-7Lr\" id=\"fnq-22-AGL\"/>\n                                                </connections>\n                                            </button>\n                                            <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yCi-cd-PTx\">\n                                                <rect key=\"frame\" x=\"40\" y=\"2\" width=\"96\" height=\"16\"/>\n                                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"hGN-67-Q2Q\">\n                                                    <font key=\"font\" metaFont=\"system\"/>\n                                                    <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                </textFieldCell>\n                                            </textField>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"KU9-QJ-egQ\" firstAttribute=\"leading\" secondItem=\"qui-zI-7Lr\" secondAttribute=\"leading\" constant=\"24\" id=\"9j6-Vk-cEc\"/>\n                                            <constraint firstItem=\"yCi-cd-PTx\" firstAttribute=\"leading\" secondItem=\"KU9-QJ-egQ\" secondAttribute=\"trailing\" constant=\"4\" id=\"IUY-LY-gsT\"/>\n                                            <constraint firstItem=\"yCi-cd-PTx\" firstAttribute=\"top\" secondItem=\"qui-zI-7Lr\" secondAttribute=\"top\" id=\"dKq-MX-kKA\"/>\n                                            <constraint firstItem=\"KU9-QJ-egQ\" firstAttribute=\"top\" secondItem=\"qui-zI-7Lr\" secondAttribute=\"top\" constant=\"2\" id=\"dgw-23-u7j\"/>\n                                            <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"yCi-cd-PTx\" secondAttribute=\"trailing\" constant=\"4\" id=\"qfh-hJ-adK\"/>\n                                        </constraints>\n                                        <connections>\n                                            <outlet property=\"selectedCheckbox\" destination=\"KU9-QJ-egQ\" id=\"sY9-ge-Id9\"/>\n                                            <outlet property=\"textField\" destination=\"yCi-cd-PTx\" id=\"ODN-0m-6vc\"/>\n                                        </connections>\n                                    </tableCellView>\n                                </prototypeCellViews>\n                            </tableColumn>\n                        </tableColumns>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"-2\" id=\"0K9-4z-1Mw\"/>\n                            <outlet property=\"delegate\" destination=\"-2\" id=\"ZnB-Ql-nRs\"/>\n                        </connections>\n                    </outlineView>\n                </subviews>\n            </clipView>\n            <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"Hap-mi-jh1\">\n                <rect key=\"frame\" x=\"1\" y=\"273\" width=\"550\" height=\"16\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </scroller>\n            <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"kmM-BS-bDm\">\n                <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n            </scroller>\n            <point key=\"canvasLocation\" x=\"-232\" y=\"-79\"/>\n        </scrollView>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TVCMainWindow.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23077.2\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23077.2\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TXMasterController\">\n            <connections>\n                <outlet property=\"mainWindow\" destination=\"21\" id=\"TEv-p7-EgJ\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <window title=\"Textual 7\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" tabbingMode=\"disallowed\" id=\"21\" userLabel=\"Window\" customClass=\"TVCMainWindow\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\" miniaturizable=\"YES\" resizable=\"YES\"/>\n            <windowCollectionBehavior key=\"collectionBehavior\" fullScreenPrimary=\"YES\"/>\n            <rect key=\"contentRect\" x=\"515\" y=\"206\" width=\"800\" height=\"477\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1055\"/>\n            <view key=\"contentView\" wantsLayer=\"YES\" id=\"2\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"477\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"phB-0r-qij\" userLabel=\"Text Field\" customClass=\"TVCMainWindowTextViewContentView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"800\" height=\"38\"/>\n                        <subviews>\n                            <segmentedControl verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Q9x-Ny-Yn4\" customClass=\"TVCMainWindowSegmentedController\">\n                                <rect key=\"frame\" x=\"9\" y=\"7\" width=\"154\" height=\"23\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"152\" id=\"1ir-ed-Ia3\"/>\n                                </constraints>\n                                <segmentedCell key=\"cell\" borderStyle=\"border\" alignment=\"left\" segmentDistribution=\"fillEqually\" style=\"texturedSquare\" trackingMode=\"momentary\" id=\"l5w-Kh-b34\" customClass=\"TVCMainWindowSegmentedControllerCell\">\n                                    <font key=\"font\" metaFont=\"system\"/>\n                                    <segments>\n                                        <segment toolTip=\"Add Server or Channel\" image=\"NSAddTemplate\">\n                                            <nil key=\"label\"/>\n                                        </segment>\n                                        <segment toolTip=\"Manage Selection\" image=\"NSActionTemplate\" tag=\"1\">\n                                            <nil key=\"label\"/>\n                                        </segment>\n                                        <segment toolTip=\"Open Address Book\" image=\"MainWindowSegmentedControlUserTemplate\" tag=\"2\">\n                                            <nil key=\"label\"/>\n                                        </segment>\n                                    </segments>\n                                    <connections>\n                                        <action selector=\"segmentedCellClicked:\" target=\"Q9x-Ny-Yn4\" id=\"OoN-TX-Sf0\"/>\n                                    </connections>\n                                </segmentedCell>\n                                <accessibility description=\"Main Window Segmented Controller\"/>\n                                <connections>\n                                    <outlet property=\"segmentedControllerLeadingConstraint\" destination=\"BVS-64-Ck9\" id=\"gEb-sq-vxO\"/>\n                                    <outlet property=\"segmentedControllerWidthConstraint\" destination=\"1ir-ed-Ia3\" id=\"dNR-4h-5xG\"/>\n                                </connections>\n                            </segmentedControl>\n                            <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nbK-l5-9k5\" customClass=\"TVCMainWindowTextViewBackground\">\n                                <rect key=\"frame\" x=\"172\" y=\"6\" width=\"618\" height=\"25\"/>\n                                <subviews>\n                                    <scrollView borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"10\" horizontalPageScroll=\"10\" verticalLineScroll=\"10\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xnK-JZ-PNd\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"3\" width=\"608\" height=\"19\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" copiesOnScroll=\"NO\" id=\"R89-6i-JgM\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"608\" height=\"19\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <textView editable=\"NO\" selectable=\"NO\" drawsBackground=\"NO\" importsGraphics=\"NO\" verticallyResizable=\"YES\" continuousSpellChecking=\"YES\" allowsUndo=\"YES\" allowsNonContiguousLayout=\"YES\" spellingCorrection=\"YES\" grammarChecking=\"YES\" smartInsertDelete=\"YES\" id=\"Ub5-no-pBU\" customClass=\"TVCMainWindowTextView\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"608\" height=\"19\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" flexibleMinY=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <size key=\"minSize\" width=\"608\" height=\"19\"/>\n                                                    <size key=\"maxSize\" width=\"1397\" height=\"10000000\"/>\n                                                    <color key=\"insertionPointColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <accessibility description=\"Main Text Field\"/>\n                                                    <connections>\n                                                        <outlet property=\"backgroundView\" destination=\"nbK-l5-9k5\" id=\"9hb-sC-ujn\"/>\n                                                        <outlet property=\"contentView\" destination=\"phB-0r-qij\" id=\"q5a-XP-rcM\"/>\n                                                        <outlet property=\"segmentedController\" destination=\"Q9x-Ny-Yn4\" id=\"Wfb-bb-UFY\"/>\n                                                        <outlet property=\"segmentedControllerCell\" destination=\"l5w-Kh-b34\" id=\"bCl-8m-PYT\"/>\n                                                        <outlet property=\"textViewHeightConstraint\" destination=\"4wi-57-9OA\" id=\"WKH-Kh-F86\"/>\n                                                        <outlet property=\"windowContentViewMinimumHeight\" destination=\"XJm-Dd-FjI\" id=\"yUG-1i-yuZ\"/>\n                                                    </connections>\n                                                </textView>\n                                            </subviews>\n                                        </clipView>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" doubleValue=\"1\" horizontal=\"YES\" id=\"CHU-gl-rY2\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"87\" height=\"18\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"kWB-tP-6YF\">\n                                            <rect key=\"frame\" x=\"481\" y=\"1\" width=\"16\" height=\"13\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"xnK-JZ-PNd\" secondAttribute=\"bottom\" constant=\"3\" id=\"dVz-Ga-jCK\"/>\n                                    <constraint firstItem=\"xnK-JZ-PNd\" firstAttribute=\"leading\" secondItem=\"nbK-l5-9k5\" secondAttribute=\"leading\" id=\"h2j-vU-jjP\"/>\n                                    <constraint firstItem=\"xnK-JZ-PNd\" firstAttribute=\"top\" secondItem=\"nbK-l5-9k5\" secondAttribute=\"top\" constant=\"3\" id=\"lXH-1e-q4x\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"xnK-JZ-PNd\" secondAttribute=\"trailing\" constant=\"10\" id=\"xYw-C2-alv\"/>\n                                </constraints>\n                                <connections>\n                                    <outlet property=\"textView\" destination=\"Ub5-no-pBU\" id=\"bkZ-AY-i7H\"/>\n                                </connections>\n                            </customView>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"nbK-l5-9k5\" secondAttribute=\"trailing\" constant=\"10\" id=\"4Uj-Jq-fdw\"/>\n                            <constraint firstAttribute=\"height\" constant=\"38\" id=\"4wi-57-9OA\"/>\n                            <constraint firstItem=\"Q9x-Ny-Yn4\" firstAttribute=\"leading\" secondItem=\"phB-0r-qij\" secondAttribute=\"leading\" constant=\"10\" id=\"BVS-64-Ck9\"/>\n                            <constraint firstItem=\"Q9x-Ny-Yn4\" firstAttribute=\"centerY\" secondItem=\"phB-0r-qij\" secondAttribute=\"centerY\" id=\"WNs-kr-fBb\"/>\n                            <constraint firstItem=\"nbK-l5-9k5\" firstAttribute=\"top\" secondItem=\"phB-0r-qij\" secondAttribute=\"top\" constant=\"7\" id=\"awN-Bn-Ddd\"/>\n                            <constraint firstItem=\"nbK-l5-9k5\" firstAttribute=\"leading\" secondItem=\"Q9x-Ny-Yn4\" secondAttribute=\"trailing\" constant=\"10\" id=\"bvY-ST-GSO\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"nbK-l5-9k5\" secondAttribute=\"bottom\" constant=\"6\" id=\"hXg-Rj-6BH\"/>\n                        </constraints>\n                        <connections>\n                            <outlet property=\"segmentedController\" destination=\"Q9x-Ny-Yn4\" id=\"tS5-QF-8za\"/>\n                            <outlet property=\"textView\" destination=\"Ub5-no-pBU\" id=\"tIm-bm-cE5\"/>\n                        </connections>\n                    </customView>\n                    <splitView autosaveName=\"\" dividerStyle=\"thin\" vertical=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dVR-2U-X51\" userLabel=\"Thin Split View\" customClass=\"TVCMainWindowSplitView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"38\" width=\"800\" height=\"439\"/>\n                        <subviews>\n                            <visualEffectView blendingMode=\"behindWindow\" material=\"underWindowBackground\" state=\"followsWindowActiveState\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KgM-JY-9PC\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                <subviews>\n                                    <scrollView borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"23\" horizontalPageScroll=\"10\" verticalLineScroll=\"23\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KbE-36-qMw\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"pGy-N5-8Z2\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <outlineView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"firstColumnOnly\" tableStyle=\"fullWidth\" columnReordering=\"NO\" columnResizing=\"NO\" emptySelection=\"NO\" autosaveColumns=\"NO\" rowHeight=\"23\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" viewBased=\"YES\" indentationPerLevel=\"6\" outlineTableColumn=\"4h6-Uy-Vo9\" id=\"MLD-Aa-PLM\" customClass=\"TVCServerList\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"backgroundColor\" white=\"1\" alpha=\"0.0\" colorSpace=\"deviceWhite\"/>\n                                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <tableColumns>\n                                                        <tableColumn width=\"138\" minWidth=\"40\" maxWidth=\"1000\" id=\"4h6-Uy-Vo9\">\n                                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </tableHeaderCell>\n                                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"qcu-ms-jpx\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                            <prototypeCellViews>\n                                                                <tableCellView identifier=\"GroupView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LOI-ud-jS4\" customClass=\"TVCServerListCellGroupItem\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"23\"/>\n                                                                    <subviews>\n                                                                        <textField focusRingType=\"none\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wBU-6B-7f4\">\n                                                                            <rect key=\"frame\" x=\"3\" y=\"3\" width=\"147\" height=\"17\"/>\n                                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"fBN-3b-ksS\">\n                                                                                <font key=\"font\" metaFont=\"systemBold\" size=\"14\"/>\n                                                                                <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                        </textField>\n                                                                    </subviews>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"wBU-6B-7f4\" firstAttribute=\"top\" relation=\"greaterThanOrEqual\" secondItem=\"LOI-ud-jS4\" secondAttribute=\"top\" constant=\"3\" id=\"B9Y-uv-4AN\"/>\n                                                                        <constraint firstAttribute=\"trailing\" secondItem=\"wBU-6B-7f4\" secondAttribute=\"trailing\" constant=\"2\" id=\"T0c-Wm-Ntv\"/>\n                                                                        <constraint firstItem=\"wBU-6B-7f4\" firstAttribute=\"leading\" secondItem=\"LOI-ud-jS4\" secondAttribute=\"leading\" constant=\"5\" id=\"b3P-cC-qaP\"/>\n                                                                        <constraint firstItem=\"wBU-6B-7f4\" firstAttribute=\"centerY\" secondItem=\"LOI-ud-jS4\" secondAttribute=\"centerY\" id=\"qGr-Yw-sdX\"/>\n                                                                    </constraints>\n                                                                    <connections>\n                                                                        <outlet property=\"cellTextField\" destination=\"wBU-6B-7f4\" id=\"jkE-JW-N5b\"/>\n                                                                        <outlet property=\"cellTextFieldLeftMarginConstraint\" destination=\"b3P-cC-qaP\" id=\"Dar-F2-ajG\"/>\n                                                                    </connections>\n                                                                </tableCellView>\n                                                                <tableCellView identifier=\"ChildView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AKs-o3-7CO\" customClass=\"TVCServerListCellChildItem\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"23\" width=\"150\" height=\"19\"/>\n                                                                    <subviews>\n                                                                        <imageView wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"1000\" verticalCompressionResistancePriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"68i-pd-Me5\">\n                                                                            <rect key=\"frame\" x=\"2\" y=\"2\" width=\"0.0\" height=\"15\"/>\n                                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" imageScaling=\"proportionallyUpOrDown\" id=\"L7W-3b-gZZ\"/>\n                                                                        </imageView>\n                                                                        <textField focusRingType=\"none\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YvY-15-HQ3\">\n                                                                            <rect key=\"frame\" x=\"6\" y=\"2\" width=\"90\" height=\"15\"/>\n                                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"aWH-di-A9U\">\n                                                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                                                <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                        </textField>\n                                                                        <imageView wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"1000\" verticalCompressionResistancePriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ybi-Bk-q6V\">\n                                                                            <rect key=\"frame\" x=\"148\" y=\"1\" width=\"0.0\" height=\"17\"/>\n                                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" id=\"AgO-Mi-Fwf\"/>\n                                                                        </imageView>\n                                                                    </subviews>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"68i-pd-Me5\" firstAttribute=\"leading\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"leading\" constant=\"2\" id=\"30q-JO-bxw\"/>\n                                                                        <constraint firstItem=\"Ybi-Bk-q6V\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"YvY-15-HQ3\" secondAttribute=\"trailing\" constant=\"8\" id=\"4RY-SZ-rtF\"/>\n                                                                        <constraint firstItem=\"68i-pd-Me5\" firstAttribute=\"top\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"top\" constant=\"2\" id=\"4bj-uN-9BF\"/>\n                                                                        <constraint firstAttribute=\"bottom\" secondItem=\"68i-pd-Me5\" secondAttribute=\"bottom\" constant=\"2\" id=\"5La-r3-bcy\"/>\n                                                                        <constraint firstItem=\"68i-pd-Me5\" firstAttribute=\"centerY\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"centerY\" id=\"CqV-vG-O0t\"/>\n                                                                        <constraint firstAttribute=\"trailing\" secondItem=\"Ybi-Bk-q6V\" secondAttribute=\"trailing\" constant=\"2\" id=\"F6K-Cf-KhL\"/>\n                                                                        <constraint firstItem=\"YvY-15-HQ3\" firstAttribute=\"centerY\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"centerY\" id=\"FCv-Qe-6RD\"/>\n                                                                        <constraint firstItem=\"Ybi-Bk-q6V\" firstAttribute=\"centerY\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"centerY\" id=\"Ld9-82-1jh\"/>\n                                                                        <constraint firstItem=\"YvY-15-HQ3\" firstAttribute=\"top\" relation=\"greaterThanOrEqual\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"top\" constant=\"2\" id=\"hR7-ul-DBq\"/>\n                                                                        <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"YvY-15-HQ3\" secondAttribute=\"trailing\" constant=\"2\" id=\"jg3-oa-ktd\"/>\n                                                                        <constraint firstItem=\"YvY-15-HQ3\" firstAttribute=\"leading\" secondItem=\"68i-pd-Me5\" secondAttribute=\"trailing\" constant=\"6\" id=\"tLx-Q1-geB\"/>\n                                                                        <constraint firstItem=\"Ybi-Bk-q6V\" firstAttribute=\"top\" secondItem=\"AKs-o3-7CO\" secondAttribute=\"top\" constant=\"1\" id=\"zDv-Ef-pSt\"/>\n                                                                    </constraints>\n                                                                    <connections>\n                                                                        <outlet property=\"cellTextField\" destination=\"YvY-15-HQ3\" id=\"9HX-hd-ONy\"/>\n                                                                        <outlet property=\"imageView\" destination=\"68i-pd-Me5\" id=\"cX3-Mq-zsK\"/>\n                                                                        <outlet property=\"messageCountBadgeImageView\" destination=\"Ybi-Bk-q6V\" id=\"4Ke-5o-esE\"/>\n                                                                        <outlet property=\"messageCountBadgeLeadingConstraint\" destination=\"4RY-SZ-rtF\" id=\"Khe-Sw-zGT\"/>\n                                                                        <outlet property=\"messageCountBadgeTrailingConstraint\" destination=\"F6K-Cf-KhL\" id=\"xwX-22-z2h\"/>\n                                                                    </connections>\n                                                                </tableCellView>\n                                                            </prototypeCellViews>\n                                                        </tableColumn>\n                                                    </tableColumns>\n                                                    <accessibility description=\"Server List\"/>\n                                                    <connections>\n                                                        <outlet property=\"dataSource\" destination=\"21\" id=\"doc-Ux-ZeS\"/>\n                                                        <outlet property=\"delegate\" destination=\"21\" id=\"3S0-9E-ZM8\"/>\n                                                        <outlet property=\"visualEffectView\" destination=\"KgM-JY-9PC\" id=\"qaq-vu-mgs\"/>\n                                                    </connections>\n                                                </outlineView>\n                                            </subviews>\n                                        </clipView>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"e4Y-GC-Kwt\">\n                                            <rect key=\"frame\" x=\"1\" y=\"119\" width=\"223\" height=\"15\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"Dao-ye-Bbf\">\n                                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"120\" id=\"5hi-RS-NLb\"/>\n                                    <constraint firstItem=\"KbE-36-qMw\" firstAttribute=\"leading\" secondItem=\"KgM-JY-9PC\" secondAttribute=\"leading\" id=\"HLq-Mw-ou6\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"KbE-36-qMw\" secondAttribute=\"trailing\" id=\"VJb-Js-hLp\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"KbE-36-qMw\" secondAttribute=\"bottom\" id=\"gyb-Dl-0Zg\"/>\n                                    <constraint firstItem=\"KbE-36-qMw\" firstAttribute=\"top\" secondItem=\"KgM-JY-9PC\" secondAttribute=\"top\" id=\"hKK-kV-GA5\"/>\n                                    <constraint firstAttribute=\"width\" relation=\"lessThanOrEqual\" constant=\"300\" id=\"uvA-9N-e8z\"/>\n                                </constraints>\n                            </visualEffectView>\n                            <splitView dividerStyle=\"thin\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dCp-Wp-aIX\" customClass=\"TVCMainWindowChannelView\">\n                                <rect key=\"frame\" x=\"151\" y=\"0.0\" width=\"498\" height=\"439\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"100\" id=\"mtt-4n-lrH\"/>\n                                </constraints>\n                            </splitView>\n                            <visualEffectView blendingMode=\"behindWindow\" material=\"underWindowBackground\" state=\"followsWindowActiveState\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2k7-ax-6YE\">\n                                <rect key=\"frame\" x=\"650\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                <subviews>\n                                    <scrollView borderType=\"none\" autohidesScrollers=\"YES\" horizontalLineScroll=\"20\" horizontalPageScroll=\"10\" verticalLineScroll=\"20\" verticalPageScroll=\"10\" hasHorizontalScroller=\"NO\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KMX-Oo-KOu\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                        <clipView key=\"contentView\" drawsBackground=\"NO\" id=\"dMW-Pm-dRv\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                            <subviews>\n                                                <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" tableStyle=\"fullWidth\" columnReordering=\"NO\" columnResizing=\"NO\" autosaveColumns=\"NO\" rowHeight=\"20\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" viewBased=\"YES\" floatsGroupRows=\"NO\" id=\"bgh-q2-4XX\" customClass=\"TVCMemberList\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"439\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                    <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    <tableColumns>\n                                                        <tableColumn width=\"138\" minWidth=\"40\" maxWidth=\"1000\" id=\"eAc-xK-Bvw\">\n                                                            <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\">\n                                                                <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </tableHeaderCell>\n                                                            <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"VBc-Qe-fZN\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                                            <prototypeCellViews>\n                                                                <tableCellView identifier=\"GroupView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nyR-GE-ZXL\" customClass=\"TVCMemberListCell\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"150\" height=\"20\"/>\n                                                                    <subviews>\n                                                                        <imageView wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"1000\" verticalCompressionResistancePriority=\"1000\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Lq2-t9-aDp\">\n                                                                            <rect key=\"frame\" x=\"0.0\" y=\"2\" width=\"16\" height=\"16\"/>\n                                                                            <constraints>\n                                                                                <constraint firstAttribute=\"width\" secondItem=\"Lq2-t9-aDp\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"zNU-oK-R37\"/>\n                                                                            </constraints>\n                                                                            <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" image=\"FormattingColor_2\" id=\"G8T-wi-HCu\"/>\n                                                                        </imageView>\n                                                                        <textField focusRingType=\"none\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jld-0X-vn0\">\n                                                                            <rect key=\"frame\" x=\"20\" y=\"2\" width=\"132\" height=\"16\"/>\n                                                                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Label\" id=\"Mby-SL-PEz\">\n                                                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                                                <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                                                <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                            </textFieldCell>\n                                                                        </textField>\n                                                                    </subviews>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"jld-0X-vn0\" firstAttribute=\"top\" secondItem=\"nyR-GE-ZXL\" secondAttribute=\"top\" constant=\"2\" id=\"P2i-Rd-QtT\"/>\n                                                                        <constraint firstItem=\"jld-0X-vn0\" firstAttribute=\"leading\" secondItem=\"Lq2-t9-aDp\" secondAttribute=\"trailing\" constant=\"6\" id=\"cd6-99-HOk\"/>\n                                                                        <constraint firstItem=\"Lq2-t9-aDp\" firstAttribute=\"top\" secondItem=\"nyR-GE-ZXL\" secondAttribute=\"top\" constant=\"2\" id=\"fAn-nx-R4H\"/>\n                                                                        <constraint firstItem=\"Lq2-t9-aDp\" firstAttribute=\"leading\" secondItem=\"nyR-GE-ZXL\" secondAttribute=\"leading\" id=\"fBT-mI-gYa\"/>\n                                                                        <constraint firstItem=\"jld-0X-vn0\" firstAttribute=\"centerY\" secondItem=\"nyR-GE-ZXL\" secondAttribute=\"centerY\" id=\"pEP-xB-8EX\"/>\n                                                                        <constraint firstItem=\"Lq2-t9-aDp\" firstAttribute=\"centerY\" secondItem=\"nyR-GE-ZXL\" secondAttribute=\"centerY\" id=\"qS9-DP-CLq\"/>\n                                                                        <constraint firstAttribute=\"trailing\" secondItem=\"jld-0X-vn0\" secondAttribute=\"trailing\" id=\"xer-US-fgj\"/>\n                                                                    </constraints>\n                                                                    <connections>\n                                                                        <outlet property=\"cellTextField\" destination=\"jld-0X-vn0\" id=\"L5s-IO-xaA\"/>\n                                                                        <outlet property=\"imageView\" destination=\"Lq2-t9-aDp\" id=\"3RI-Vl-ylD\"/>\n                                                                        <outlet property=\"markBadgeLeftMarginConstraint\" destination=\"fBT-mI-gYa\" id=\"h1u-iC-3ui\"/>\n                                                                    </connections>\n                                                                </tableCellView>\n                                                            </prototypeCellViews>\n                                                        </tableColumn>\n                                                    </tableColumns>\n                                                    <connections>\n                                                        <binding destination=\"hdH-wA-Q1P\" name=\"content\" keyPath=\"arrangedObjects\" id=\"kGZ-Mq-rJ7\"/>\n                                                        <outlet property=\"contentController\" destination=\"hdH-wA-Q1P\" id=\"ADE-cR-3al\"/>\n                                                        <outlet property=\"memberListUserInfoPopover\" destination=\"iYh-l7-KsB\" id=\"vr3-QJ-1MS\"/>\n                                                        <outlet property=\"visualEffectView\" destination=\"2k7-ax-6YE\" id=\"IbW-dz-7Os\"/>\n                                                    </connections>\n                                                </tableView>\n                                            </subviews>\n                                        </clipView>\n                                        <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"e5K-h3-ecX\">\n                                            <rect key=\"frame\" x=\"-100\" y=\"-100\" width=\"293\" height=\"16\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                        <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"uDI-i2-xc0\">\n                                            <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                        </scroller>\n                                    </scrollView>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" relation=\"lessThanOrEqual\" constant=\"300\" id=\"1fo-ar-fxS\"/>\n                                    <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"120\" id=\"FXS-Qi-nKW\"/>\n                                    <constraint firstItem=\"KMX-Oo-KOu\" firstAttribute=\"leading\" secondItem=\"2k7-ax-6YE\" secondAttribute=\"leading\" id=\"Mkw-jR-Ly1\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"KMX-Oo-KOu\" secondAttribute=\"trailing\" id=\"MmJ-z4-jtY\"/>\n                                    <constraint firstItem=\"KMX-Oo-KOu\" firstAttribute=\"top\" secondItem=\"2k7-ax-6YE\" secondAttribute=\"top\" id=\"e3L-2B-wg6\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"KMX-Oo-KOu\" secondAttribute=\"bottom\" id=\"jjE-gq-Ni4\"/>\n                                </constraints>\n                            </visualEffectView>\n                        </subviews>\n                        <constraints>\n                            <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"35\" id=\"XJm-Dd-FjI\"/>\n                            <constraint firstItem=\"2k7-ax-6YE\" firstAttribute=\"top\" secondItem=\"dVR-2U-X51\" secondAttribute=\"top\" id=\"XRJ-Ei-CKy\"/>\n                            <constraint firstItem=\"KgM-JY-9PC\" firstAttribute=\"top\" secondItem=\"dVR-2U-X51\" secondAttribute=\"top\" id=\"qdp-pc-Cjr\"/>\n                        </constraints>\n                        <holdingPriorities>\n                            <real value=\"355\"/>\n                            <real value=\"350\"/>\n                            <real value=\"355\"/>\n                        </holdingPriorities>\n                        <connections>\n                            <outlet property=\"memberListWidthMaxConstraint\" destination=\"1fo-ar-fxS\" id=\"fY7-yG-bAU\"/>\n                            <outlet property=\"memberListWidthMinConstraint\" destination=\"FXS-Qi-nKW\" id=\"xIo-k6-eNI\"/>\n                            <outlet property=\"serverListWidthMaxConstraint\" destination=\"uvA-9N-e8z\" id=\"Laj-nP-kTh\"/>\n                            <outlet property=\"serverListWidthMinConstraint\" destination=\"5hi-RS-NLb\" id=\"hAB-Sl-TOZ\"/>\n                        </connections>\n                    </splitView>\n                    <visualEffectView blendingMode=\"withinWindow\" material=\"underWindowBackground\" state=\"followsWindowActiveState\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Se1-ja-hFN\" customClass=\"TVCMainWindowLoadingScreenView\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"38\" width=\"800\" height=\"439\"/>\n                        <connections>\n                            <outlet property=\"progressView\" destination=\"9NQ-ho-u6f\" id=\"KI1-yZ-V2x\"/>\n                            <outlet property=\"progressViewDescriptionTextField\" destination=\"krn-AQ-P4T\" id=\"EH8-wP-FzB\"/>\n                            <outlet property=\"progressViewIndicator\" destination=\"WS7-Zg-h6u\" id=\"XYt-hu-zhy\"/>\n                            <outlet property=\"trialExpiredView\" destination=\"dlj-jp-O6P\" id=\"hIg-fZ-s9L\"/>\n                            <outlet property=\"welcomeAddServerView\" destination=\"c10-eB-wRJ\" id=\"YGC-SF-VWn\"/>\n                            <outlet property=\"welcomeAddServerViewContinueButton\" destination=\"ba0-0Q-9bh\" id=\"t0n-Ip-wMq\"/>\n                        </connections>\n                    </visualEffectView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"dVR-2U-X51\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" id=\"2ro-j0-acT\"/>\n                    <constraint firstItem=\"phB-0r-qij\" firstAttribute=\"top\" secondItem=\"Se1-ja-hFN\" secondAttribute=\"bottom\" id=\"54i-0J-hb3\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"phB-0r-qij\" secondAttribute=\"trailing\" id=\"6oD-Jp-7wd\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"phB-0r-qij\" secondAttribute=\"bottom\" id=\"KD5-T4-WZX\"/>\n                    <constraint firstItem=\"Se1-ja-hFN\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" id=\"NUA-6d-cnz\"/>\n                    <constraint firstItem=\"dVR-2U-X51\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" id=\"P6K-zr-yLh\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"Se1-ja-hFN\" secondAttribute=\"trailing\" id=\"jua-U4-RDu\"/>\n                    <constraint firstItem=\"Se1-ja-hFN\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"top\" id=\"k1T-uE-HVD\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"dVR-2U-X51\" secondAttribute=\"trailing\" id=\"lT7-88-ztW\"/>\n                    <constraint firstItem=\"phB-0r-qij\" firstAttribute=\"leading\" secondItem=\"2\" secondAttribute=\"leading\" id=\"qin-63-ACL\"/>\n                    <constraint firstItem=\"phB-0r-qij\" firstAttribute=\"top\" secondItem=\"dVR-2U-X51\" secondAttribute=\"bottom\" id=\"sZP-Ep-9Fh\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"channelView\" destination=\"dCp-Wp-aIX\" id=\"SRq-MD-Vzk\"/>\n                <outlet property=\"contentSplitView\" destination=\"dVR-2U-X51\" id=\"UTS-m3-2nd\"/>\n                <outlet property=\"formattingMenu\" destination=\"j7v-mc-UwU\" id=\"4X3-MP-pDp\"/>\n                <outlet property=\"inputTextField\" destination=\"Ub5-no-pBU\" id=\"mCF-mM-bHc\"/>\n                <outlet property=\"loadingScreen\" destination=\"Se1-ja-hFN\" id=\"niK-Fq-MHr\"/>\n                <outlet property=\"mainMenuProxy\" destination=\"U6M-jc-NbT\" id=\"QeA-Xy-1ah\"/>\n                <outlet property=\"memberList\" destination=\"bgh-q2-4XX\" id=\"j80-GF-rXN\"/>\n                <outlet property=\"serverList\" destination=\"MLD-Aa-PLM\" id=\"SZb-p4-bEc\"/>\n                <outlet property=\"titlebarAccessoryView\" destination=\"asp-kn-ubA\" id=\"M0x-e3-Mna\"/>\n                <outlet property=\"titlebarAccessoryViewController\" destination=\"Yr8-XA-FFO\" id=\"3cU-yb-0Yx\"/>\n                <outlet property=\"titlebarAccessoryViewLockButton\" destination=\"eFh-15-nxS\" id=\"izN-Fu-EpE\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"1461\" y=\"752.5\"/>\n        </window>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oh2-zJ-yiT\" userLabel=\"User Info Popover View\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"358\" height=\"125\"/>\n            <subviews>\n                <gridView xPlacement=\"fill\" yPlacement=\"fill\" rowAlignment=\"firstBaseline\" rowSpacing=\"3\" columnSpacing=\"4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ICd-wA-BP1\">\n                    <rect key=\"frame\" x=\"15\" y=\"10\" width=\"328\" height=\"105\"/>\n                    <rows>\n                        <gridRow id=\"krD-PF-8kY\"/>\n                        <gridRow id=\"WIU-yG-MVI\"/>\n                        <gridRow id=\"Q7S-fA-zK4\"/>\n                        <gridRow id=\"yEF-a5-wiQ\"/>\n                        <gridRow id=\"EmQ-MG-Vbq\"/>\n                        <gridRow id=\"V1J-y2-JcM\"/>\n                    </rows>\n                    <columns>\n                        <gridColumn id=\"2YH-Ed-b3H\"/>\n                        <gridColumn xPlacement=\"leading\" id=\"rpa-b6-KdN\"/>\n                    </columns>\n                    <gridCells>\n                        <gridCell row=\"krD-PF-8kY\" column=\"2YH-Ed-b3H\" id=\"9Ll-ZC-QwD\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ThT-Me-8qg\">\n                                <rect key=\"frame\" x=\"-2\" y=\"90\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Nickname:\" id=\"z6F-bu-Ztu\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"krD-PF-8kY\" column=\"rpa-b6-KdN\" id=\"C0y-uu-gDv\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Blz-Bt-ZsS\">\n                                <rect key=\"frame\" x=\"80\" y=\"90\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"av8-83-Zed\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"ThT-Me-8qg\" id=\"FzV-YU-7FB\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"WIU-yG-MVI\" column=\"2YH-Ed-b3H\" id=\"ju8-1C-a1S\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HzN-f2-swN\">\n                                <rect key=\"frame\" x=\"-2\" y=\"72\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Username:\" id=\"CNy-6F-gGj\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"WIU-yG-MVI\" column=\"rpa-b6-KdN\" id=\"UdS-eP-dZs\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jP1-tt-X27\">\n                                <rect key=\"frame\" x=\"80\" y=\"72\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"fBu-jr-cGU\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"HzN-f2-swN\" id=\"L3r-tK-b1i\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"Q7S-fA-zK4\" column=\"2YH-Ed-b3H\" id=\"q3T-g7-6Kk\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g0C-E0-viB\">\n                                <rect key=\"frame\" x=\"-2\" y=\"54\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Address:\" id=\"Qak-zW-pkC\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"Q7S-fA-zK4\" column=\"rpa-b6-KdN\" id=\"kDg-yc-qTQ\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gx5-KC-Pkt\">\n                                <rect key=\"frame\" x=\"80\" y=\"54\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"fuW-Vk-8im\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"g0C-E0-viB\" id=\"g0e-Wi-gfX\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"yEF-a5-wiQ\" column=\"2YH-Ed-b3H\" id=\"FUg-Ql-Zi9\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gYJ-PO-Xi9\">\n                                <rect key=\"frame\" x=\"-2\" y=\"36\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Real name:\" id=\"Rtg-7l-7PS\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"yEF-a5-wiQ\" column=\"rpa-b6-KdN\" id=\"ZZB-wc-cOt\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EcV-hb-9F1\">\n                                <rect key=\"frame\" x=\"80\" y=\"36\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"ohH-Rl-ixA\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"gYJ-PO-Xi9\" id=\"Dzt-Rf-7iD\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"EmQ-MG-Vbq\" column=\"2YH-Ed-b3H\" id=\"3hx-wt-dlx\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gg2-7k-P4H\">\n                                <rect key=\"frame\" x=\"-2\" y=\"18\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Privileges:\" id=\"Jh3-ii-xIy\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"EmQ-MG-Vbq\" column=\"rpa-b6-KdN\" id=\"Ff7-oK-cSk\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WEa-1V-bIW\">\n                                <rect key=\"frame\" x=\"80\" y=\"18\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"XTw-zV-D90\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"Gg2-7k-P4H\" id=\"Zxe-H6-QXX\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"V1J-y2-JcM\" column=\"2YH-Ed-b3H\" id=\"PsM-cf-J1s\">\n                            <textField key=\"contentView\" focusRingType=\"none\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0k8-Dm-XbJ\">\n                                <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"82\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Away status:\" id=\"8hg-20-pcc\">\n                                    <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                                    <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                            </textField>\n                        </gridCell>\n                        <gridCell row=\"V1J-y2-JcM\" column=\"rpa-b6-KdN\" id=\"kFq-rD-b5f\">\n                            <textField key=\"contentView\" focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6vR-3K-Yh7\">\n                                <rect key=\"frame\" x=\"80\" y=\"0.0\" width=\"246\" height=\"15\"/>\n                                <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"################################\" id=\"UPo-wk-s6E\">\n                                    <font key=\"font\" metaFont=\"cellTitle\"/>\n                                    <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                    <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                </textFieldCell>\n                                <connections>\n                                    <accessibilityConnection property=\"title\" destination=\"0k8-Dm-XbJ\" id=\"Giu-kD-4a2\"/>\n                                </connections>\n                            </textField>\n                        </gridCell>\n                    </gridCells>\n                </gridView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"trailing\" secondItem=\"ICd-wA-BP1\" secondAttribute=\"trailing\" constant=\"15\" id=\"9Av-pM-CUr\"/>\n                <constraint firstItem=\"ICd-wA-BP1\" firstAttribute=\"leading\" secondItem=\"Oh2-zJ-yiT\" secondAttribute=\"leading\" constant=\"15\" id=\"ZEs-b0-afv\"/>\n                <constraint firstItem=\"ICd-wA-BP1\" firstAttribute=\"top\" secondItem=\"Oh2-zJ-yiT\" secondAttribute=\"top\" constant=\"10\" id=\"ptT-xX-rbc\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ICd-wA-BP1\" secondAttribute=\"bottom\" constant=\"10\" id=\"yMQ-OZ-wLN\"/>\n            </constraints>\n            <accessibility description=\"User Information Popover\"/>\n            <point key=\"canvasLocation\" x=\"32\" y=\"261\"/>\n        </customView>\n        <popover id=\"iYh-l7-KsB\" userLabel=\"User Info Popover\" customClass=\"TVCMemberListUserInfoPopover\">\n            <connections>\n                <outlet property=\"addressField\" destination=\"gx5-KC-Pkt\" id=\"sjn-pL-XM1\"/>\n                <outlet property=\"awayStatusField\" destination=\"6vR-3K-Yh7\" id=\"1j1-Im-HsZ\"/>\n                <outlet property=\"contentViewController\" destination=\"hJd-My-gQw\" id=\"6X4-yG-whE\"/>\n                <outlet property=\"nicknameField\" destination=\"Blz-Bt-ZsS\" id=\"GjS-bq-zuA\"/>\n                <outlet property=\"privilegesField\" destination=\"WEa-1V-bIW\" id=\"lld-ea-hD7\"/>\n                <outlet property=\"realNameField\" destination=\"EcV-hb-9F1\" id=\"Yrr-h9-X8A\"/>\n                <outlet property=\"usernameField\" destination=\"jP1-tt-X27\" id=\"jVx-NK-OZI\"/>\n            </connections>\n        </popover>\n        <viewController id=\"hJd-My-gQw\" userLabel=\"User Info Popover Controller\">\n            <connections>\n                <outlet property=\"view\" destination=\"Oh2-zJ-yiT\" id=\"8aI-0t-3P3\"/>\n            </connections>\n        </viewController>\n        <menuItem title=\"IRC Formatting\" tag=\"53037\" id=\"yuS-Ad-J8i\">\n            <modifierMask key=\"keyEquivalentModifierMask\"/>\n            <menu key=\"submenu\" title=\"IRC Formatting\" id=\"tby-cl-t36\">\n                <items>\n                    <menuItem title=\"Bold\" tag=\"100\" id=\"ajV-SV-z21\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Bold\">\n                                <attributes>\n                                    <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertBoldCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"FL2-d6-WTy\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Italics\" tag=\"101\" id=\"MQM-6c-LVF\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Italics\">\n                                <attributes>\n                                    <font key=\"NSFont\" metaFont=\"system\"/>\n                                    <font key=\"NSOriginalFont\" metaFont=\"system\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertItalicCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"ywY-c0-vnI\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Monospace\" tag=\"102\" id=\"IRX-kV-qMN\" userLabel=\"Monospace\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Monospace\">\n                                <attributes>\n                                    <font key=\"NSFont\" size=\"13\" name=\"Menlo-Regular\"/>\n                                    <font key=\"NSOriginalFont\" size=\"13\" name=\"Menlo-Regular\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertMonospaceCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"MlM-MK-kaM\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Spoiler\" tag=\"103\" id=\"TKk-OM-x7h\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Spoiler\">\n                                <attributes>\n                                    <color key=\"NSBackgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    <color key=\"NSColor\" white=\"0.8407\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    <font key=\"NSFont\" metaFont=\"system\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertSpoilerCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"uf7-BY-Dc6\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Strikethrough\" tag=\"104\" id=\"eHi-3i-hdN\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Strikethrough\">\n                                <attributes>\n                                    <font key=\"NSFont\" metaFont=\"system\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                    <integer key=\"NSStrikethrough\" value=\"1\"/>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertStrikethroughCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"PnJ-g6-Soe\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Underline\" tag=\"105\" id=\"WEO-6i-cGf\">\n                        <attributedString key=\"attributedTitle\">\n                            <fragment content=\"Underline\">\n                                <attributes>\n                                    <font key=\"NSFont\" metaFont=\"system\"/>\n                                    <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                        <tabStops>\n                                            <textTab alignment=\"left\" location=\"36\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"72\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"108\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"144\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"180\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"216\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"252\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"288\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"324\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"360\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"396\">\n                                                <options/>\n                                            </textTab>\n                                            <textTab alignment=\"left\" location=\"432\">\n                                                <options/>\n                                            </textTab>\n                                        </tabStops>\n                                    </paragraphStyle>\n                                    <integer key=\"NSUnderline\" value=\"1\"/>\n                                    <color key=\"NSUnderlineColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                </attributes>\n                            </fragment>\n                        </attributedString>\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <connections>\n                            <action selector=\"insertUnderlineCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"F1P-4u-Qi6\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem isSeparatorItem=\"YES\" tag=\"106\" id=\"2wB-PE-DHZ\"/>\n                    <menuItem title=\"Text Color\" state=\"on\" tag=\"107\" hidden=\"YES\" keyEquivalent=\"C\" id=\"Ebt-RF-aBw\">\n                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                        <connections>\n                            <action selector=\"removeForegroundColorCharFromTextBox:\" target=\"j7v-mc-UwU\" id=\"MfG-sK-ba9\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Text Color\" tag=\"108\" id=\"zcK-F5-D5E\">\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <menu key=\"submenu\" title=\"Text Color\" id=\"nLk-Fl-2lR\">\n                            <items>\n                                <menuItem title=\"Text Foreground Color\" id=\"lOb-fX-IG0\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"bg0-Ng-Tzn\"/>\n                                <menuItem title=\" White\" offStateImage=\"FormattingColor_0\" id=\"ARN-Ri-nbk\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"FNB-p8-dkn\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Black\" offStateImage=\"FormattingColor_1\" tag=\"1\" id=\"0Ss-XT-b86\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"L3V-HU-moa\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Blue (Navy)\" offStateImage=\"FormattingColor_3\" tag=\"2\" id=\"czd-tP-iaS\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"fqd-Jj-JWw\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Green\" offStateImage=\"FormattingColor_2\" tag=\"3\" id=\"kS9-2O-sqS\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"ifM-ve-mmE\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Red\" offStateImage=\"FormattingColor_4\" tag=\"4\" id=\"IWI-GH-Ora\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"4kp-Lr-M6n\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Brown (Maroon)\" offStateImage=\"FormattingColor_5\" tag=\"5\" id=\"Who-wC-fSt\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"83e-yc-YNI\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Purple\" offStateImage=\"FormattingColor_7\" tag=\"6\" id=\"EIN-fm-82Q\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"Wmx-gZ-kNd\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Orange\" offStateImage=\"FormattingColor_6\" tag=\"7\" id=\"8vZ-G8-jv5\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"Ckj-0h-aMs\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Yellow\" offStateImage=\"FormattingColor_13\" tag=\"8\" id=\"Gh5-I1-yLt\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"nhL-U2-ZsB\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Green (Lime)\" offStateImage=\"FormattingColor_12\" tag=\"9\" id=\"N9c-LY-gcF\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"Ejt-mI-FcA\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Teal (Green/Blue Cyan)\" offStateImage=\"FormattingColor_10\" tag=\"10\" id=\"Bje-lA-3rz\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"UdV-8W-mbW\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Cyan (Cyan) (Aqua)\" offStateImage=\"FormattingColor_11\" tag=\"11\" id=\"P7u-ao-KWb\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"4eW-CR-GtF\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Blue (Royal)\" offStateImage=\"FormattingColor_9\" tag=\"12\" id=\"fi2-Ew-trd\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"uk3-zq-TUW\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Pink (Light Purple) (Fuchsia)\" offStateImage=\"FormattingColor_8\" tag=\"13\" id=\"CrD-bC-Yfu\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"RB4-Kq-ziy\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Grey\" offStateImage=\"FormattingColor_14\" tag=\"14\" id=\"r0U-BE-Nuu\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"mKr-yg-A0i\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Grey (Silver)\" offStateImage=\"FormattingColor_15\" tag=\"15\" id=\"uI2-y4-Mub\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"WrN-Zd-u4L\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"592-9O-NaR\"/>\n                                <menuItem title=\" Rainbow\" offStateImage=\"FormattingColor_Rainbow\" tag=\"299\" id=\"yvr-bb-p4H\">\n                                    <attributedString key=\"attributedTitle\">\n                                        <fragment content=\" R\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"a\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"0.50196078430000002\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"i\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"1\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"n\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.67843137249999996\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"b\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.0\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"o\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.0\" blue=\"0.36078431370000003\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"w\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.50196078430000002\" green=\"0.0\" blue=\"0.50196078430000002\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <font key=\"NSOriginalFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"natural\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                    </attributedString>\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"y6a-Uv-z5F\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"hGo-0i-jYX\"/>\n                                <menuItem title=\"Other…\" tag=\"300\" id=\"uyY-8y-tGv\" userLabel=\"Other…\">\n                                    <attributedString key=\"attributedTitle\"/>\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertForegroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"bSk-e0-k4B\"/>\n                                    </connections>\n                                </menuItem>\n                            </items>\n                            <connections>\n                                <outlet property=\"delegate\" destination=\"j7v-mc-UwU\" id=\"Mdn-nS-EPn\"/>\n                            </connections>\n                        </menu>\n                        <connections>\n                            <action selector=\"emptyAction:\" target=\"j7v-mc-UwU\" id=\"DhV-1G-B5s\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Background Color\" state=\"on\" tag=\"109\" hidden=\"YES\" keyEquivalent=\"H\" id=\"ePW-6F-Q1S\">\n                        <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                        <connections>\n                            <action selector=\"removeBackgroundColorCharFromTextBox:\" target=\"j7v-mc-UwU\" id=\"vyg-et-Ooe\"/>\n                        </connections>\n                    </menuItem>\n                    <menuItem title=\"Background Color\" tag=\"110\" id=\"yrv-9t-LSZ\">\n                        <modifierMask key=\"keyEquivalentModifierMask\"/>\n                        <menu key=\"submenu\" title=\"Background Color\" id=\"dMA-xy-EJU\">\n                            <items>\n                                <menuItem title=\"Text Background Color\" id=\"4xF-Sg-oGj\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"JG7-7S-yEI\"/>\n                                <menuItem title=\" White\" offStateImage=\"FormattingColor_0\" id=\"TDN-yE-ZR8\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"MFE-ww-sKV\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Black\" offStateImage=\"FormattingColor_1\" tag=\"1\" id=\"Aw4-EX-d4G\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"qva-b0-fWk\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Blue (Navy)\" offStateImage=\"FormattingColor_3\" tag=\"2\" id=\"l7k-2J-Xf5\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"bGp-6k-NTc\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Green\" offStateImage=\"FormattingColor_2\" tag=\"3\" id=\"SGm-V5-eSq\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"bsh-dX-pGw\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Red\" offStateImage=\"FormattingColor_4\" tag=\"4\" id=\"YP3-Vn-UX9\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"mpn-SZ-odr\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Brown (Maroon)\" offStateImage=\"FormattingColor_5\" tag=\"5\" id=\"x1s-UD-e6l\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"07a-6f-29A\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Purple\" offStateImage=\"FormattingColor_7\" tag=\"6\" id=\"b3W-X6-t1o\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"6jR-Zv-pSv\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Orange\" offStateImage=\"FormattingColor_6\" tag=\"7\" id=\"OIM-ms-A0J\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"niw-i1-Na7\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Yellow\" offStateImage=\"FormattingColor_13\" tag=\"8\" id=\"ABW-nJ-yww\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"tnn-tV-dN3\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Green (Lime)\" offStateImage=\"FormattingColor_12\" tag=\"9\" id=\"PoI-vF-KTc\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"gXc-M5-S85\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Teal (Green/Blue Cyan)\" offStateImage=\"FormattingColor_10\" tag=\"10\" id=\"dlX-Ta-yRu\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"HiV-pG-1Em\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Cyan (Cyan) (Aqua)\" offStateImage=\"FormattingColor_11\" tag=\"11\" id=\"LwL-4r-OcQ\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"43d-0V-u0d\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Blue (Royal)\" offStateImage=\"FormattingColor_9\" tag=\"12\" id=\"qRD-RR-Ksa\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"cnh-7i-KYu\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Pink (Light Purple) (Fuchsia)\" offStateImage=\"FormattingColor_8\" tag=\"13\" id=\"QK2-3t-Rgp\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"v77-3W-2X3\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Grey\" offStateImage=\"FormattingColor_14\" tag=\"14\" id=\"Qjv-cy-whN\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"yEd-hH-HRp\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem title=\" Light Grey (Silver)\" offStateImage=\"FormattingColor_15\" tag=\"15\" id=\"glT-A8-2O4\">\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"9Ot-er-ugQ\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"Lkd-mt-5g7\"/>\n                                <menuItem title=\" Rainbow\" offStateImage=\"FormattingColor_Rainbow\" tag=\"299\" id=\"YPx-ab-Cac\">\n                                    <attributedString key=\"attributedTitle\">\n                                        <fragment content=\" R\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"a\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"0.50196078431372548\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"i\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"1\" green=\"1\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"n\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.67843137254901964\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"b\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.0\" blue=\"1\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"o\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.0\" green=\"0.0\" blue=\"0.36078431372549019\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                        <fragment content=\"w\">\n                                            <attributes>\n                                                <color key=\"NSColor\" red=\"0.50196078431372548\" green=\"0.0\" blue=\"0.50196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                                <font key=\"NSFont\" metaFont=\"systemBold\"/>\n                                                <paragraphStyle key=\"NSParagraphStyle\" alignment=\"left\" lineBreakMode=\"wordWrapping\" baseWritingDirection=\"natural\" tighteningFactorForTruncation=\"0.0\" allowsDefaultTighteningForTruncation=\"NO\">\n                                                    <tabStops>\n                                                        <textTab alignment=\"left\" location=\"36\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"72\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"108\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"144\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"180\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"216\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"252\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"288\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"324\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"360\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"396\">\n                                                            <options/>\n                                                        </textTab>\n                                                        <textTab alignment=\"left\" location=\"432\">\n                                                            <options/>\n                                                        </textTab>\n                                                    </tabStops>\n                                                </paragraphStyle>\n                                            </attributes>\n                                        </fragment>\n                                    </attributedString>\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"iBo-Ja-C2N\"/>\n                                    </connections>\n                                </menuItem>\n                                <menuItem isSeparatorItem=\"YES\" id=\"P6H-kS-fFY\"/>\n                                <menuItem title=\"Other…\" tag=\"300\" id=\"dKB-ut-N9M\" userLabel=\"Other…\">\n                                    <attributedString key=\"attributedTitle\"/>\n                                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                    <connections>\n                                        <action selector=\"insertBackgroundColorCharIntoTextBox:\" target=\"j7v-mc-UwU\" id=\"ciE-yc-Hpb\"/>\n                                    </connections>\n                                </menuItem>\n                            </items>\n                            <connections>\n                                <outlet property=\"delegate\" destination=\"j7v-mc-UwU\" id=\"FhI-EN-VNu\"/>\n                            </connections>\n                        </menu>\n                        <connections>\n                            <action selector=\"emptyAction:\" target=\"j7v-mc-UwU\" id=\"oba-5b-r2j\"/>\n                        </connections>\n                    </menuItem>\n                </items>\n                <connections>\n                    <outlet property=\"delegate\" destination=\"j7v-mc-UwU\" id=\"cZL-rX-76X\"/>\n                </connections>\n            </menu>\n        </menuItem>\n        <customObject id=\"j7v-mc-UwU\" userLabel=\"FormatTextController\" customClass=\"TVCTextViewIRCFormattingMenu\">\n            <connections>\n                <outlet property=\"backgroundColorMenu\" destination=\"dMA-xy-EJU\" id=\"eRX-Kd-c1X\"/>\n                <outlet property=\"foregroundColorMenu\" destination=\"nLk-Fl-2lR\" id=\"s19-Dx-CSF\"/>\n                <outlet property=\"formatterMenu\" destination=\"yuS-Ad-J8i\" id=\"dg9-ul-9u2\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"U6M-jc-NbT\" customClass=\"TXMenuControllerMainWindowProxy\"/>\n        <customView hidden=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"asp-kn-ubA\" customClass=\"TVCMainWindowTitlebarAccessoryView\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"110\" height=\"22\"/>\n            <subviews>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eFh-15-nxS\" customClass=\"TVCMainWindowTitlebarAccessoryViewLockButton\">\n                    <rect key=\"frame\" x=\"3\" y=\"1\" width=\"104\" height=\"19\"/>\n                    <buttonCell key=\"cell\" type=\"recessed\" title=\"Not Private\" bezelStyle=\"recessed\" image=\"NSLockUnlockedTemplate\" imagePosition=\"left\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"HaN-Sj-wDl\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"systemBold\" size=\"12\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"titlebarAccessoryViewLockButtonClicked:\" target=\"21\" id=\"a6q-QT-SVd\"/>\n                        <outlet property=\"lockButtonLeftMarginConstraint\" destination=\"qts-vn-Wxx\" id=\"cye-ff-geo\"/>\n                        <outlet property=\"lockButtonRightMarginConstraint\" destination=\"Ref-Vz-BjG\" id=\"wYT-1a-NLy\"/>\n                        <outlet property=\"mainWindowRef\" destination=\"21\" id=\"IBC-I6-WlA\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"eFh-15-nxS\" firstAttribute=\"centerY\" secondItem=\"asp-kn-ubA\" secondAttribute=\"centerY\" id=\"C2d-bm-bgM\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"eFh-15-nxS\" secondAttribute=\"trailing\" constant=\"3\" id=\"Ref-Vz-BjG\"/>\n                <constraint firstItem=\"eFh-15-nxS\" firstAttribute=\"leading\" secondItem=\"asp-kn-ubA\" secondAttribute=\"leading\" constant=\"3\" id=\"qts-vn-Wxx\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"51\" y=\"117\"/>\n        </customView>\n        <viewController id=\"Yr8-XA-FFO\" customClass=\"TVCMainWindowTitlebarAccessoryViewController\">\n            <connections>\n                <outlet property=\"view\" destination=\"asp-kn-ubA\" id=\"6kH-ZT-LxG\"/>\n            </connections>\n        </viewController>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9NQ-ho-u6f\" userLabel=\"Loading Screen: Progress Message\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"404\" height=\"257\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fXR-tC-HNL\">\n                    <rect key=\"frame\" x=\"75\" y=\"44\" width=\"255\" height=\"35\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" title=\"Welcome to Textual\" id=\"0jK-Hy-GsU\">\n                        <font key=\"font\" metaFont=\"system\" size=\"30\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vs9-Im-qLZ\">\n                    <rect key=\"frame\" x=\"127\" y=\"87\" width=\"150\" height=\"150\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"150\" id=\"1I7-iu-5fe\"/>\n                        <constraint firstAttribute=\"width\" secondItem=\"Vs9-Im-qLZ\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"a2k-5E-fdr\"/>\n                    </constraints>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"wpM-pw-UdB\"/>\n                </imageView>\n                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7NU-Ke-m1W\">\n                    <rect key=\"frame\" x=\"116\" y=\"20\" width=\"172\" height=\"16\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"krn-AQ-P4T\">\n                            <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"152\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" allowsUndo=\"NO\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Loading Configuration …\" id=\"T82-TC-gp8\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <progressIndicator wantsLayer=\"YES\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" maxValue=\"100\" bezeled=\"NO\" indeterminate=\"YES\" controlSize=\"small\" style=\"spinning\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WS7-Zg-h6u\">\n                            <rect key=\"frame\" x=\"156\" y=\"0.0\" width=\"16\" height=\"16\"/>\n                        </progressIndicator>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"fXR-tC-HNL\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"leading\" constant=\"65\" id=\"0gX-FY-Nus\"/>\n                <constraint firstItem=\"7NU-Ke-m1W\" firstAttribute=\"centerX\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"centerX\" id=\"4Ls-4H-PgG\"/>\n                <constraint firstItem=\"7NU-Ke-m1W\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"leading\" constant=\"20\" id=\"BMc-9U-GCP\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"7NU-Ke-m1W\" secondAttribute=\"bottom\" constant=\"20\" id=\"Fpf-oR-yef\"/>\n                <constraint firstItem=\"Vs9-Im-qLZ\" firstAttribute=\"centerX\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"centerX\" id=\"G5e-xy-XRU\"/>\n                <constraint firstItem=\"Vs9-Im-qLZ\" firstAttribute=\"top\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"top\" constant=\"20\" id=\"Lvi-f0-SgL\"/>\n                <constraint firstItem=\"fXR-tC-HNL\" firstAttribute=\"top\" secondItem=\"Vs9-Im-qLZ\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"ekJ-fl-yWG\"/>\n                <constraint firstItem=\"fXR-tC-HNL\" firstAttribute=\"centerX\" secondItem=\"9NQ-ho-u6f\" secondAttribute=\"centerX\" id=\"jBB-9Q-wck\"/>\n                <constraint firstItem=\"7NU-Ke-m1W\" firstAttribute=\"top\" secondItem=\"fXR-tC-HNL\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"sHo-4A-nC8\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"510\" y=\"492\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"c10-eB-wRJ\" userLabel=\"Loading Screen: Welcome, Add Server\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"482\" height=\"327\"/>\n            <subviews>\n                <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GY8-jo-A4y\">\n                    <rect key=\"frame\" x=\"165\" y=\"155\" width=\"152\" height=\"152\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"152\" id=\"7Gk-Ye-EeM\"/>\n                        <constraint firstAttribute=\"width\" secondItem=\"GY8-jo-A4y\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"eUr-Eu-mwp\"/>\n                    </constraints>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"hLG-Ns-gsB\"/>\n                </imageView>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hcL-fW-9VX\">\n                    <rect key=\"frame\" x=\"114\" y=\"112\" width=\"255\" height=\"35\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Welcome to Textual\" id=\"uL2-Aa-1FS\">\n                        <font key=\"font\" metaFont=\"system\" size=\"30\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iAb-RH-KAw\">\n                    <rect key=\"frame\" x=\"33\" y=\"56\" width=\"416\" height=\"48\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" id=\"bTX-Jn-rpL\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">Textual is a powerful, yet lightweight, IRC client built exclusively for the Mac. To get started, Textual will walk you through adding your first server. Click the button below to get started.</string>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ba0-0Q-9bh\">\n                    <rect key=\"frame\" x=\"197\" y=\"13\" width=\"89\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Continue\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"Ml7-3B-qhV\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Begin Setup\"/>\n                    <connections>\n                        <action selector=\"showWelcomeSheet:\" target=\"U6M-jc-NbT\" id=\"t5s-aH-Fdt\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"hcL-fW-9VX\" firstAttribute=\"top\" secondItem=\"GY8-jo-A4y\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"64k-Y9-bif\"/>\n                <constraint firstItem=\"GY8-jo-A4y\" firstAttribute=\"top\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"top\" constant=\"20\" id=\"6fl-pv-bBy\"/>\n                <constraint firstItem=\"iAb-RH-KAw\" firstAttribute=\"top\" secondItem=\"hcL-fW-9VX\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"AJr-Ek-GdE\"/>\n                <constraint firstItem=\"GY8-jo-A4y\" firstAttribute=\"centerX\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"centerX\" id=\"Fgy-8g-C4a\"/>\n                <constraint firstItem=\"ba0-0Q-9bh\" firstAttribute=\"top\" secondItem=\"iAb-RH-KAw\" secondAttribute=\"bottom\" constant=\"16\" id=\"RNm-hl-gkV\"/>\n                <constraint firstItem=\"iAb-RH-KAw\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"leading\" constant=\"35\" id=\"UKY-gA-XdM\"/>\n                <constraint firstItem=\"ba0-0Q-9bh\" firstAttribute=\"centerX\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"centerX\" id=\"cWz-cO-vpm\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ba0-0Q-9bh\" secondAttribute=\"bottom\" constant=\"20\" id=\"ctQ-SD-hkp\"/>\n                <constraint firstItem=\"iAb-RH-KAw\" firstAttribute=\"centerX\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"centerX\" id=\"nRB-PS-ezH\"/>\n                <constraint firstItem=\"hcL-fW-9VX\" firstAttribute=\"centerX\" secondItem=\"c10-eB-wRJ\" secondAttribute=\"centerX\" id=\"qnR-nb-G6A\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"32\" y=\"581\"/>\n        </customView>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dlj-jp-O6P\" userLabel=\"Loading Screen: Trial Expired\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"520\" height=\"415\"/>\n            <subviews>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Sxb-jV-wmm\">\n                    <rect key=\"frame\" x=\"55\" y=\"200\" width=\"410\" height=\"35\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Your trial of Textual has expired!\" id=\"LNi-eT-r8e\">\n                        <font key=\"font\" metaFont=\"system\" size=\"30\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6kZ-YA-3P0\">\n                    <rect key=\"frame\" x=\"18\" y=\"144\" width=\"484\" height=\"48\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" alignment=\"center\" id=\"J9b-GU-Ie0\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">Thank you for trying Textual for the past 30 days. \n\nTo continue using Textual, you will need to purchase it.</string>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u65-PZ-rca\">\n                    <rect key=\"frame\" x=\"200\" y=\"101\" width=\"121\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Purchase Now\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"Oyn-9I-e5e\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Purchase Textual\"/>\n                    <connections>\n                        <action selector=\"openStandaloneStoreWebpage:\" target=\"U6M-jc-NbT\" id=\"KTW-vE-uqm\"/>\n                    </connections>\n                </button>\n                <imageView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"y8X-eU-D17\">\n                    <rect key=\"frame\" x=\"184\" y=\"243\" width=\"152\" height=\"152\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"152\" id=\"JuG-GC-0q4\"/>\n                        <constraint firstAttribute=\"width\" secondItem=\"y8X-eU-D17\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"miR-e6-Ves\"/>\n                    </constraints>\n                    <imageCell key=\"cell\" refusesFirstResponder=\"YES\" alignment=\"left\" animates=\"YES\" imageScaling=\"proportionallyDown\" image=\"applicationIcon\" id=\"dnb-Ek-TpJ\"/>\n                </imageView>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rfe-Am-khK\">\n                    <rect key=\"frame\" x=\"50\" y=\"87\" width=\"420\" height=\"5\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"420\" id=\"dfS-de-acv\"/>\n                    </constraints>\n                </box>\n                <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LK8-9t-3xT\">\n                    <rect key=\"frame\" x=\"164\" y=\"55\" width=\"192\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Already own a copy of Textual?\" id=\"MJr-dN-Icn\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XHv-hd-4V2\">\n                    <rect key=\"frame\" x=\"195\" y=\"13\" width=\"130\" height=\"32\"/>\n                    <buttonCell key=\"cell\" type=\"push\" title=\"Activate Textual\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" inset=\"2\" id=\"zy8-ma-OJS\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"manageLicense:\" target=\"U6M-jc-NbT\" id=\"7y5-0V-dcv\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"6kZ-YA-3P0\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"leading\" constant=\"20\" id=\"01t-8p-oqN\"/>\n                <constraint firstItem=\"u65-PZ-rca\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"5kQ-QL-tso\"/>\n                <constraint firstItem=\"XHv-hd-4V2\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"5rv-6N-3cb\"/>\n                <constraint firstItem=\"y8X-eU-D17\" firstAttribute=\"top\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"top\" constant=\"20\" id=\"7ki-0j-b16\"/>\n                <constraint firstItem=\"Sxb-jV-wmm\" firstAttribute=\"top\" secondItem=\"y8X-eU-D17\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"Am6-q9-qnX\"/>\n                <constraint firstItem=\"6kZ-YA-3P0\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"DeM-5Z-7ND\"/>\n                <constraint firstItem=\"LK8-9t-3xT\" firstAttribute=\"top\" secondItem=\"Rfe-Am-khK\" secondAttribute=\"bottom\" constant=\"18\" id=\"GaF-8W-2pm\"/>\n                <constraint firstItem=\"Rfe-Am-khK\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"QDc-jC-TGW\"/>\n                <constraint firstItem=\"u65-PZ-rca\" firstAttribute=\"top\" secondItem=\"6kZ-YA-3P0\" secondAttribute=\"bottom\" constant=\"16\" id=\"SZR-Ek-kFA\"/>\n                <constraint firstItem=\"XHv-hd-4V2\" firstAttribute=\"top\" secondItem=\"LK8-9t-3xT\" secondAttribute=\"bottom\" constant=\"15\" id=\"UCA-Bx-6zU\"/>\n                <constraint firstItem=\"LK8-9t-3xT\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"apH-AL-6KX\"/>\n                <constraint firstItem=\"Rfe-Am-khK\" firstAttribute=\"top\" secondItem=\"u65-PZ-rca\" secondAttribute=\"bottom\" constant=\"18\" id=\"dRu-2D-kuI\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"XHv-hd-4V2\" secondAttribute=\"bottom\" constant=\"20\" id=\"i5w-hF-QvZ\"/>\n                <constraint firstItem=\"Sxb-jV-wmm\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"m8N-CP-UOl\"/>\n                <constraint firstItem=\"6kZ-YA-3P0\" firstAttribute=\"top\" secondItem=\"Sxb-jV-wmm\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"maP-LW-L2Z\"/>\n                <constraint firstItem=\"y8X-eU-D17\" firstAttribute=\"centerX\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"centerX\" id=\"nDV-id-QUN\"/>\n                <constraint firstItem=\"Sxb-jV-wmm\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"dlj-jp-O6P\" secondAttribute=\"leading\" constant=\"45\" id=\"yNX-EA-MDr\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"52\" y=\"1002\"/>\n        </customView>\n        <arrayController objectClassName=\"IRCChannelMember\" preservesSelection=\"NO\" selectsInsertedObjects=\"NO\" avoidsEmptySelection=\"NO\" id=\"hdH-wA-Q1P\" customClass=\"IRCChannelMemberListController\">\n            <classReference key=\"objectClass\" className=\"IRCChannelMember\"/>\n            <connections>\n                <outlet property=\"tableView\" destination=\"bgh-q2-4XX\" id=\"hkO-aM-hXC\"/>\n            </connections>\n        </arrayController>\n    </objects>\n    <resources>\n        <image name=\"FormattingColor_0\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_1\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_10\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_11\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_12\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_13\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_14\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_15\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_2\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_3\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_4\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_5\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_6\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_7\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_8\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_9\" width=\"16\" height=\"16\"/>\n        <image name=\"FormattingColor_Rainbow\" width=\"16\" height=\"16\"/>\n        <image name=\"MainWindowSegmentedControlUserTemplate\" width=\"20\" height=\"18\"/>\n        <image name=\"NSActionTemplate\" width=\"20\" height=\"20\"/>\n        <image name=\"NSAddTemplate\" width=\"18\" height=\"17\"/>\n        <image name=\"NSLockUnlockedTemplate\" width=\"21\" height=\"19\"/>\n        <image name=\"applicationIcon\" width=\"512\" height=\"512\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TVCNotificationConfigurationView.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23077.2\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23077.2\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TVCNotificationConfigurationViewController\">\n            <connections>\n                <outlet property=\"alertBounceDockIconButton\" destination=\"Hkh-C6-mUr\" id=\"dU3-lg-xtZ\"/>\n                <outlet property=\"alertBounceDockIconRepeatedlyButton\" destination=\"bgs-Yr-nUE\" id=\"g7a-zo-qvL\"/>\n                <outlet property=\"alertDisableWhileAwayButton\" destination=\"ghI-8s-WwC\" id=\"ZFi-49-gWK\"/>\n                <outlet property=\"alertPushNotificationButton\" destination=\"357-Bn-nqF\" id=\"zUn-IN-pT6\"/>\n                <outlet property=\"alertSoundChoiceButton\" destination=\"SF6-68-nMU\" id=\"RwI-sk-i6E\"/>\n                <outlet property=\"alertSpeakEventButton\" destination=\"eNG-wb-6fd\" id=\"gVp-7U-UDw\"/>\n                <outlet property=\"alertTypeChoiceButton\" destination=\"VdN-8Y-A2M\" id=\"ZdN-Ha-V2v\"/>\n                <outlet property=\"contentView\" destination=\"r8A-Ud-C6d\" id=\"pqH-XA-5eh\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <view translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"r8A-Ud-C6d\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"545\" height=\"220\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ghI-8s-WwC\">\n                    <rect key=\"frame\" x=\"98\" y=\"83\" width=\"171\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Disable alert while away\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"8aV-e8-f40\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onChangedAlertDisableWhileAway:\" target=\"-2\" id=\"7Dj-r0-X56\"/>\n                    </connections>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eNG-wb-6fd\">\n                    <rect key=\"frame\" x=\"98\" y=\"113\" width=\"183\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Speak using system voice\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"QDo-qm-GYL\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onChangedAlertSpoken:\" target=\"-2\" id=\"ZOs-jC-zxl\"/>\n                    </connections>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"357-Bn-nqF\">\n                    <rect key=\"frame\" x=\"98\" y=\"143\" width=\"182\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Show notification for alert\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" state=\"on\" inset=\"2\" id=\"Wh7-Vc-DoE\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onChangedAlertPushNotification:\" target=\"-2\" id=\"LWj-TM-FmS\"/>\n                    </connections>\n                </button>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hkh-C6-mUr\">\n                    <rect key=\"frame\" x=\"98\" y=\"53\" width=\"134\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Bounce dock icon\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"a61-jS-ybM\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onChangedAlertBounceDockIcon:\" target=\"-2\" id=\"Yu3-rK-Z0M\"/>\n                    </connections>\n                </button>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9Ke-Id-MhS\">\n                    <rect key=\"frame\" x=\"423\" y=\"188\" width=\"102\" height=\"5\"/>\n                </box>\n                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gKB-p5-E8Q\">\n                    <rect key=\"frame\" x=\"20\" y=\"188\" width=\"102\" height=\"5\"/>\n                </box>\n                <stackView distribution=\"equalSpacing\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YND-yP-DZn\">\n                    <rect key=\"frame\" x=\"130\" y=\"180\" width=\"285\" height=\"20\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6Vh-Zp-QDA\">\n                            <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"101\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" controlSize=\"mini\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Selected Alert:\" id=\"Pw9-kC-IY0\">\n                                <font key=\"font\" metaFont=\"systemBold\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VdN-8Y-A2M\">\n                            <rect key=\"frame\" x=\"102\" y=\"-4\" width=\"187\" height=\"25\"/>\n                            <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" inset=\"2\" id=\"hzb-aS-M6b\">\n                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" title=\"OtherViews\" id=\"a2c-uV-s9f\">\n                                    <items>\n                                        <menuItem id=\"VhG-mG-ZCI\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"180\" id=\"LjY-vl-EaF\"/>\n                            </constraints>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"6Vh-Zp-QDA\" id=\"vcD-K3-cb7\"/>\n                                <action selector=\"onChangedAlertType:\" target=\"-2\" id=\"eNq-mi-YwV\"/>\n                            </connections>\n                        </popUpButton>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bgs-Yr-nUE\">\n                    <rect key=\"frame\" x=\"238\" y=\"53\" width=\"94\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Repeatedly\" bezelStyle=\"regularSquare\" imagePosition=\"left\" inset=\"2\" id=\"mwa-QT-nmq\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"onChangedAlertBounceDockIconRepeatedly:\" target=\"-2\" id=\"wr6-qS-s84\"/>\n                    </connections>\n                </button>\n                <stackView distribution=\"equalSpacing\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zfb-Sh-LAJ\">\n                    <rect key=\"frame\" x=\"118\" y=\"20\" width=\"192\" height=\"20\"/>\n                    <subviews>\n                        <textField focusRingType=\"none\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3x1-zP-s54\">\n                            <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"124\" height=\"16\"/>\n                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Play sound on alert:\" id=\"EOI-iY-erP\">\n                                <font key=\"font\" metaFont=\"system\"/>\n                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                            </textFieldCell>\n                        </textField>\n                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SF6-68-nMU\">\n                            <rect key=\"frame\" x=\"125\" y=\"-4\" width=\"71\" height=\"25\"/>\n                            <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" inset=\"2\" id=\"BZG-sJ-2Ja\">\n                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                                <menu key=\"menu\" title=\"OtherViews\" id=\"eGD-V0-BYc\">\n                                    <items>\n                                        <menuItem title=\"Beep\" id=\"m4s-0z-vew\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                </menu>\n                            </popUpButtonCell>\n                            <connections>\n                                <accessibilityConnection property=\"title\" destination=\"3x1-zP-s54\" id=\"gY5-Dc-coV\"/>\n                                <action selector=\"onChangedAlertSound:\" target=\"-2\" id=\"ly7-zq-XQ4\"/>\n                            </connections>\n                        </popUpButton>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"eNG-wb-6fd\" firstAttribute=\"leading\" secondItem=\"357-Bn-nqF\" secondAttribute=\"leading\" id=\"7UC-Ja-trG\"/>\n                <constraint firstItem=\"ghI-8s-WwC\" firstAttribute=\"top\" secondItem=\"eNG-wb-6fd\" secondAttribute=\"bottom\" constant=\"14\" id=\"9BT-vS-qcZ\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"ghI-8s-WwC\" secondAttribute=\"trailing\" constant=\"20\" id=\"Acs-Eh-bm8\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"bgs-Yr-nUE\" secondAttribute=\"trailing\" constant=\"20\" id=\"BLN-FV-MAO\"/>\n                <constraint firstItem=\"Hkh-C6-mUr\" firstAttribute=\"leading\" secondItem=\"ghI-8s-WwC\" secondAttribute=\"leading\" id=\"CJK-hl-HQW\"/>\n                <constraint firstItem=\"9Ke-Id-MhS\" firstAttribute=\"leading\" secondItem=\"YND-yP-DZn\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"CZ8-1Q-TU8\"/>\n                <constraint firstItem=\"357-Bn-nqF\" firstAttribute=\"leading\" secondItem=\"r8A-Ud-C6d\" secondAttribute=\"leading\" constant=\"100\" id=\"CnP-Yx-wLk\"/>\n                <constraint firstItem=\"9Ke-Id-MhS\" firstAttribute=\"centerY\" secondItem=\"YND-yP-DZn\" secondAttribute=\"centerY\" id=\"D5w-PO-gr9\"/>\n                <constraint firstItem=\"gKB-p5-E8Q\" firstAttribute=\"leading\" secondItem=\"r8A-Ud-C6d\" secondAttribute=\"leading\" constant=\"20\" id=\"E3E-JG-0kW\"/>\n                <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"545\" id=\"MxZ-d9-Mq7\"/>\n                <constraint firstItem=\"357-Bn-nqF\" firstAttribute=\"top\" secondItem=\"YND-yP-DZn\" secondAttribute=\"bottom\" constant=\"20\" id=\"QNs-rf-c6A\"/>\n                <constraint firstAttribute=\"bottom\" relation=\"greaterThanOrEqual\" secondItem=\"Zfb-Sh-LAJ\" secondAttribute=\"bottom\" constant=\"20\" id=\"RCw-M0-3rP\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"9Ke-Id-MhS\" secondAttribute=\"trailing\" constant=\"20\" id=\"RRl-94-mVE\"/>\n                <constraint firstItem=\"YND-yP-DZn\" firstAttribute=\"centerX\" secondItem=\"r8A-Ud-C6d\" secondAttribute=\"centerX\" id=\"UOc-rg-KeS\"/>\n                <constraint firstItem=\"YND-yP-DZn\" firstAttribute=\"leading\" secondItem=\"gKB-p5-E8Q\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"V04-x8-rR1\"/>\n                <constraint firstItem=\"ghI-8s-WwC\" firstAttribute=\"leading\" secondItem=\"eNG-wb-6fd\" secondAttribute=\"leading\" id=\"ZbK-Gq-AiR\"/>\n                <constraint firstItem=\"Zfb-Sh-LAJ\" firstAttribute=\"top\" secondItem=\"Hkh-C6-mUr\" secondAttribute=\"bottom\" constant=\"14\" id=\"Znk-CY-qbX\"/>\n                <constraint firstItem=\"gKB-p5-E8Q\" firstAttribute=\"centerY\" secondItem=\"YND-yP-DZn\" secondAttribute=\"centerY\" id=\"f7B-v7-fgg\"/>\n                <constraint firstItem=\"bgs-Yr-nUE\" firstAttribute=\"firstBaseline\" secondItem=\"Hkh-C6-mUr\" secondAttribute=\"firstBaseline\" id=\"fr2-R9-Ogo\"/>\n                <constraint firstItem=\"bgs-Yr-nUE\" firstAttribute=\"leading\" secondItem=\"Hkh-C6-mUr\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"hn6-v5-2Cc\"/>\n                <constraint firstItem=\"eNG-wb-6fd\" firstAttribute=\"top\" secondItem=\"357-Bn-nqF\" secondAttribute=\"bottom\" constant=\"14\" id=\"iD0-vP-4j6\"/>\n                <constraint firstItem=\"Zfb-Sh-LAJ\" firstAttribute=\"leading\" secondItem=\"Hkh-C6-mUr\" secondAttribute=\"leading\" constant=\"18\" id=\"ign-7W-tkT\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"eNG-wb-6fd\" secondAttribute=\"trailing\" constant=\"20\" id=\"kR6-WN-tKf\"/>\n                <constraint firstItem=\"YND-yP-DZn\" firstAttribute=\"top\" secondItem=\"r8A-Ud-C6d\" secondAttribute=\"top\" constant=\"20\" id=\"oY9-mL-iW9\"/>\n                <constraint firstItem=\"Hkh-C6-mUr\" firstAttribute=\"top\" secondItem=\"ghI-8s-WwC\" secondAttribute=\"bottom\" constant=\"14\" id=\"uG1-aD-r2T\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"357-Bn-nqF\" secondAttribute=\"trailing\" constant=\"20\" id=\"uHL-4r-key\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Zfb-Sh-LAJ\" secondAttribute=\"trailing\" constant=\"20\" id=\"zQY-Hs-OIN\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"204\" y=\"82\"/>\n        </view>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Resources/User Interface/en.lproj/TXCMainMenu.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"23727\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"23727\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TXApplication\">\n            <connections>\n                <outlet property=\"delegate\" destination=\"196\" id=\"197\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <userDefaultsController id=\"TlT-Ik-3QP\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n        <customObject id=\"196\" userLabel=\"AppController\" customClass=\"TXMasterController\">\n            <connections>\n                <outlet property=\"menuController\" destination=\"267\" id=\"ubg-bs-tE3\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"267\" userLabel=\"MenuController\" customClass=\"TXMenuController\">\n            <connections>\n                <outlet property=\"channelViewChannelNameMenu\" destination=\"963\" id=\"Apn-Xd-gl8\"/>\n                <outlet property=\"channelViewGeneralMenu\" destination=\"374\" id=\"jud-oP-p2n\"/>\n                <outlet property=\"channelViewURLMenu\" destination=\"426\" id=\"abE-mI-Ckx\"/>\n                <outlet property=\"dockMenu\" destination=\"Q9Y-E0-gAT\" id=\"930-9r-xqt\"/>\n                <outlet property=\"encryptionManagerStatusMenu\" destination=\"edI-1l-81o\" id=\"fSt-o4-bUU\"/>\n                <outlet property=\"mainMenuChannelMenu\" destination=\"1s1-yL-ZHT\" id=\"yR9-do-srs\"/>\n                <outlet property=\"mainMenuChannelMenuItem\" destination=\"276\" id=\"ZFA-Nr-7nd\"/>\n                <outlet property=\"mainMenuNavigationChannelListMenu\" destination=\"89a-J1-2zg\" id=\"8Ju-VI-XQI\"/>\n                <outlet property=\"mainMenuQueryMenu\" destination=\"6uP-Kf-gUN\" id=\"QXL-LN-bey\"/>\n                <outlet property=\"mainMenuQueryMenuItem\" destination=\"d6g-it-Teq\" id=\"BCp-Fd-2hl\"/>\n                <outlet property=\"mainMenuServerMenuItem\" destination=\"286\" id=\"OSj-f8-vqi\"/>\n                <outlet property=\"mainMenuWindowMenuItem\" destination=\"19\" id=\"w4D-Ns-fa4\"/>\n                <outlet property=\"mainWindowSegmentedControllerCellMenu\" destination=\"2953\" id=\"oCb-R7-qbx\"/>\n                <outlet property=\"muteNotificationsDockMenuItem\" destination=\"dnc-ku-aQ3\" id=\"Af9-tD-wlC\"/>\n                <outlet property=\"muteNotificationsFileMenuItem\" destination=\"QNy-Fk-SRO\" id=\"nHn-Ki-RJX\"/>\n                <outlet property=\"muteNotificationsSoundsDockMenuItem\" destination=\"5jG-1t-WG4\" id=\"bTl-Aa-XkS\"/>\n                <outlet property=\"muteNotificationsSoundsFileMenuItem\" destination=\"3092\" id=\"hgY-Y1-W6o\"/>\n                <outlet property=\"serverListNoSelectionMenu\" destination=\"367\" id=\"XGd-aV-afa\"/>\n                <outlet property=\"userControlMenu\" destination=\"327\" id=\"Qyi-GH-9oZ\"/>\n            </connections>\n        </customObject>\n        <menu title=\"Menu\" id=\"367\" userLabel=\"Add Server Menu\">\n            <items>\n                <menuItem title=\"Add Server…\" tag=\"1400\" id=\"369\">\n                    <connections>\n                        <action selector=\"addServer:\" target=\"267\" id=\"2606\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"oPr-nd-Yxd\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"21\" y=\"-424\"/>\n        </menu>\n        <menu title=\"Menu\" id=\"374\" userLabel=\"Channel View Menu\">\n            <items>\n                <menuItem title=\"Change Nickname...\" tag=\"1200\" id=\"377\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"showServerChangeNicknameSheet:\" target=\"267\" id=\"tlA-ze-pwa\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1201\" id=\"378\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Search With Google\" tag=\"1202\" id=\"397\">\n                    <connections>\n                        <action selector=\"searchGoogle:\" target=\"267\" id=\"2591\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Look Up in Dictionary\" tag=\"1203\" id=\"Yts-x2-7aO\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"lookUpInDictionary:\" target=\"267\" id=\"uss-lW-HRk\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1204\" id=\"472\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Copy\" tag=\"1205\" keyEquivalent=\"c\" id=\"379\">\n                    <connections>\n                        <action selector=\"copy:\" target=\"267\" id=\"rVg-cQ-xDP\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Paste\" tag=\"1206\" keyEquivalent=\"v\" id=\"1778\">\n                    <connections>\n                        <action selector=\"paste:\" target=\"267\" id=\"2998\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1207\" id=\"1397\"/>\n                <menuItem title=\"Query Logs\" tag=\"1208\" keyEquivalent=\"L\" id=\"1492\">\n                    <connections>\n                        <action selector=\"openChannelLogs:\" target=\"267\" id=\"2571\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Channel\" tag=\"1209\" id=\"vBf-dC-Bvb\">\n                    <menu key=\"submenu\" title=\"Channel\" id=\"ooT-mM-5UK\"/>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"vC1-ft-wJ3\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"L6h-v2-qwT\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-434\" y=\"-545\"/>\n        </menu>\n        <menu title=\"File\" id=\"Q9Y-E0-gAT\" userLabel=\"Dock Menu\">\n            <items>\n                <menuItem title=\"Disable All Notifications\" tag=\"1700\" id=\"dnc-ku-aQ3\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"toggleMuteOnNotifications:\" target=\"267\" id=\"Hrx-oO-Zow\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Disable All Notification Sounds\" tag=\"1701\" keyEquivalent=\"M\" id=\"5jG-1t-WG4\">\n                    <connections>\n                        <action selector=\"toggleMuteOnNotificationSounds:\" target=\"267\" id=\"rBT-LB-lUy\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"2RV-vm-dLp\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"95\" y=\"-617\"/>\n        </menu>\n        <menu id=\"edI-1l-81o\" userLabel=\"Encryption Manager Status Menu\">\n            <items>\n                <menuItem title=\"What is this?\" tag=\"1500\" id=\"fdJ-Px-D0q\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionWhatIsThisInformation:\" target=\"267\" id=\"kzN-uE-GOs\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1501\" id=\"Rqm-1P-8cE\"/>\n                <menuItem title=\"Start Private Conversation\" tag=\"1502\" id=\"wTZ-NT-MgD\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionStartPrivateConversation:\" target=\"267\" id=\"uqX-jS-WxC\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Refresh Private Conversation\" tag=\"1503\" id=\"SJp-pz-WvU\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionRefreshPrivateConversation:\" target=\"267\" id=\"lS1-ZG-dAN\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"End Private Conversation\" tag=\"1504\" id=\"bJT-Nc-UwZ\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionEndPrivateConversation:\" target=\"267\" id=\"bPL-Ih-3je\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1505\" id=\"vgt-gi-rFQ\"/>\n                <menuItem title=\"Authenticate Chat Partner\" tag=\"1506\" id=\"9eO-kw-9HG\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionAuthenticateChatPartner:\" target=\"267\" id=\"F1j-kX-1Dw\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1507\" id=\"seh-5B-FFy\"/>\n                <menuItem title=\"View List of Fingerprints\" tag=\"1508\" id=\"aii-WP-szA\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"encryptionListFingerprints:\" target=\"267\" id=\"8Ai-8r-XNy\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"WYt-sp-mVt\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-452\" y=\"-306\"/>\n        </menu>\n        <menu id=\"963\" userLabel=\"Join Channel Menu\">\n            <items>\n                <menuItem title=\"Join Channel\" tag=\"1000\" id=\"964\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"joinChannelClicked:\" target=\"267\" id=\"PIP-i8-9N2\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"Up9-R6-U8F\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"22\" y=\"-515\"/>\n        </menu>\n        <menu title=\"MainMenu\" systemMenu=\"main\" id=\"29\">\n            <items>\n                <menuItem title=\"Textual\" tag=\"1\" id=\"56\">\n                    <menu key=\"submenu\" title=\"Textual\" systemMenu=\"apple\" id=\"57\">\n                        <items>\n                            <menuItem title=\"About Textual\" tag=\"100\" id=\"58\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showAboutWindow:\" target=\"267\" id=\"2575\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"101\" id=\"1001\"/>\n                            <menuItem title=\"Preferences…\" tag=\"102\" keyEquivalent=\",\" id=\"129\">\n                                <connections>\n                                    <action selector=\"showPreferencesWindow:\" target=\"267\" id=\"nJn-8N-O42\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Manage license…\" tag=\"103\" id=\"yeF-9Q-Tlt\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"manageLicense:\" target=\"267\" id=\"9xt-Qu-8UP\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Check for updates…\" tag=\"105\" id=\"SKm-yR-9hI\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"checkForUpdates:\" target=\"267\" id=\"Khl-F9-d2t\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"106\" id=\"143\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Services\" tag=\"107\" id=\"131\">\n                                <menu key=\"submenu\" title=\"Services\" systemMenu=\"services\" id=\"130\">\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"o09-mK-KWY\"/>\n                                    </connections>\n                                </menu>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"108\" id=\"144\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Hide Textual\" tag=\"109\" keyEquivalent=\"h\" id=\"134\">\n                                <connections>\n                                    <action selector=\"hide:\" target=\"-2\" id=\"152\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Hide Others\" tag=\"110\" keyEquivalent=\"h\" id=\"145\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"hideOtherApplications:\" target=\"-2\" id=\"146\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Show All\" tag=\"111\" id=\"150\">\n                                <connections>\n                                    <action selector=\"unhideAllApplications:\" target=\"-2\" id=\"153\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"112\" id=\"149\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Quit Textual\" tag=\"113\" keyEquivalent=\"q\" id=\"136\">\n                                <connections>\n                                    <action selector=\"terminate:\" target=\"-2\" id=\"139\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"PN0-yW-wXe\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"K4E-hv-TxN\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"File\" tag=\"2\" id=\"1746\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"File\" id=\"1747\">\n                        <items>\n                            <menuItem title=\"Disable All Notifications\" tag=\"200\" id=\"QNy-Fk-SRO\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"toggleMuteOnNotifications:\" target=\"267\" id=\"BG4-hs-ZvW\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Disable All Notification Sounds\" tag=\"202\" keyEquivalent=\"M\" id=\"3092\">\n                                <connections>\n                                    <action selector=\"toggleMuteOnNotificationSounds:\" target=\"267\" id=\"Ox8-g0-Y9n\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"202\" id=\"3093\"/>\n                            <menuItem title=\"Print\" tag=\"203\" keyEquivalent=\"p\" id=\"3oe-sP-dbd\">\n                                <connections>\n                                    <action selector=\"print:\" target=\"267\" id=\"67R-xe-x0s\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"204\" id=\"Cel-Q1-WOk\"/>\n                            <menuItem title=\"Close Window\" tag=\"205\" keyEquivalent=\"w\" id=\"1770\">\n                                <connections>\n                                    <action selector=\"closeWindow:\" target=\"267\" id=\"CHQ-u4-kTI\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"pjj-nO-cXn\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"nyO-4e-eA9\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Edit\" tag=\"3\" id=\"163\">\n                    <menu key=\"submenu\" title=\"Edit\" id=\"169\">\n                        <items>\n                            <menuItem title=\"Undo\" tag=\"300\" keyEquivalent=\"z\" id=\"158\">\n                                <connections>\n                                    <action selector=\"undo:\" target=\"-1\" id=\"180\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Redo\" tag=\"301\" keyEquivalent=\"Z\" id=\"173\">\n                                <connections>\n                                    <action selector=\"redo:\" target=\"-1\" id=\"178\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"302\" id=\"156\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Cut\" tag=\"303\" keyEquivalent=\"x\" id=\"160\">\n                                <connections>\n                                    <action selector=\"cut:\" target=\"-1\" id=\"175\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Copy\" tag=\"304\" keyEquivalent=\"c\" id=\"157\">\n                                <connections>\n                                    <action selector=\"copy:\" target=\"-1\" id=\"2028\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Paste\" tag=\"305\" keyEquivalent=\"v\" id=\"1780\">\n                                <connections>\n                                    <action selector=\"paste:\" target=\"267\" id=\"2997\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete\" tag=\"306\" id=\"164\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"delete:\" target=\"-1\" id=\"195\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Select All\" tag=\"307\" keyEquivalent=\"a\" id=\"172\">\n                                <connections>\n                                    <action selector=\"selectAll:\" target=\"-1\" id=\"179\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"308\" id=\"174\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Find\" tag=\"309\" id=\"168\">\n                                <menu key=\"submenu\" title=\"Find\" showsStateColumn=\"NO\" id=\"159\">\n                                    <items>\n                                        <menuItem title=\"Find…\" tag=\"3090000\" keyEquivalent=\"f\" id=\"1453\">\n                                            <connections>\n                                                <action selector=\"showFindPrompt:\" target=\"267\" id=\"rJN-Xr-PAJ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Next\" tag=\"3090001\" keyEquivalent=\"g\" id=\"1454\">\n                                            <connections>\n                                                <action selector=\"showFindPrompt:\" target=\"267\" id=\"L8F-Ae-4jy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Find Previous\" tag=\"3090002\" keyEquivalent=\"G\" id=\"1455\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"showFindPrompt:\" target=\"267\" id=\"yYj-Ky-6L0\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"mMD-1t-j6S\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"ZZm-WO-ixt\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Spelling and Grammar\" id=\"71z-t0-k2U\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Spelling\" id=\"FNd-N6-hy7\">\n                                    <items>\n                                        <menuItem title=\"Show Spelling and Grammar\" keyEquivalent=\":\" id=\"2oJ-IA-p2L\">\n                                            <connections>\n                                                <action selector=\"showGuessPanel:\" target=\"-1\" id=\"Pus-9r-KFd\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Document Now\" keyEquivalent=\";\" id=\"Rwq-Vj-x2E\">\n                                            <connections>\n                                                <action selector=\"checkSpelling:\" target=\"-1\" id=\"8v7-5j-PwO\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"YJ3-Vc-jAo\"/>\n                                        <menuItem title=\"Check Spelling While Typing\" id=\"yqa-aO-xja\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleContinuousSpellChecking:\" target=\"-1\" id=\"IaC-GW-f5k\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Check Grammar With Spelling\" id=\"tWm-3u-DtG\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleGrammarChecking:\" target=\"-1\" id=\"nxP-oz-gde\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Correct Spelling Automatically\" id=\"e78-jX-wDa\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticSpellingCorrection:\" target=\"-1\" id=\"oJ9-8e-MKg\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"tMw-ub-5XS\"/>\n                                    </connections>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Substitutions\" id=\"8Uq-G1-gb8\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Substitutions\" id=\"JfQ-5K-b3k\">\n                                    <items>\n                                        <menuItem title=\"Show Substitutions\" id=\"mRD-Me-cP7\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"orderFrontSubstitutionsPanel:\" target=\"-1\" id=\"soz-EC-kl2\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" id=\"aUf-xB-9Kb\"/>\n                                        <menuItem title=\"Smart Copy/Paste\" id=\"9Nm-LZ-prJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleSmartInsertDelete:\" target=\"-1\" id=\"bJe-DX-2N0\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Quotes\" id=\"f5z-Eu-enx\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticQuoteSubstitution:\" target=\"-1\" id=\"gnu-Dy-zV5\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Dashes\" id=\"4ds-au-DCA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDashSubstitution:\" target=\"-1\" id=\"NFc-N1-8tD\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Smart Links\" id=\"vsE-DG-NhW\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticLinkDetection:\" target=\"-1\" id=\"Ofj-vQ-XBu\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Data Detectors\" id=\"c1N-Eq-Tcp\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticDataDetection:\" target=\"-1\" id=\"6OR-s2-AQq\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Replacement\" id=\"gal-LY-imE\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleAutomaticTextReplacement:\" target=\"-1\" id=\"6Rk-PR-r9k\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"J4o-4q-5Sj\"/>\n                                    </connections>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Transformations\" id=\"sv8-hw-0D2\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Transformations\" id=\"Ezw-r3-Ssh\">\n                                    <items>\n                                        <menuItem title=\"Make Upper Case\" id=\"Di1-pQ-7gt\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"uppercaseWord:\" target=\"-1\" id=\"KLn-vt-fN8\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Make Lower Case\" id=\"VtS-Ww-rJ4\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"lowercaseWord:\" target=\"-1\" id=\"YnG-hf-GMy\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Capitalize\" id=\"i8F-xa-ETA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"capitalizeWord:\" target=\"-1\" id=\"PKp-xW-aiA\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"K7C-cW-yT2\"/>\n                                    </connections>\n                                </menu>\n                            </menuItem>\n                            <menuItem title=\"Speech\" id=\"rKL-ND-sIh\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Speech\" id=\"jlf-mn-Icz\">\n                                    <items>\n                                        <menuItem title=\"Start Speaking\" id=\"hmE-s1-jsc\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"startSpeaking:\" target=\"-1\" id=\"Ih7-Kg-AZv\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Stop Speaking\" id=\"PjN-ea-ukt\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"stopSpeaking:\" target=\"-1\" id=\"Qvg-YQ-V24\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"FQR-pW-MwC\"/>\n                                    </connections>\n                                </menu>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"tyA-4J-7Q6\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"ASP-Hh-Tba\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"View\" tag=\"4\" id=\"1782\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"View\" id=\"1783\">\n                        <items>\n                            <menuItem title=\"Mark Scrollback\" tag=\"400\" keyEquivalent=\"l\" id=\"1786\">\n                                <connections>\n                                    <action selector=\"markScrollback:\" target=\"267\" id=\"2593\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Scrollback Marker\" tag=\"401\" keyEquivalent=\"l\" id=\"2305\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"gotoScrollbackMarker:\" target=\"267\" id=\"2595\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"402\" id=\"2307\"/>\n                            <menuItem title=\"Mark All As Read\" tag=\"403\" keyEquivalent=\"U\" id=\"1924\">\n                                <connections>\n                                    <action selector=\"markAllAsRead:\" target=\"267\" id=\"2596\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Clear Scrollback\" tag=\"404\" keyEquivalent=\"k\" id=\"2299\">\n                                <connections>\n                                    <action selector=\"clearScrollback:\" target=\"267\" id=\"2594\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"405\" id=\"1788\"/>\n                            <menuItem title=\"Increase Font Size\" tag=\"406\" keyEquivalent=\"=\" id=\"1919\">\n                                <connections>\n                                    <action selector=\"increaseLogFontSize:\" target=\"267\" id=\"2597\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Decrease Font Size\" tag=\"407\" keyEquivalent=\"-\" id=\"1921\">\n                                <connections>\n                                    <action selector=\"decreaseLogFontSize:\" target=\"267\" id=\"2598\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"408\" id=\"1918\"/>\n                            <menuItem title=\"Toggle Fullscreen\" tag=\"409\" keyEquivalent=\"f\" id=\"1790\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleFullscreen:\" target=\"267\" id=\"v4x-I2-JVb\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"gQv-ZE-0tg\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"zhW-0k-ebX\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Server\" tag=\"5\" id=\"286\">\n                    <menu key=\"submenu\" title=\"Server\" id=\"287\">\n                        <items>\n                            <menuItem title=\"Connect\" tag=\"500\" id=\"288\">\n                                <connections>\n                                    <action selector=\"connect:\" target=\"267\" id=\"2599\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Connect Without Proxy\" tag=\"501\" id=\"WUj-Jg-uiz\">\n                                <connections>\n                                    <action selector=\"connectBypassingProxy:\" target=\"267\" id=\"nq7-WC-EKW\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Disconnect\" tag=\"502\" id=\"289\">\n                                <connections>\n                                    <action selector=\"disconnect:\" target=\"267\" id=\"2600\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Cancel Reconnect\" tag=\"503\" id=\"406\">\n                                <connections>\n                                    <action selector=\"cancelReconnection:\" target=\"267\" id=\"2601\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"504\" id=\"293\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Channel List…\" tag=\"505\" id=\"492\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showServerChannelList:\" target=\"267\" id=\"2604\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Change Nickname…\" tag=\"506\" id=\"297\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showServerChangeNicknameSheet:\" target=\"267\" id=\"kCq-Fc-lPR\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"507\" id=\"298\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Add Server…\" tag=\"508\" id=\"300\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"addServer:\" target=\"267\" id=\"2605\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Duplicate Server\" tag=\"509\" id=\"304\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"duplicateServer:\" target=\"267\" id=\"Ged-g2-cAh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Delete Server…\" tag=\"510\" id=\"301\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCA\n</string>\n                                <connections>\n                                    <action selector=\"deleteServer:\" target=\"267\" id=\"2608\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"511\" id=\"303\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Add Channel…\" tag=\"512\" keyEquivalent=\"+\" id=\"320\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"addChannel:\" target=\"267\" id=\"2619\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"513\" id=\"319\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Server Properties…\" tag=\"514\" keyEquivalent=\"u\" id=\"302\">\n                                <connections>\n                                    <action selector=\"showServerPropertiesSheet:\" target=\"267\" id=\"rk8-q9-syi\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"pQH-ZC-X9q\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"oCW-OL-I1v\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Channel\" tag=\"6\" id=\"276\">\n                    <menu key=\"submenu\" title=\"Channel\" id=\"277\">\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"T2H-cP-LPd\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"Agc-rV-LPJ\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Query\" tag=\"7\" id=\"d6g-it-Teq\">\n                    <menu key=\"submenu\" title=\"Query\" id=\"hfh-O1-XP3\">\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"m25-SC-w3J\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"btc-wk-RoB\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Navigation\" tag=\"8\" id=\"1542\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Navigation\" id=\"1543\">\n                        <items>\n                            <menuItem title=\"Servers\" tag=\"700\" id=\"1545\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Servers\" id=\"1546\">\n                                    <items>\n                                        <menuItem title=\"Next Server\" tag=\"7000000\" keyEquivalent=\"\" id=\"1547\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"33c-3O-4GY\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Previous Server\" tag=\"7000001\" keyEquivalent=\"\" id=\"1566\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"QBb-k7-SHd\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"7000002\" id=\"1575\"/>\n                                        <menuItem title=\"Next Active Server\" tag=\"7000003\" keyEquivalent=\"\" id=\"1567\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" option=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"Fd1-Q6-tFn\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Previous Active Server\" tag=\"7000004\" keyEquivalent=\"\" id=\"1568\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" option=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"A17-lY-xgQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"z4H-yG-JiW\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"ILC-uk-HLC\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Channels\" tag=\"701\" id=\"1548\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Channels\" id=\"1549\">\n                                    <items>\n                                        <menuItem title=\"Next Channel\" tag=\"7010000\" keyEquivalent=\"]\" id=\"1552\">\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"FEm-TJ-BlC\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Previous Channel\" tag=\"7010001\" keyEquivalent=\"[\" id=\"1553\">\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"qJH-4r-wb0\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"7010002\" id=\"1564\"/>\n                                        <menuItem title=\"Next Active Channel\" tag=\"7010003\" keyEquivalent=\"]\" id=\"1550\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"IMx-qS-u08\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Previous Active Channel\" tag=\"7010004\" keyEquivalent=\"[\" id=\"1551\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"lHv-lA-vR6\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"7010005\" id=\"1565\"/>\n                                        <menuItem title=\"Next Unread Channel\" tag=\"7010006\" id=\"1554\">\n                                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCQ\n</string>\n                                            <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"jAU-OK-CRa\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Previous Unread Channel\" tag=\"7010007\" id=\"1555\">\n                                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCQ\n</string>\n                                            <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" control=\"YES\"/>\n                                            <connections>\n                                                <action selector=\"performNavigationAction:\" target=\"267\" id=\"C4b-0U-OJO\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"fwF-bl-9az\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"Cp4-nH-QgN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"702\" id=\"1576\"/>\n                            <menuItem title=\"Move Backward\" tag=\"703\" id=\"4BH-0G-zyN\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performNavigationAction:\" target=\"267\" id=\"TYh-BI-Pqn\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Move Forward\" tag=\"704\" id=\"1577\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCQ\n</string>\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"performNavigationAction:\" target=\"267\" id=\"yn1-bX-GHN\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"705\" id=\"KcO-aF-w7t\"/>\n                            <menuItem title=\"Previous Selection\" tag=\"706\" id=\"1591\">\n                                <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCQ\n</string>\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\"/>\n                                <connections>\n                                    <action selector=\"performNavigationAction:\" target=\"267\" id=\"8GH-xS-E09\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"707\" id=\"2278\"/>\n                            <menuItem title=\"Next Highlight\" tag=\"708\" keyEquivalent=\"\" id=\"2276\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"onNextHighlight:\" target=\"267\" id=\"2303\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Previous Highlight\" tag=\"709\" keyEquivalent=\"\" id=\"2277\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"onPreviousHighlight:\" target=\"267\" id=\"2304\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"710\" id=\"pdm-79-JE9\"/>\n                            <menuItem title=\"Jump to Current Session\" tag=\"711\" id=\"Z6x-pq-6mw\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"jumpToCurrentSession:\" target=\"267\" id=\"ffs-z9-79e\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Jump to Present\" tag=\"712\" keyEquivalent=\"b\" id=\"S3s-dt-aIR\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"jumpToPresent:\" target=\"267\" id=\"f6S-m2-EOq\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"713\" id=\"4n1-ds-J5l\"/>\n                            <menuItem title=\"Channel List…\" tag=\"714\" id=\"FbN-9g-vFD\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Channel List…\" id=\"89a-J1-2zg\">\n                                    <items>\n                                        <menuItem title=\"Item\" id=\"TxA-XA-q8p\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"3oS-Rx-p0w\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"FJN-O8-gJT\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"715\" id=\"rFI-Dq-HBe\"/>\n                            <menuItem title=\"Search channels…\" tag=\"716\" keyEquivalent=\"d\" id=\"J3M-kj-Pa7\">\n                                <connections>\n                                    <action selector=\"showChannelSpotlightWindow:\" target=\"267\" id=\"ttM-ud-1xT\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"Jkm-kT-YoU\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"BVR-3b-g0j\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Window\" tag=\"9\" id=\"19\">\n                    <menu key=\"submenu\" title=\"Window\" systemMenu=\"window\" id=\"24\">\n                        <items>\n                            <menuItem title=\"Minimize\" tag=\"800\" keyEquivalent=\"m\" id=\"23\">\n                                <connections>\n                                    <action selector=\"performMiniaturize:\" target=\"-1\" id=\"37\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Zoom\" tag=\"801\" id=\"1364\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"performZoom:\" target=\"-1\" id=\"1377\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"802\" id=\"477\"/>\n                            <menuItem title=\"Toggle Visibility of Member List\" tag=\"803\" keyEquivalent=\"u\" id=\"qom-q3-cE2\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleMemberListVisibility:\" target=\"267\" id=\"BE4-sJ-zAs\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Toggle Visibility of Server List\" tag=\"804\" keyEquivalent=\"s\" id=\"6od-OR-qNS\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleServerListVisibility:\" target=\"267\" id=\"QZ5-GG-Vjc\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Toggle Window Appearance\" tag=\"805\" keyEquivalent=\"D\" id=\"FMz-pu-hpN\">\n                                <connections>\n                                    <action selector=\"toggleMainWindowAppearance:\" target=\"267\" id=\"zCO-93-Kgg\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"806\" id=\"Jza-lS-TTR\"/>\n                            <menuItem title=\"Sort Channel List\" tag=\"807\" keyEquivalent=\"r\" id=\"1306\">\n                                <connections>\n                                    <action selector=\"sortChannelListNames:\" target=\"267\" id=\"2579\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"808\" id=\"EnE-LZ-pWA\"/>\n                            <menuItem title=\"Center Window\" tag=\"809\" id=\"1524\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"centerMainWindow:\" target=\"267\" id=\"2554\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Reset Window to Default Size\" tag=\"810\" id=\"3096\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"resetMainWindowFrame:\" target=\"267\" id=\"Tv5-j5-MYf\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"811\" id=\"1308\"/>\n                            <menuItem title=\"Main Window\" tag=\"812\" keyEquivalent=\"1\" id=\"1309\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"showMainWindow:\" target=\"267\" id=\"2578\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Address Book\" tag=\"813\" keyEquivalent=\"2\" id=\"1310\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"showAddressBook:\" target=\"267\" id=\"5pS-cz-5ce\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Ignore List\" tag=\"814\" keyEquivalent=\"3\" id=\"1451\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"showIgnoreList:\" target=\"267\" id=\"Vza-RY-BtS\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"View Logs\" tag=\"815\" keyEquivalent=\"4\" id=\"1378\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"openLogLocation:\" target=\"267\" id=\"2574\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Highlight List\" tag=\"816\" keyEquivalent=\"5\" id=\"2268\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"showServerHighlightList:\" target=\"267\" id=\"QzC-Mq-UeU\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"File Transfers\" tag=\"817\" keyEquivalent=\"6\" id=\"CDY-3R-NUL\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\"/>\n                                <connections>\n                                    <action selector=\"showFileTransfersWindow:\" target=\"267\" id=\"klt-6R-Q9W\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"818\" id=\"92\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                            </menuItem>\n                            <menuItem title=\"Bring All to Front\" tag=\"819\" id=\"5\">\n                                <connections>\n                                    <action selector=\"arrangeInFront:\" target=\"-1\" id=\"39\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"LlZ-tx-h0l\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"oft-RM-Sbj\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Help\" tag=\"10\" id=\"1384\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Help\" systemMenu=\"help\" id=\"1385\">\n                        <items>\n                            <menuItem title=\"Acknowledgements\" tag=\"900\" id=\"1796\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"openAcknowledgements:\" target=\"267\" id=\"2556\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"License Agreement\" tag=\"901\" id=\"BrC-PS-U3X\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"ell-Ij-llA\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Privacy Policy\" tag=\"902\" id=\"1710\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"7cF-3R-5pW\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"903\" id=\"1661\"/>\n                            <menuItem title=\"Frequently Asked Questions\" tag=\"904\" id=\"gkX-Of-Y5Q\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"G7o-2j-dES\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Knowledge Base\" tag=\"905\" id=\"1686\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Knowledge Base\" id=\"1687\">\n                                    <items>\n                                        <menuItem title=\"Knowledge Base Home\" tag=\"9050000\" id=\"01c-Ny-YrB\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"ujf-rz-QKO\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9050001\" id=\"VTu-dA-PTE\"/>\n                                        <menuItem title=\"Chat Encryption\" tag=\"9050004\" id=\"w1H-u0-OYW\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"Ttg-Hf-X1o\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Command Reference\" tag=\"9050005\" id=\"1667\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"fkh-AP-nEH\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Feature Requests\" tag=\"9050006\" id=\"1689\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"kbI-Gd-aBG\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Keyboard Shortcuts\" tag=\"9050007\" id=\"3080\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"EcI-bN-kg9\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Memory Management\" tag=\"9050008\" id=\"1691\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"yKU-Kd-2sX\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Network Timeouts\" tag=\"9050016\" id=\"tGD-xh-GnJ\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"yNp-EX-dir\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Text Formatting\" tag=\"9050009\" id=\"1693\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"VqO-jK-WsS\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Styling Information\" tag=\"9050010\" id=\"1695\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"F9h-mt-chQ\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9050011\" id=\"3079\"/>\n                                        <menuItem title=\"Connecting with a Certificate\" tag=\"9050012\" id=\"o9J-hu-dKA\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"6Ax-wH-9h7\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Connecting to a ZNC Bouncer\" tag=\"9050013\" id=\"VQN-Rg-JZ0\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"QOa-Cc-r8n\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9050014\" id=\"e0i-mT-GT6\"/>\n                                        <menuItem title=\"DCC File Transfer Information\" tag=\"9050015\" id=\"3064\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"openHelpMenuItem:\" target=\"267\" id=\"qfF-bN-57R\"/>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"Hme-Rb-WrG\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"brg-bn-EbZ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"906\" id=\"Ws1-vl-bOl\"/>\n                            <menuItem title=\"Connect to Help Channel\" tag=\"907\" id=\"1392\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"connectToTextualHelpChannel:\" target=\"267\" id=\"2568\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Connect to Testing Channel\" tag=\"908\" id=\"2706\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"connectToTextualTestingChannel:\" target=\"267\" id=\"2708\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"909\" id=\"1795\"/>\n                            <menuItem title=\"Advanced\" tag=\"910\" id=\"2718\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <menu key=\"submenu\" title=\"Advanced\" id=\"2719\">\n                                    <items>\n                                        <menuItem title=\"Enable Developer Mode\" tag=\"9100000\" id=\"2280\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"toggleDeveloperMode:\" target=\"267\" id=\"2281\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9100001\" id=\"2721\"/>\n                                        <menuItem title=\"Hidden Preferences…\" tag=\"9100002\" id=\"2725\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"showHiddenPreferences:\" target=\"267\" id=\"SSd-K5-dFp\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9100003\" id=\"3085\"/>\n                                        <menuItem title=\"Export Preferences\" tag=\"9100004\" id=\"3088\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"exportPreferences:\" target=\"267\" id=\"3091\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Import Preferences\" tag=\"9100005\" id=\"3086\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"importPreferences:\" target=\"267\" id=\"3090\"/>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem isSeparatorItem=\"YES\" tag=\"9100006\" id=\"gIQ-2m-VHD\">\n                                            <connections>\n                                                <binding destination=\"TlT-Ik-3QP\" name=\"hidden\" keyPath=\"values.TextualDeveloperEnvironment\" id=\"7wz-iv-L8K\">\n                                                    <dictionary key=\"options\">\n                                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                    </dictionary>\n                                                </binding>\n                                            </connections>\n                                        </menuItem>\n                                        <menuItem title=\"Reset &quot;Don't Ask Me&quot; Warnings\" tag=\"9100007\" id=\"UfC-Uf-EFM\">\n                                            <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                            <connections>\n                                                <action selector=\"resetDoNotAskMePopupWarnings:\" target=\"267\" id=\"z5V-jK-Ms7\"/>\n                                                <binding destination=\"TlT-Ik-3QP\" name=\"hidden\" keyPath=\"values.TextualDeveloperEnvironment\" id=\"B8q-Zl-Mul\">\n                                                    <dictionary key=\"options\">\n                                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                                    </dictionary>\n                                                </binding>\n                                            </connections>\n                                        </menuItem>\n                                    </items>\n                                    <connections>\n                                        <outlet property=\"delegate\" destination=\"267\" id=\"Vke-2T-jD9\"/>\n                                    </connections>\n                                </menu>\n                                <connections>\n                                    <action selector=\"emptyAction:\" target=\"267\" id=\"c1K-oo-2Iu\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"xBH-z6-KOr\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"mVd-0G-AFH\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"Mt0-YV-PA3\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-226\" y=\"-741\"/>\n        </menu>\n        <menu title=\"Channel\" id=\"1s1-yL-ZHT\" userLabel=\"Main Menu Channel Menu\">\n            <items>\n                <menuItem title=\"Join Channel\" tag=\"600\" id=\"VDf-LC-AQe\">\n                    <connections>\n                        <action selector=\"joinChannel:\" target=\"267\" id=\"Xho-FL-l1F\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Leave Channel\" tag=\"601\" id=\"6Pu-S2-OdH\">\n                    <connections>\n                        <action selector=\"leaveChannel:\" target=\"267\" id=\"raX-Uv-OO0\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"602\" id=\"gyR-vq-vvN\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Add Channel…\" tag=\"603\" keyEquivalent=\"+\" id=\"iaX-9x-rWn\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"addChannel:\" target=\"267\" id=\"fCm-ro-Nf1\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Delete Channel\" tag=\"604\" id=\"Z4A-oQ-yoK\">\n                    <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCA\n</string>\n                    <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"deleteChannel:\" target=\"267\" id=\"ZW3-ae-pDI\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"605\" id=\"O0y-AX-HXr\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"View Logs\" tag=\"606\" keyEquivalent=\"L\" id=\"1VV-Oq-Rk6\">\n                    <connections>\n                        <action selector=\"openChannelLogs:\" target=\"267\" id=\"47A-tT-tZa\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"607\" id=\"avn-dz-Qmm\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Modify Topic\" tag=\"608\" keyEquivalent=\"t\" id=\"RId-Ia-xg5\">\n                    <connections>\n                        <action selector=\"showChannelModifyTopicSheet:\" target=\"267\" id=\"at7-Bz-xYc\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Modes\" tag=\"609\" id=\"HAP-Md-4qh\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"Modes\" id=\"iSZ-k7-gbv\">\n                        <items>\n                            <menuItem title=\"Moderated (+m)\" tag=\"6090000\" keyEquivalent=\"M\" id=\"lWy-z7-Hem\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleChannelModerationMode:\" target=\"267\" id=\"c2o-rb-DRh\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Unmoderated (-m)\" tag=\"6090001\" keyEquivalent=\"m\" id=\"rro-UW-UWz\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleChannelModerationMode:\" target=\"267\" id=\"495-2e-0Jp\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"6090002\" id=\"M8P-bM-0w4\"/>\n                            <menuItem title=\"Invite Only (+i)\" tag=\"6090003\" keyEquivalent=\"I\" id=\"L1b-7x-bd4\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleChannelInviteMode:\" target=\"267\" id=\"z7P-9I-MUZ\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Anyone Can Join (-i)\" tag=\"6090004\" keyEquivalent=\"i\" id=\"cO1-TC-8Ks\">\n                                <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                                <connections>\n                                    <action selector=\"toggleChannelInviteMode:\" target=\"267\" id=\"9Go-RV-b9b\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"6090005\" id=\"Azs-Ib-6y7\"/>\n                            <menuItem title=\"Manage All Modes\" tag=\"6090006\" keyEquivalent=\"o\" id=\"2Em-53-ZkH\">\n                                <connections>\n                                    <action selector=\"showChannelModifyModesSheet:\" target=\"267\" id=\"4Cq-dH-L56\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"mFM-jK-rMh\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"2HF-eb-2PN\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"610\" id=\"RqG-lo-Gxd\"/>\n                <menuItem title=\"List of Bans\" tag=\"611\" keyEquivalent=\"B\" id=\"3Th-KI-FDa\">\n                    <connections>\n                        <action selector=\"showChannelBanList:\" target=\"267\" id=\"ljO-i2-HSo\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"List of Ban Exceptions\" tag=\"612\" keyEquivalent=\"E\" id=\"JDw-Hy-xwD\">\n                    <connections>\n                        <action selector=\"showChannelBanExceptionList:\" target=\"267\" id=\"8ov-fX-8lN\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"List of Invite Exceptions\" tag=\"613\" keyEquivalent=\"I\" id=\"fgw-tx-l9L\">\n                    <connections>\n                        <action selector=\"showChannelInviteExceptionList:\" target=\"267\" id=\"oCP-WI-lax\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"List of Quiets\" tag=\"614\" id=\"0Ea-Ek-qd7\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"showChannelQuietList:\" target=\"267\" id=\"1cz-cj-aO6\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"614\" id=\"ELz-5M-mXc\"/>\n                <menuItem title=\"Channel Properties…\" tag=\"615\" keyEquivalent=\"i\" id=\"rP5-rz-Tdf\">\n                    <connections>\n                        <action selector=\"showChannelPropertiesSheet:\" target=\"267\" id=\"uB4-c9-8pW\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"616\" id=\"G83-kQ-M4p\">\n                    <connections>\n                        <binding destination=\"TlT-Ik-3QP\" name=\"hidden\" keyPath=\"values.TextualDeveloperEnvironment\" id=\"Oq2-DH-zfe\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Copy Unique Identifier\" tag=\"617\" id=\"DuZ-FR-y17\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"copyUniqueIdentifier:\" target=\"267\" id=\"AP7-Yd-CKd\"/>\n                        <binding destination=\"TlT-Ik-3QP\" name=\"hidden\" keyPath=\"values.TextualDeveloperEnvironment\" id=\"5qO-OP-S9O\">\n                            <dictionary key=\"options\">\n                                <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                            </dictionary>\n                        </binding>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"pbv-Ao-GhP\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"74\" y=\"-168\"/>\n        </menu>\n        <menu title=\"Query\" id=\"6uP-Kf-gUN\" userLabel=\"Main Menu Query Menu\">\n            <items>\n                <menuItem title=\"Close Query\" tag=\"1800\" id=\"VZM-IN-6jc\">\n                    <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nCA\n</string>\n                    <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"leaveChannel:\" target=\"267\" id=\"mfX-sy-vbK\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1801\" id=\"4Jy-dg-PdG\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Query Logs\" tag=\"1802\" keyEquivalent=\"L\" id=\"HNx-8u-amC\">\n                    <connections>\n                        <action selector=\"openChannelLogs:\" target=\"267\" id=\"Fgb-hr-F9e\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"e9S-J4-SoO\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-222\" y=\"-61\"/>\n        </menu>\n        <menu title=\"Menu\" id=\"426\" userLabel=\"Open URL Menu\">\n            <items>\n                <menuItem title=\"Copy URL\" tag=\"1100\" id=\"427\">\n                    <connections>\n                        <action selector=\"copyUrl:\" target=\"267\" id=\"2645\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"n8y-YA-LIK\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-510\" y=\"-144\"/>\n        </menu>\n        <menu title=\"Menu\" id=\"2953\" userLabel=\"Segmented Controller Menu\">\n            <items>\n                <menuItem title=\"Add Server…\" tag=\"1300\" id=\"2954\">\n                    <connections>\n                        <action selector=\"addServer:\" target=\"267\" id=\"2955\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1301\" id=\"2957\"/>\n                <menuItem title=\"Add Channel…\" tag=\"1302\" keyEquivalent=\"+\" id=\"2958\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" shift=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"addChannel:\" target=\"267\" id=\"2959\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"e4U-Ty-iAr\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-479\" y=\"-38\"/>\n        </menu>\n        <menu title=\"Menu\" id=\"327\" userLabel=\"User Controls Menu\">\n            <items>\n                <menuItem title=\"Add Ignore\" tag=\"1600\" id=\"fw1-yc-Vm1\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"memberAddIgnore:\" target=\"267\" id=\"drP-cu-7wg\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Modify Ignore\" tag=\"1601\" id=\"cg4-kn-WKm\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"memberModifyIgnore:\" target=\"267\" id=\"zwS-Rh-6dG\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Remove Ignore\" tag=\"1602\" id=\"twe-vV-VYO\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"memberRemoveIgnore:\" target=\"267\" id=\"01h-cr-wYk\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1603\" id=\"lgn-Pi-rSn\"/>\n                <menuItem title=\"Invite to...\" tag=\"1604\" id=\"1003\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"memberSendInvite:\" target=\"267\" id=\"2627\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1605\" id=\"7tS-Df-q8O\"/>\n                <menuItem title=\"Get Info (Whois)\" tag=\"1606\" keyEquivalent=\"W\" id=\"328\">\n                    <connections>\n                        <action selector=\"memberSendWhois:\" target=\"267\" id=\"2625\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Private Message (Query)\" tag=\"1607\" id=\"329\">\n                    <connections>\n                        <action selector=\"memberStartPrivateMessage:\" target=\"267\" id=\"2924\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1608\" id=\"331\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Give Op (+o)\" tag=\"1609\" keyEquivalent=\"O\" id=\"1319\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"memberModeGiveOp:\" target=\"267\" id=\"BQv-JN-QCd\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Give Halfop (+h)\" tag=\"1610\" keyEquivalent=\"H\" id=\"1321\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"memberModeGiveHalfop:\" target=\"267\" id=\"FxT-S5-Tk1\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Give Voice (+v)\" tag=\"1611\" keyEquivalent=\"V\" id=\"1323\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" control=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"memberModeGiveVoice:\" target=\"267\" id=\"szn-vu-CME\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"All Modes Given\" tag=\"1612\" id=\"2553\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"SAa-JW-Qdf\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1613\" id=\"1315\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Take Op (-o)\" tag=\"1614\" keyEquivalent=\"O\" id=\"1320\">\n                    <connections>\n                        <action selector=\"memberModeTakeOp:\" target=\"267\" id=\"9Xw-5A-Wlw\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Take Halfop (-h)\" tag=\"1615\" keyEquivalent=\"H\" id=\"1322\">\n                    <connections>\n                        <action selector=\"memberModeTakeHalfop:\" target=\"267\" id=\"xd0-hD-BF4\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Take Voice (-v)\" tag=\"1616\" keyEquivalent=\"V\" id=\"1324\">\n                    <connections>\n                        <action selector=\"memberModeTakeVoice:\" target=\"267\" id=\"RdX-Vb-1ia\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"All Modes Taken\" tag=\"1617\" id=\"2552\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"CSP-dV-Wbc\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1618\" id=\"2295\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Ban\" tag=\"1619\" keyEquivalent=\"b\" id=\"1329\">\n                    <connections>\n                        <action selector=\"memberBanFromChannel:\" target=\"267\" id=\"YIF-Hw-0Ci\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Kick\" tag=\"1620\" keyEquivalent=\"k\" id=\"1350\">\n                    <connections>\n                        <action selector=\"memberKickFromChannel:\" target=\"267\" id=\"2639\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Ban and Kick\" tag=\"1621\" keyEquivalent=\"k\" id=\"1330\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" option=\"YES\" command=\"YES\"/>\n                    <connections>\n                        <action selector=\"memberKickbanFromChannel:\" target=\"267\" id=\"2641\"/>\n                    </connections>\n                </menuItem>\n                <menuItem isSeparatorItem=\"YES\" tag=\"1622\" id=\"1316\">\n                    <modifierMask key=\"keyEquivalentModifierMask\" command=\"YES\"/>\n                </menuItem>\n                <menuItem title=\"Client-to-Client\" tag=\"1623\" id=\"437\">\n                    <menu key=\"submenu\" title=\"Client-to-Client\" id=\"438\">\n                        <items>\n                            <menuItem title=\"Send file…\" tag=\"16230000\" id=\"Ckj-P4-1K5\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"memberSendFileRequest:\" target=\"267\" id=\"ILQ-5P-8gU\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"16230001\" id=\"tkc-j6-xvy\"/>\n                            <menuItem title=\"Lag (PING)\" tag=\"16230002\" id=\"439\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPPing:\" target=\"267\" id=\"2628\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Local Time (TIME)\" tag=\"16230003\" id=\"440\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPTime:\" target=\"267\" id=\"2629\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"16230004\" id=\"3101\"/>\n                            <menuItem title=\"Client Information (CLIENTINFO)\" tag=\"16230005\" id=\"443\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPClientInfo:\" target=\"267\" id=\"2632\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Client Version (VERSION)\" tag=\"16230006\" id=\"441\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPVersion:\" target=\"267\" id=\"2630\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"16230007\" id=\"3100\"/>\n                            <menuItem title=\"User Information (FINGER)\" tag=\"16230008\" id=\"3098\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPFinger:\" target=\"267\" id=\"3102\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"User Information (USERINFO)\" tag=\"16230009\" id=\"442\">\n                                <connections>\n                                    <action selector=\"memberSendCTCPUserinfo:\" target=\"267\" id=\"2631\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"f4y-5G-TtP\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"NFV-nw-zbW\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"IRC Operator\" tag=\"1624\" id=\"1331\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <menu key=\"submenu\" title=\"IRC Operator\" id=\"1332\">\n                        <items>\n                            <menuItem title=\"Set Virtual Host (vHost)\" tag=\"16240000\" id=\"1411\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"showSetVhostPrompt:\" target=\"267\" id=\"2567\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem isSeparatorItem=\"YES\" tag=\"16240001\" id=\"1410\"/>\n                            <menuItem title=\"Kill from Server\" tag=\"16240002\" id=\"1333\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"memberKillFromServer:\" target=\"267\" id=\"2642\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Shun on Server\" tag=\"16240003\" id=\"1334\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"memberShunOnServer:\" target=\"267\" id=\"RoJ-a4-3V6\"/>\n                                </connections>\n                            </menuItem>\n                            <menuItem title=\"Ban from Server (G:Line)\" tag=\"16240004\" id=\"1335\">\n                                <modifierMask key=\"keyEquivalentModifierMask\"/>\n                                <connections>\n                                    <action selector=\"memberBanFromServer:\" target=\"267\" id=\"onv-XN-5bA\"/>\n                                </connections>\n                            </menuItem>\n                        </items>\n                        <connections>\n                            <outlet property=\"delegate\" destination=\"267\" id=\"Qn9-eK-lcm\"/>\n                        </connections>\n                    </menu>\n                    <connections>\n                        <action selector=\"emptyAction:\" target=\"267\" id=\"WnP-IQ-zDq\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <connections>\n                <outlet property=\"delegate\" destination=\"267\" id=\"VR8-mY-poH\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-197\" y=\"-399\"/>\n        </menu>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/App/Textual App.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXAggregateTarget section */\n\t\t4CCF301015804DCE006FFE21 /* Build Frameworks */ = {\n\t\t\tisa = PBXAggregateTarget;\n\t\t\tbuildConfigurationList = 4CCF301115804DCE006FFE21 /* Build configuration list for PBXAggregateTarget \"Build Frameworks\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4CCF301715804DD1006FFE21 /* ShellScript */,\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Build Frameworks\";\n\t\t\tproductName = \"Build Frameworks\";\n\t\t};\n/* End PBXAggregateTarget section */\n\n/* Begin PBXBuildFile section */\n\t\t4C06DF2A20EC49A60055D09A /* IRCCommandIndexLocalData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A020EB676400448776 /* IRCCommandIndexLocalData.plist */; };\n\t\t4C06DF2B20EC49A60055D09A /* IRCCommandIndexRemoteData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C31539F20EB676400448776 /* IRCCommandIndexRemoteData.plist */; };\n\t\t4C06DF2C20EC49A60055D09A /* IRCNetworks.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A220EB676400448776 /* IRCNetworks.plist */; };\n\t\t4C06DF2F20EC49A60055D09A /* StaticStore.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A420EB676400448776 /* StaticStore.plist */; };\n\t\t4C06DF3020EC49A60055D09A /* TemplateLineTypes.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A120EB676400448776 /* TemplateLineTypes.plist */; };\n\t\t4C06DF3320EC49A60055D09A /* IRCCommandIndexLocalData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A020EB676400448776 /* IRCCommandIndexLocalData.plist */; };\n\t\t4C06DF3420EC49A60055D09A /* IRCCommandIndexRemoteData.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C31539F20EB676400448776 /* IRCCommandIndexRemoteData.plist */; };\n\t\t4C06DF3520EC49A60055D09A /* IRCNetworks.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A220EB676400448776 /* IRCNetworks.plist */; };\n\t\t4C06DF3820EC49A60055D09A /* StaticStore.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A420EB676400448776 /* StaticStore.plist */; };\n\t\t4C06DF3920EC49A60055D09A /* TemplateLineTypes.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A120EB676400448776 /* TemplateLineTypes.plist */; };\n\t\t4C06DF4320EC49B80055D09A /* RemoteLicenseSystemPublicKey.pub in Resources */ = {isa = PBXBuildFile; fileRef = 4C3152EE20EB676400448776 /* RemoteLicenseSystemPublicKey.pub */; };\n\t\t4C06DF4420EC49B90055D09A /* RemoteLicenseSystemPublicKey.pub in Resources */ = {isa = PBXBuildFile; fileRef = 4C3152EE20EB676400448776 /* RemoteLicenseSystemPublicKey.pub */; };\n\t\t4C06DFC920EC49FA0055D09A /* MainWindowSegmentedControlUserTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537820EB676400448776 /* MainWindowSegmentedControlUserTemplate.pdf */; };\n\t\t4C06DFCA20EC49FA0055D09A /* MainWindowSpotlightIconTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537920EB676400448776 /* MainWindowSpotlightIconTemplate.pdf */; };\n\t\t4C06DFCB20EC49FA0055D09A /* ErroneousTextFieldValueIndicator.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537B20EB676400448776 /* ErroneousTextFieldValueIndicator.tif */; };\n\t\t4C06DFCC20EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537E20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif */; };\n\t\t4C06DFCD20EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537F20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif */; };\n\t\t4C06DFD020EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538220EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif */; };\n\t\t4C06DFD120EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538320EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive.tif */; };\n\t\t4C06DFD220EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538420EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif */; };\n\t\t4C06DFD320EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538520EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif */; };\n\t\t4C06DFD420EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538620EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif */; };\n\t\t4C06DFD520EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538720EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif */; };\n\t\t4C06DFE420EC49FB0055D09A /* MainWindowSegmentedControlUserTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537820EB676400448776 /* MainWindowSegmentedControlUserTemplate.pdf */; };\n\t\t4C06DFE520EC49FB0055D09A /* MainWindowSpotlightIconTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537920EB676400448776 /* MainWindowSpotlightIconTemplate.pdf */; };\n\t\t4C06DFE620EC49FB0055D09A /* ErroneousTextFieldValueIndicator.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537B20EB676400448776 /* ErroneousTextFieldValueIndicator.tif */; };\n\t\t4C06DFE720EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537E20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif */; };\n\t\t4C06DFE820EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537F20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif */; };\n\t\t4C06DFEB20EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538220EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif */; };\n\t\t4C06DFEC20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538320EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive.tif */; };\n\t\t4C06DFED20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538420EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif */; };\n\t\t4C06DFEE20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538520EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif */; };\n\t\t4C06DFEF20EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538620EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif */; };\n\t\t4C06DFF020EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31538720EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif */; };\n\t\t4C06E02020EC4A060055D09A /* DIRedBadgeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537020EB676400448776 /* DIRedBadgeRight.png */; };\n\t\t4C06E02120EC4A060055D09A /* DIRedBadgeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537120EB676400448776 /* DIRedBadgeLeft.png */; };\n\t\t4C06E02220EC4A060055D09A /* DIRedBadgeCenter.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537220EB676400448776 /* DIRedBadgeCenter.png */; };\n\t\t4C06E02620EC4A060055D09A /* DIRedBadgeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537020EB676400448776 /* DIRedBadgeRight.png */; };\n\t\t4C06E02720EC4A060055D09A /* DIRedBadgeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537120EB676400448776 /* DIRedBadgeLeft.png */; };\n\t\t4C06E02820EC4A060055D09A /* DIRedBadgeCenter.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31537220EB676400448776 /* DIRedBadgeCenter.png */; };\n\t\t4C06E03820EC4A0F0055D09A /* DIGreenBadgeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535F20EB676400448776 /* DIGreenBadgeLeft.png */; };\n\t\t4C06E03920EC4A0F0055D09A /* DIGreenBadgeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31536020EB676400448776 /* DIGreenBadgeRight.png */; };\n\t\t4C06E03A20EC4A0F0055D09A /* DIGreenBadgeCenter.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31536120EB676400448776 /* DIGreenBadgeCenter.png */; };\n\t\t4C06E03E20EC4A100055D09A /* DIGreenBadgeLeft.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535F20EB676400448776 /* DIGreenBadgeLeft.png */; };\n\t\t4C06E03F20EC4A100055D09A /* DIGreenBadgeRight.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31536020EB676400448776 /* DIGreenBadgeRight.png */; };\n\t\t4C06E04020EC4A100055D09A /* DIGreenBadgeCenter.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31536120EB676400448776 /* DIGreenBadgeCenter.png */; };\n\t\t4C06E04C20EC4A2E0055D09A /* applicationIcon.iconset in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535920EB676400448776 /* applicationIcon.iconset */; };\n\t\t4C06E04D20EC4A2E0055D09A /* applicationIconBirthday.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535A20EB676400448776 /* applicationIconBirthday.icns */; };\n\t\t4C06E04E20EC4A2F0055D09A /* applicationIcon.iconset in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535920EB676400448776 /* applicationIcon.iconset */; };\n\t\t4C06E04F20EC4A2F0055D09A /* applicationIconBirthday.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535A20EB676400448776 /* applicationIconBirthday.icns */; };\n\t\t4C06E05320EC4A3D0055D09A /* Copyright Information for Images.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535620EB676400448776 /* Copyright Information for Images.txt */; };\n\t\t4C06E05420EC4A3E0055D09A /* Copyright Information for Images.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535620EB676400448776 /* Copyright Information for Images.txt */; };\n\t\t4C06E05A20EC4A4C0055D09A /* encryptionLockIconLight@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535020EB676400448776 /* encryptionLockIconLight@2x.tif */; };\n\t\t4C06E05B20EC4A4C0055D09A /* encryptionLockIconDark.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535120EB676400448776 /* encryptionLockIconDark.tif */; };\n\t\t4C06E05C20EC4A4C0055D09A /* encryptionLockIconDark@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535220EB676400448776 /* encryptionLockIconDark@2x.tif */; };\n\t\t4C06E05D20EC4A4C0055D09A /* encryptionLockIconLight.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535320EB676400448776 /* encryptionLockIconLight.tif */; };\n\t\t4C06E05E20EC4A4C0055D09A /* encryptionLockIconLight@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535020EB676400448776 /* encryptionLockIconLight@2x.tif */; };\n\t\t4C06E05F20EC4A4C0055D09A /* encryptionLockIconDark.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535120EB676400448776 /* encryptionLockIconDark.tif */; };\n\t\t4C06E06020EC4A4C0055D09A /* encryptionLockIconDark@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535220EB676400448776 /* encryptionLockIconDark@2x.tif */; };\n\t\t4C06E06120EC4A4C0055D09A /* encryptionLockIconLight.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31535320EB676400448776 /* encryptionLockIconLight.tif */; };\n\t\t4C06E07820EC4A540055D09A /* FormattingColor_8.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533D20EB676400448776 /* FormattingColor_8.png */; };\n\t\t4C06E07920EC4A540055D09A /* FormattingColor_9.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533E20EB676400448776 /* FormattingColor_9.png */; };\n\t\t4C06E07A20EC4A540055D09A /* FormattingColor_11.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533F20EB676400448776 /* FormattingColor_11.png */; };\n\t\t4C06E07B20EC4A540055D09A /* FormattingColor_10.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534020EB676400448776 /* FormattingColor_10.png */; };\n\t\t4C06E07C20EC4A540055D09A /* FormattingColor_12.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534120EB676400448776 /* FormattingColor_12.png */; };\n\t\t4C06E07D20EC4A540055D09A /* FormattingColor_Rainbow.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534220EB676400448776 /* FormattingColor_Rainbow.tif */; };\n\t\t4C06E07E20EC4A540055D09A /* FormattingColor_13.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534320EB676400448776 /* FormattingColor_13.png */; };\n\t\t4C06E07F20EC4A540055D09A /* FormattingColor_14.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534420EB676400448776 /* FormattingColor_14.png */; };\n\t\t4C06E08020EC4A540055D09A /* FormattingColor_15.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534520EB676400448776 /* FormattingColor_15.png */; };\n\t\t4C06E08120EC4A540055D09A /* FormattingColor_7.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534620EB676400448776 /* FormattingColor_7.png */; };\n\t\t4C06E08220EC4A540055D09A /* FormattingColor_6.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534720EB676400448776 /* FormattingColor_6.png */; };\n\t\t4C06E08320EC4A540055D09A /* FormattingColor_4.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534820EB676400448776 /* FormattingColor_4.png */; };\n\t\t4C06E08420EC4A540055D09A /* FormattingColor_5.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534920EB676400448776 /* FormattingColor_5.png */; };\n\t\t4C06E08520EC4A540055D09A /* FormattingColor_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534A20EB676400448776 /* FormattingColor_1.png */; };\n\t\t4C06E08620EC4A540055D09A /* FormattingColor_Rainbow@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534B20EB676400448776 /* FormattingColor_Rainbow@2x.tif */; };\n\t\t4C06E08720EC4A540055D09A /* FormattingColor_0.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534C20EB676400448776 /* FormattingColor_0.png */; };\n\t\t4C06E08820EC4A540055D09A /* FormattingColor_2.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534D20EB676400448776 /* FormattingColor_2.png */; };\n\t\t4C06E08920EC4A540055D09A /* FormattingColor_3.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534E20EB676400448776 /* FormattingColor_3.png */; };\n\t\t4C06E08A20EC4A540055D09A /* FormattingColor_8.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533D20EB676400448776 /* FormattingColor_8.png */; };\n\t\t4C06E08B20EC4A540055D09A /* FormattingColor_9.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533E20EB676400448776 /* FormattingColor_9.png */; };\n\t\t4C06E08C20EC4A540055D09A /* FormattingColor_11.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533F20EB676400448776 /* FormattingColor_11.png */; };\n\t\t4C06E08D20EC4A540055D09A /* FormattingColor_10.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534020EB676400448776 /* FormattingColor_10.png */; };\n\t\t4C06E08E20EC4A540055D09A /* FormattingColor_12.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534120EB676400448776 /* FormattingColor_12.png */; };\n\t\t4C06E08F20EC4A540055D09A /* FormattingColor_Rainbow.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534220EB676400448776 /* FormattingColor_Rainbow.tif */; };\n\t\t4C06E09020EC4A540055D09A /* FormattingColor_13.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534320EB676400448776 /* FormattingColor_13.png */; };\n\t\t4C06E09120EC4A540055D09A /* FormattingColor_14.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534420EB676400448776 /* FormattingColor_14.png */; };\n\t\t4C06E09220EC4A540055D09A /* FormattingColor_15.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534520EB676400448776 /* FormattingColor_15.png */; };\n\t\t4C06E09320EC4A540055D09A /* FormattingColor_7.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534620EB676400448776 /* FormattingColor_7.png */; };\n\t\t4C06E09420EC4A540055D09A /* FormattingColor_6.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534720EB676400448776 /* FormattingColor_6.png */; };\n\t\t4C06E09520EC4A540055D09A /* FormattingColor_4.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534820EB676400448776 /* FormattingColor_4.png */; };\n\t\t4C06E09620EC4A540055D09A /* FormattingColor_5.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534920EB676400448776 /* FormattingColor_5.png */; };\n\t\t4C06E09720EC4A540055D09A /* FormattingColor_1.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534A20EB676400448776 /* FormattingColor_1.png */; };\n\t\t4C06E09820EC4A540055D09A /* FormattingColor_Rainbow@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534B20EB676400448776 /* FormattingColor_Rainbow@2x.tif */; };\n\t\t4C06E09920EC4A540055D09A /* FormattingColor_0.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534C20EB676400448776 /* FormattingColor_0.png */; };\n\t\t4C06E09A20EC4A540055D09A /* FormattingColor_2.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534D20EB676400448776 /* FormattingColor_2.png */; };\n\t\t4C06E09B20EC4A540055D09A /* FormattingColor_3.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31534E20EB676400448776 /* FormattingColor_3.png */; };\n\t\t4C06E0B520EC4A5A0055D09A /* channelRoomStatusIconLightActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533120EB676400448776 /* channelRoomStatusIconLightActive@2x.tif */; };\n\t\t4C06E0B620EC4A5A0055D09A /* channelRoomStatusIconDarkActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533220EB676400448776 /* channelRoomStatusIconDarkActive@2x.tif */; };\n\t\t4C06E0B720EC4A5A0055D09A /* channelRoomStatusIconLightInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533320EB676400448776 /* channelRoomStatusIconLightInactive.tif */; };\n\t\t4C06E0B820EC4A5A0055D09A /* channelRoomStatusIconDarkInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533420EB676400448776 /* channelRoomStatusIconDarkInactive@2x.tif */; };\n\t\t4C06E0BA20EC4A5A0055D09A /* channelRoomStatusIconDarkActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533620EB676400448776 /* channelRoomStatusIconDarkActive.tif */; };\n\t\t4C06E0BB20EC4A5A0055D09A /* channelRoomStatusIconLightActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533720EB676400448776 /* channelRoomStatusIconLightActive.tif */; };\n\t\t4C06E0BD20EC4A5A0055D09A /* channelRoomStatusIconDarkInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533920EB676400448776 /* channelRoomStatusIconDarkInactive.tif */; };\n\t\t4C06E0BF20EC4A5A0055D09A /* channelRoomStatusIconLightInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533B20EB676400448776 /* channelRoomStatusIconLightInactive@2x.tif */; };\n\t\t4C06E0C720EC4A5B0055D09A /* channelRoomStatusIconLightActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533120EB676400448776 /* channelRoomStatusIconLightActive@2x.tif */; };\n\t\t4C06E0C820EC4A5B0055D09A /* channelRoomStatusIconDarkActive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533220EB676400448776 /* channelRoomStatusIconDarkActive@2x.tif */; };\n\t\t4C06E0C920EC4A5B0055D09A /* channelRoomStatusIconLightInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533320EB676400448776 /* channelRoomStatusIconLightInactive.tif */; };\n\t\t4C06E0CA20EC4A5B0055D09A /* channelRoomStatusIconDarkInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533420EB676400448776 /* channelRoomStatusIconDarkInactive@2x.tif */; };\n\t\t4C06E0CC20EC4A5B0055D09A /* channelRoomStatusIconDarkActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533620EB676400448776 /* channelRoomStatusIconDarkActive.tif */; };\n\t\t4C06E0CD20EC4A5B0055D09A /* channelRoomStatusIconLightActive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533720EB676400448776 /* channelRoomStatusIconLightActive.tif */; };\n\t\t4C06E0CF20EC4A5B0055D09A /* channelRoomStatusIconDarkInactive.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533920EB676400448776 /* channelRoomStatusIconDarkInactive.tif */; };\n\t\t4C06E0D120EC4A5B0055D09A /* channelRoomStatusIconLightInactive@2x.tif in Resources */ = {isa = PBXBuildFile; fileRef = 4C31533B20EB676400448776 /* channelRoomStatusIconLightInactive@2x.tif */; };\n\t\t4C06E10620EC4A630055D09A /* TPWTB_Advanced@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531920EB676400448776 /* TPWTB_Advanced@2x.png */; };\n\t\t4C06E10720EC4A630055D09A /* TPWTB_Highlights.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531A20EB676400448776 /* TPWTB_Highlights.png */; };\n\t\t4C06E10820EC4A630055D09A /* TPWTB_Highlights@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531B20EB676400448776 /* TPWTB_Highlights@2x.png */; };\n\t\t4C06E10920EC4A630055D09A /* TPWTB_Addons.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531C20EB676400448776 /* TPWTB_Addons.png */; };\n\t\t4C06E10A20EC4A630055D09A /* TPWTB_Advanced.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531D20EB676400448776 /* TPWTB_Advanced.png */; };\n\t\t4C06E10B20EC4A630055D09A /* TPWTB_Controls.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531E20EB676400448776 /* TPWTB_Controls.png */; };\n\t\t4C06E10C20EC4A630055D09A /* TPWTB_Style@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531F20EB676400448776 /* TPWTB_Style@2x.png */; };\n\t\t4C06E10D20EC4A630055D09A /* TPWTB_General@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532020EB676400448776 /* TPWTB_General@2x.png */; };\n\t\t4C06E10E20EC4A630055D09A /* TPWTB_Addons@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532120EB676400448776 /* TPWTB_Addons@2x.png */; };\n\t\t4C06E10F20EC4A630055D09A /* TPWTB_Notifications@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532220EB676400448776 /* TPWTB_Notifications@2x.png */; };\n\t\t4C06E11020EC4A630055D09A /* TPWTB_Controls@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532320EB676400448776 /* TPWTB_Controls@2x.png */; };\n\t\t4C06E11120EC4A630055D09A /* TPWTB_Interface.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532420EB676400448776 /* TPWTB_Interface.png */; };\n\t\t4C06E11220EC4A630055D09A /* TPWTB_Interface@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532520EB676400448776 /* TPWTB_Interface@2x.png */; };\n\t\t4C06E11320EC4A630055D09A /* TPWTB_Notifications.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532620EB676400448776 /* TPWTB_Notifications.png */; };\n\t\t4C06E11420EC4A630055D09A /* TPWTB_Style.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532720EB676400448776 /* TPWTB_Style.png */; };\n\t\t4C06E11520EC4A630055D09A /* TPWTB_General.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532820EB676400448776 /* TPWTB_General.png */; };\n\t\t4C06E11620EC4A630055D09A /* TPWTB_Advanced@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531920EB676400448776 /* TPWTB_Advanced@2x.png */; };\n\t\t4C06E11720EC4A630055D09A /* TPWTB_Highlights.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531A20EB676400448776 /* TPWTB_Highlights.png */; };\n\t\t4C06E11820EC4A630055D09A /* TPWTB_Highlights@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531B20EB676400448776 /* TPWTB_Highlights@2x.png */; };\n\t\t4C06E11920EC4A630055D09A /* TPWTB_Addons.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531C20EB676400448776 /* TPWTB_Addons.png */; };\n\t\t4C06E11A20EC4A630055D09A /* TPWTB_Advanced.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531D20EB676400448776 /* TPWTB_Advanced.png */; };\n\t\t4C06E11B20EC4A630055D09A /* TPWTB_Controls.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531E20EB676400448776 /* TPWTB_Controls.png */; };\n\t\t4C06E11C20EC4A630055D09A /* TPWTB_Style@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31531F20EB676400448776 /* TPWTB_Style@2x.png */; };\n\t\t4C06E11D20EC4A630055D09A /* TPWTB_General@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532020EB676400448776 /* TPWTB_General@2x.png */; };\n\t\t4C06E11E20EC4A630055D09A /* TPWTB_Addons@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532120EB676400448776 /* TPWTB_Addons@2x.png */; };\n\t\t4C06E11F20EC4A630055D09A /* TPWTB_Notifications@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532220EB676400448776 /* TPWTB_Notifications@2x.png */; };\n\t\t4C06E12020EC4A630055D09A /* TPWTB_Controls@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532320EB676400448776 /* TPWTB_Controls@2x.png */; };\n\t\t4C06E12120EC4A630055D09A /* TPWTB_Interface.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532420EB676400448776 /* TPWTB_Interface.png */; };\n\t\t4C06E12220EC4A630055D09A /* TPWTB_Interface@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532520EB676400448776 /* TPWTB_Interface@2x.png */; };\n\t\t4C06E12320EC4A630055D09A /* TPWTB_Notifications.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532620EB676400448776 /* TPWTB_Notifications.png */; };\n\t\t4C06E12420EC4A630055D09A /* TPWTB_Style.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532720EB676400448776 /* TPWTB_Style.png */; };\n\t\t4C06E12520EC4A630055D09A /* TPWTB_General.png in Resources */ = {isa = PBXBuildFile; fileRef = 4C31532820EB676400448776 /* TPWTB_General.png */; };\n\t\t4C06E18B20EC4AC40055D09A /* TDCServerPropertiesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13920EC4AC40055D09A /* TDCServerPropertiesSheet.xib */; };\n\t\t4C06E18C20EC4AC40055D09A /* TDCServerPropertiesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13920EC4AC40055D09A /* TDCServerPropertiesSheet.xib */; };\n\t\t4C06E19320EC4AC40055D09A /* TDCServerHighlightListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13D20EC4AC40055D09A /* TDCServerHighlightListSheet.xib */; };\n\t\t4C06E19420EC4AC40055D09A /* TDCServerHighlightListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13D20EC4AC40055D09A /* TDCServerHighlightListSheet.xib */; };\n\t\t4C06E19720EC4AC40055D09A /* TDCServerEndpointListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13F20EC4AC40055D09A /* TDCServerEndpointListSheet.xib */; };\n\t\t4C06E19820EC4AC40055D09A /* TDCServerEndpointListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E13F20EC4AC40055D09A /* TDCServerEndpointListSheet.xib */; };\n\t\t4C06E19B20EC4AC40055D09A /* TDCChannelModifyModesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14120EC4AC40055D09A /* TDCChannelModifyModesSheet.xib */; };\n\t\t4C06E19C20EC4AC40055D09A /* TDCChannelModifyModesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14120EC4AC40055D09A /* TDCChannelModifyModesSheet.xib */; };\n\t\t4C06E19F20EC4AC40055D09A /* TDCChannelSpotlightController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14320EC4AC40055D09A /* TDCChannelSpotlightController.xib */; };\n\t\t4C06E1A020EC4AC40055D09A /* TDCChannelSpotlightController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14320EC4AC40055D09A /* TDCChannelSpotlightController.xib */; };\n\t\t4C06E1A320EC4AC40055D09A /* TDCFileTransferDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14520EC4AC40055D09A /* TDCFileTransferDialog.xib */; };\n\t\t4C06E1A420EC4AC40055D09A /* TDCFileTransferDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14520EC4AC40055D09A /* TDCFileTransferDialog.xib */; };\n\t\t4C06E1A720EC4AC40055D09A /* TDCServerChannelListDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14720EC4AC40055D09A /* TDCServerChannelListDialog.xib */; };\n\t\t4C06E1A820EC4AC40055D09A /* TDCServerChannelListDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14720EC4AC40055D09A /* TDCServerChannelListDialog.xib */; };\n\t\t4C06E1AB20EC4AC40055D09A /* TDCChannelBanListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14920EC4AC40055D09A /* TDCChannelBanListSheet.xib */; };\n\t\t4C06E1AC20EC4AC40055D09A /* TDCChannelBanListSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14920EC4AC40055D09A /* TDCChannelBanListSheet.xib */; };\n\t\t4C06E1AF20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14B20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib */; };\n\t\t4C06E1B020EC4AC40055D09A /* TDCChannelPropertiesSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14B20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib */; };\n\t\t4C06E1B320EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14D20EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib */; };\n\t\t4C06E1B420EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E14D20EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib */; };\n\t\t4C06E1BB20EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15120EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib */; };\n\t\t4C06E1BC20EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15120EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib */; };\n\t\t4C06E1C320EC4AC40055D09A /* TVCChannelSelectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15520EC4AC40055D09A /* TVCChannelSelectionView.xib */; };\n\t\t4C06E1C420EC4AC40055D09A /* TVCChannelSelectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15520EC4AC40055D09A /* TVCChannelSelectionView.xib */; };\n\t\t4C06E1C720EC4AC40055D09A /* TXCMainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15720EC4AC40055D09A /* TXCMainMenu.xib */; };\n\t\t4C06E1C820EC4AC40055D09A /* TXCMainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15720EC4AC40055D09A /* TXCMainMenu.xib */; };\n\t\t4C06E1CB20EC4AC40055D09A /* TVCNotificationConfigurationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15920EC4AC40055D09A /* TVCNotificationConfigurationView.xib */; };\n\t\t4C06E1CC20EC4AC40055D09A /* TVCNotificationConfigurationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15920EC4AC40055D09A /* TVCNotificationConfigurationView.xib */; };\n\t\t4C06E1CF20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15B20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib */; };\n\t\t4C06E1D020EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15B20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib */; };\n\t\t4C06E1D320EC4AC40055D09A /* TDCPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15D20EC4AC40055D09A /* TDCPreferences.xib */; };\n\t\t4C06E1D420EC4AC40055D09A /* TDCPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15D20EC4AC40055D09A /* TDCPreferences.xib */; };\n\t\t4C06E1D720EC4AC40055D09A /* TDCChannelInviteSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15F20EC4AC40055D09A /* TDCChannelInviteSheet.xib */; };\n\t\t4C06E1D820EC4AC40055D09A /* TDCChannelInviteSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E15F20EC4AC40055D09A /* TDCChannelInviteSheet.xib */; };\n\t\t4C06E1DB20EC4AC40055D09A /* TDCNicknameColorSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16120EC4AC40055D09A /* TDCNicknameColorSheet.xib */; };\n\t\t4C06E1DC20EC4AC40055D09A /* TDCNicknameColorSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16120EC4AC40055D09A /* TDCNicknameColorSheet.xib */; };\n\t\t4C06E1DF20EC4AC40055D09A /* TDCWelcomeSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16320EC4AC40055D09A /* TDCWelcomeSheet.xib */; };\n\t\t4C06E1E020EC4AC40055D09A /* TDCWelcomeSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16320EC4AC40055D09A /* TDCWelcomeSheet.xib */; };\n\t\t4C06E1E320EC4AC40055D09A /* TDCProgressIndicatorSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16520EC4AC40055D09A /* TDCProgressIndicatorSheet.xib */; };\n\t\t4C06E1E420EC4AC40055D09A /* TDCProgressIndicatorSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16520EC4AC40055D09A /* TDCProgressIndicatorSheet.xib */; };\n\t\t4C06E1E720EC4AC50055D09A /* TDCAddressBookSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16720EC4AC40055D09A /* TDCAddressBookSheet.xib */; };\n\t\t4C06E1E820EC4AC50055D09A /* TDCAddressBookSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16720EC4AC40055D09A /* TDCAddressBookSheet.xib */; };\n\t\t4C06E1EB20EC4AC50055D09A /* TVCAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16920EC4AC40055D09A /* TVCAlert.xib */; };\n\t\t4C06E1EC20EC4AC50055D09A /* TVCAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16920EC4AC40055D09A /* TVCAlert.xib */; };\n\t\t4C06E1EF20EC4AC50055D09A /* TDCLicenseUpgradeDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16B20EC4AC40055D09A /* TDCLicenseUpgradeDialog.xib */; };\n\t\t4C06E1F020EC4AC50055D09A /* TDCLicenseUpgradeDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16B20EC4AC40055D09A /* TDCLicenseUpgradeDialog.xib */; };\n\t\t4C06E1F320EC4AC50055D09A /* TDCServerChangeNicknameSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16D20EC4AC40055D09A /* TDCServerChangeNicknameSheet.xib */; };\n\t\t4C06E1F420EC4AC50055D09A /* TDCServerChangeNicknameSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16D20EC4AC40055D09A /* TDCServerChangeNicknameSheet.xib */; };\n\t\t4C06E1F720EC4AC50055D09A /* TDCChannelModifyTopicSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16F20EC4AC40055D09A /* TDCChannelModifyTopicSheet.xib */; };\n\t\t4C06E1F820EC4AC50055D09A /* TDCChannelModifyTopicSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E16F20EC4AC40055D09A /* TDCChannelModifyTopicSheet.xib */; };\n\t\t4C06E1FB20EC4AC50055D09A /* TDCAboutDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17120EC4AC40055D09A /* TDCAboutDialog.xib */; };\n\t\t4C06E1FC20EC4AC50055D09A /* TDCAboutDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17120EC4AC40055D09A /* TDCAboutDialog.xib */; };\n\t\t4C06E1FF20EC4AC50055D09A /* TDCHighlightEntrySheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17320EC4AC40055D09A /* TDCHighlightEntrySheet.xib */; };\n\t\t4C06E20020EC4AC50055D09A /* TDCHighlightEntrySheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17320EC4AC40055D09A /* TDCHighlightEntrySheet.xib */; };\n\t\t4C06E20320EC4AC50055D09A /* TVCMainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17520EC4AC40055D09A /* TVCMainWindow.xib */; };\n\t\t4C06E20420EC4AC50055D09A /* TVCMainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17520EC4AC40055D09A /* TVCMainWindow.xib */; };\n\t\t4C06E20720EC4AC50055D09A /* TDCLicenseManagerDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17720EC4AC40055D09A /* TDCLicenseManagerDialog.xib */; };\n\t\t4C06E20820EC4AC50055D09A /* TDCLicenseManagerDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17720EC4AC40055D09A /* TDCLicenseManagerDialog.xib */; };\n\t\t4C06E20B20EC4AC50055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17920EC4AC40055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib */; };\n\t\t4C06E20C20EC4AC50055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17920EC4AC40055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib */; };\n\t\t4C06E20F20EC4AC50055D09A /* TVCMemberListAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17C20EC4AC40055D09A /* TVCMemberListAppearance.plist */; };\n\t\t4C06E21020EC4AC50055D09A /* TVCMemberListAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E17C20EC4AC40055D09A /* TVCMemberListAppearance.plist */; };\n\t\t4C06E22320EC4AC50055D09A /* TDCChannelSpotlightAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18120EC4AC40055D09A /* TDCChannelSpotlightAppearance.plist */; };\n\t\t4C06E22420EC4AC50055D09A /* TDCChannelSpotlightAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18120EC4AC40055D09A /* TDCChannelSpotlightAppearance.plist */; };\n\t\t4C06E22720EC4AC50055D09A /* TVCMainWindowAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18220EC4AC40055D09A /* TVCMainWindowAppearance.plist */; };\n\t\t4C06E22820EC4AC50055D09A /* TVCMainWindowAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18220EC4AC40055D09A /* TVCMainWindowAppearance.plist */; };\n\t\t4C06E22B20EC4AC50055D09A /* TVCMainWindowTextViewAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18320EC4AC40055D09A /* TVCMainWindowTextViewAppearance.plist */; };\n\t\t4C06E22C20EC4AC50055D09A /* TVCMainWindowTextViewAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18320EC4AC40055D09A /* TVCMainWindowTextViewAppearance.plist */; };\n\t\t4C06E22F20EC4AC50055D09A /* TVCServerListAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18420EC4AC40055D09A /* TVCServerListAppearance.plist */; };\n\t\t4C06E23020EC4AC50055D09A /* TVCServerListAppearance.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E18420EC4AC40055D09A /* TVCServerListAppearance.plist */; };\n\t\t4C06E24920EC4B970055D09A /* IRCConnectionConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E24720EC4B970055D09A /* IRCConnectionConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E24A20EC4B970055D09A /* IRCConnectionConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E24720EC4B970055D09A /* IRCConnectionConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E25D20EC4BBD0055D09A /* IRCConnectionConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E25B20EC4BBD0055D09A /* IRCConnectionConfigInternal.h */; };\n\t\t4C06E25E20EC4BBD0055D09A /* IRCConnectionConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E25B20EC4BBD0055D09A /* IRCConnectionConfigInternal.h */; };\n\t\t4C06E26420EC4C560055D09A /* TPCPreferencesPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26020EC4C560055D09A /* TPCPreferencesPrivate.h */; };\n\t\t4C06E26520EC4C560055D09A /* TPCPreferencesPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26020EC4C560055D09A /* TPCPreferencesPrivate.h */; };\n\t\t4C06E26820EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26120EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h */; };\n\t\t4C06E26920EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26120EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h */; };\n\t\t4C06E26C20EC4C560055D09A /* NSObjectHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26220EC4C560055D09A /* NSObjectHelperPrivate.h */; };\n\t\t4C06E26D20EC4C560055D09A /* NSObjectHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26220EC4C560055D09A /* NSObjectHelperPrivate.h */; };\n\t\t4C06E27120EC4E350055D09A /* StaticDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26F20EC4E350055D09A /* StaticDefinitions.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E27220EC4E350055D09A /* StaticDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E26F20EC4E350055D09A /* StaticDefinitions.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E27920EC4E870055D09A /* TLOTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27420EC4E850055D09A /* TLOTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E27A20EC4E870055D09A /* TLOTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27420EC4E850055D09A /* TLOTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E27D20EC4E870055D09A /* TPCPreferencesUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27520EC4E850055D09A /* TPCPreferencesUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E27E20EC4E870055D09A /* TPCPreferencesUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27520EC4E850055D09A /* TPCPreferencesUserDefaults.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E28120EC4E870055D09A /* TPCPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27620EC4E860055D09A /* TPCPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E28220EC4E870055D09A /* TPCPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27620EC4E860055D09A /* TPCPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E28520EC4E870055D09A /* TLOLocalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27720EC4E860055D09A /* TLOLocalization.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E28620EC4E870055D09A /* TLOLocalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E27720EC4E860055D09A /* TLOLocalization.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C06E2DD20EC4FF00055D09A /* Prompts.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2A720EC4FF00055D09A /* Prompts.strings */; };\n\t\t4C06E2DE20EC4FF00055D09A /* Prompts.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2A720EC4FF00055D09A /* Prompts.strings */; };\n\t\t4C06E2E120EC4FF00055D09A /* OffTheRecord.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2A920EC4FF00055D09A /* OffTheRecord.strings */; };\n\t\t4C06E2E220EC4FF00055D09A /* OffTheRecord.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2A920EC4FF00055D09A /* OffTheRecord.strings */; };\n\t\t4C06E2E520EC4FF00055D09A /* CommonErrors.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2AB20EC4FF00055D09A /* CommonErrors.strings */; };\n\t\t4C06E2E620EC4FF00055D09A /* CommonErrors.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2AB20EC4FF00055D09A /* CommonErrors.strings */; };\n\t\t4C06E2ED20EC4FF00055D09A /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2AF20EC4FF00055D09A /* BasicLanguage.strings */; };\n\t\t4C06E2EE20EC4FF00055D09A /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2AF20EC4FF00055D09A /* BasicLanguage.strings */; };\n\t\t4C06E2F120EC4FF00055D09A /* Accessibility.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B120EC4FF00055D09A /* Accessibility.strings */; };\n\t\t4C06E2F220EC4FF00055D09A /* Accessibility.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B120EC4FF00055D09A /* Accessibility.strings */; };\n\t\t4C06E2F520EC4FF00055D09A /* TDCChannelPropertiesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B320EC4FF00055D09A /* TDCChannelPropertiesSheet.strings */; };\n\t\t4C06E2F620EC4FF00055D09A /* TDCChannelPropertiesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B320EC4FF00055D09A /* TDCChannelPropertiesSheet.strings */; };\n\t\t4C06E2F920EC4FF00055D09A /* TDCChannelBanListSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B520EC4FF00055D09A /* TDCChannelBanListSheet.strings */; };\n\t\t4C06E2FA20EC4FF00055D09A /* TDCChannelBanListSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B520EC4FF00055D09A /* TDCChannelBanListSheet.strings */; };\n\t\t4C06E2FD20EC4FF00055D09A /* TDCPreferencesController.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B720EC4FF00055D09A /* TDCPreferencesController.strings */; };\n\t\t4C06E2FE20EC4FF00055D09A /* TDCPreferencesController.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B720EC4FF00055D09A /* TDCPreferencesController.strings */; };\n\t\t4C06E30120EC4FF00055D09A /* TDCFileTransferDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B920EC4FF00055D09A /* TDCFileTransferDialog.strings */; };\n\t\t4C06E30220EC4FF00055D09A /* TDCFileTransferDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2B920EC4FF00055D09A /* TDCFileTransferDialog.strings */; };\n\t\t4C06E30520EC4FF00055D09A /* TDCChannelInviteSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BB20EC4FF00055D09A /* TDCChannelInviteSheet.strings */; };\n\t\t4C06E30620EC4FF00055D09A /* TDCChannelInviteSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BB20EC4FF00055D09A /* TDCChannelInviteSheet.strings */; };\n\t\t4C06E30920EC4FF00055D09A /* TDCAboutDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BD20EC4FF00055D09A /* TDCAboutDialog.strings */; };\n\t\t4C06E30A20EC4FF00055D09A /* TDCAboutDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BD20EC4FF00055D09A /* TDCAboutDialog.strings */; };\n\t\t4C06E30D20EC4FF00055D09A /* TDCServerPropertiesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BF20EC4FF00055D09A /* TDCServerPropertiesSheet.strings */; };\n\t\t4C06E30E20EC4FF00055D09A /* TDCServerPropertiesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2BF20EC4FF00055D09A /* TDCServerPropertiesSheet.strings */; };\n\t\t4C06E31120EC4FF00055D09A /* IRC.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C120EC4FF00055D09A /* IRC.strings */; };\n\t\t4C06E31220EC4FF00055D09A /* IRC.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C120EC4FF00055D09A /* IRC.strings */; };\n\t\t4C06E31520EC4FF00055D09A /* TLOLicenseManager.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C320EC4FF00055D09A /* TLOLicenseManager.strings */; };\n\t\t4C06E31620EC4FF00055D09A /* TLOLicenseManager.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C320EC4FF00055D09A /* TLOLicenseManager.strings */; };\n\t\t4C06E31920EC4FF00055D09A /* TDCChannelModifyModesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C520EC4FF00055D09A /* TDCChannelModifyModesSheet.strings */; };\n\t\t4C06E31A20EC4FF00055D09A /* TDCChannelModifyModesSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C520EC4FF00055D09A /* TDCChannelModifyModesSheet.strings */; };\n\t\t4C06E31D20EC4FF00055D09A /* TVCMainWindow.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C720EC4FF00055D09A /* TVCMainWindow.strings */; };\n\t\t4C06E31E20EC4FF00055D09A /* TVCMainWindow.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C720EC4FF00055D09A /* TVCMainWindow.strings */; };\n\t\t4C06E32120EC4FF00055D09A /* Notifications.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C920EC4FF00055D09A /* Notifications.strings */; };\n\t\t4C06E32220EC4FF00055D09A /* Notifications.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2C920EC4FF00055D09A /* Notifications.strings */; };\n\t\t4C06E32920EC4FF00055D09A /* TVCNotificationConfigurationView.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2CD20EC4FF00055D09A /* TVCNotificationConfigurationView.strings */; };\n\t\t4C06E32A20EC4FF00055D09A /* TVCNotificationConfigurationView.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2CD20EC4FF00055D09A /* TVCNotificationConfigurationView.strings */; };\n\t\t4C06E32D20EC4FF00055D09A /* TDCServerEndpointListSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2CF20EC4FF00055D09A /* TDCServerEndpointListSheet.strings */; };\n\t\t4C06E32E20EC4FF00055D09A /* TDCServerEndpointListSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2CF20EC4FF00055D09A /* TDCServerEndpointListSheet.strings */; };\n\t\t4C06E33120EC4FF00055D09A /* TDCServerChannelListDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D120EC4FF00055D09A /* TDCServerChannelListDialog.strings */; };\n\t\t4C06E33220EC4FF00055D09A /* TDCServerChannelListDialog.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D120EC4FF00055D09A /* TDCServerChannelListDialog.strings */; };\n\t\t4C06E33520EC4FF00055D09A /* TDCChannelSpotlightController.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D320EC4FF00055D09A /* TDCChannelSpotlightController.strings */; };\n\t\t4C06E33620EC4FF00055D09A /* TDCChannelSpotlightController.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D320EC4FF00055D09A /* TDCChannelSpotlightController.strings */; };\n\t\t4C06E33920EC4FF00055D09A /* TDCAddressBookSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D520EC4FF00055D09A /* TDCAddressBookSheet.strings */; };\n\t\t4C06E33A20EC4FF00055D09A /* TDCAddressBookSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D520EC4FF00055D09A /* TDCAddressBookSheet.strings */; };\n\t\t4C06E33D20EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D720EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings */; };\n\t\t4C06E33E20EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D720EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings */; };\n\t\t4C06E34120EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D920EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings */; };\n\t\t4C06E34220EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C06E2D920EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings */; };\n\t\t4C06E3B120EC51380055D09A /* GCDAsyncSocketExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E36B20EC51370055D09A /* GCDAsyncSocketExtensions.h */; };\n\t\t4C06E3B220EC51380055D09A /* GCDAsyncSocketExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E36B20EC51370055D09A /* GCDAsyncSocketExtensions.h */; };\n\t\t4C06E3B520EC51380055D09A /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E36C20EC51370055D09A /* GCDAsyncSocket.h */; };\n\t\t4C06E3B620EC51380055D09A /* GCDAsyncSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E36C20EC51370055D09A /* GCDAsyncSocket.h */; };\n\t\t4C06E3C920EC51380055D09A /* ICLPayloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37220EC51370055D09A /* ICLPayloadInternal.h */; };\n\t\t4C06E3CA20EC51380055D09A /* ICLPayloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37220EC51370055D09A /* ICLPayloadInternal.h */; };\n\t\t4C06E3D520EC51380055D09A /* ICLPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37520EC51370055D09A /* ICLPayload.h */; };\n\t\t4C06E3D620EC51380055D09A /* ICLPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37520EC51370055D09A /* ICLPayload.h */; };\n\t\t4C06E3F520EC51380055D09A /* RCMConnectionManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37F20EC51370055D09A /* RCMConnectionManagerProtocol.h */; };\n\t\t4C06E3F620EC51380055D09A /* RCMConnectionManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E37F20EC51370055D09A /* RCMConnectionManagerProtocol.h */; };\n\t\t4C06E3F920EC51380055D09A /* ICLInlineContentProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E38020EC51370055D09A /* ICLInlineContentProtocol.h */; };\n\t\t4C06E3FA20EC51380055D09A /* ICLInlineContentProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E38020EC51370055D09A /* ICLInlineContentProtocol.h */; };\n\t\t4C06E3FD20EC51380055D09A /* HLSHistoricLogProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E38120EC51370055D09A /* HLSHistoricLogProtocol.h */; };\n\t\t4C06E3FE20EC51380055D09A /* HLSHistoricLogProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E38120EC51370055D09A /* HLSHistoricLogProtocol.h */; };\n\t\t4C06E41220EC52240055D09A /* TVCLogLineXPCPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E41020EC52240055D09A /* TVCLogLineXPCPrivate.h */; };\n\t\t4C06E41320EC52240055D09A /* TVCLogLineXPCPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E41020EC52240055D09A /* TVCLogLineXPCPrivate.h */; };\n\t\t4C06E41720EC52D60055D09A /* ICLPayloadLocalPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E41520EC52D50055D09A /* ICLPayloadLocalPrivate.h */; };\n\t\t4C06E41820EC52D60055D09A /* ICLPayloadLocalPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C06E41520EC52D50055D09A /* ICLPayloadLocalPrivate.h */; };\n\t\t4C06E42920EC53620055D09A /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCE521A18C7BE0600D49601 /* AudioToolbox.framework */; };\n\t\t4C06E42A20EC53620055D09A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCBC1580469E00846B64 /* Cocoa.framework */; };\n\t\t4C06E42B20EC53620055D09A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CA8EC621B63C2970087BF72 /* CoreServices.framework */; };\n\t\t4C06E42D20EC53620055D09A /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C10C00D1F37E59B0004C624 /* IOKit.framework */; };\n\t\t4C06E42F20EC53620055D09A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4D6B619837C1700FB5AF0 /* QuartzCore.framework */; };\n\t\t4C06E43020EC53620055D09A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC01580469E00846B64 /* Security.framework */; };\n\t\t4C06E43320EC53620055D09A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC11580469E00846B64 /* SystemConfiguration.framework */; };\n\t\t4C06E43420EC53620055D09A /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC21580469E00846B64 /* WebKit.framework */; };\n\t\t4C06E43520EC539E0055D09A /* AutoHyperlinks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */; };\n\t\t4C06E43620EC539E0055D09A /* AutoHyperlinks.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C06E43720EC539E0055D09A /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */; };\n\t\t4C06E43820EC539E0055D09A /* CocoaExtensions.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C06E43920EC539E0055D09A /* EncryptionKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */; };\n\t\t4C06E43A20EC539E0055D09A /* EncryptionKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C06E43B20EC539E0055D09A /* GRMustache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC4A7371F8A1404008FF15F /* GRMustache.framework */; };\n\t\t4C06E43C20EC539E0055D09A /* GRMustache.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC4A7371F8A1404008FF15F /* GRMustache.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C06E44120EC539E0055D09A /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C24DC751A93C9CE0098D1BE /* Sparkle.framework */; };\n\t\t4C06E44220EC539E0055D09A /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4C24DC751A93C9CE0098D1BE /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C06E47320EC541C0055D09A /* AutoHyperlinks.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C06E47520EC541C0055D09A /* CocoaExtensions.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C06E47720EC541C0055D09A /* EncryptionKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C06E47920EC541C0055D09A /* GRMustache.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC4A7371F8A1404008FF15F /* GRMustache.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C06E47F20EC541C0055D09A /* Sparkle.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4C24DC751A93C9CE0098D1BE /* Sparkle.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C06E48120EC54260055D09A /* AutoHyperlinks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */; };\n\t\t4C06E48220EC54260055D09A /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */; };\n\t\t4C06E48320EC54260055D09A /* EncryptionKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */; };\n\t\t4C06E48420EC54260055D09A /* GRMustache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC4A7371F8A1404008FF15F /* GRMustache.framework */; };\n\t\t4C06E48720EC54260055D09A /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C24DC751A93C9CE0098D1BE /* Sparkle.framework */; };\n\t\t4C06E48820EC542C0055D09A /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCE521A18C7BE0600D49601 /* AudioToolbox.framework */; };\n\t\t4C06E48920EC542C0055D09A /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCBC1580469E00846B64 /* Cocoa.framework */; };\n\t\t4C06E48A20EC542C0055D09A /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CA8EC621B63C2970087BF72 /* CoreServices.framework */; };\n\t\t4C06E48C20EC542C0055D09A /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C10C00D1F37E59B0004C624 /* IOKit.framework */; };\n\t\t4C06E48E20EC542C0055D09A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4D6B619837C1700FB5AF0 /* QuartzCore.framework */; };\n\t\t4C06E48F20EC542C0055D09A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC01580469E00846B64 /* Security.framework */; };\n\t\t4C06E49220EC542C0055D09A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC11580469E00846B64 /* SystemConfiguration.framework */; };\n\t\t4C06E49320EC542C0055D09A /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C46CCC21580469E00846B64 /* WebKit.framework */; };\n\t\t4C06E57F20EC553A0055D09A /* TXAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529E20EB673E00448776 /* TXAppearance.m */; };\n\t\t4C06E58020EC553A0055D09A /* TXApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529C20EB673E00448776 /* TXApplication.m */; };\n\t\t4C06E58120EC553A0055D09A /* TXGlobalModels.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529B20EB673E00448776 /* TXGlobalModels.m */; };\n\t\t4C06E58220EC553A0055D09A /* TXMasterController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529F20EB673E00448776 /* TXMasterController.m */; };\n\t\t4C06E58320EC553A0055D09A /* TXMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A120EB673E00448776 /* TXMenuController.m */; };\n\t\t4C06E58420EC553A0055D09A /* TXSharedApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529D20EB673E00448776 /* TXSharedApplication.m */; };\n\t\t4C06E58520EC553A0055D09A /* TXWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A020EB673E00448776 /* TXWindowController.m */; };\n\t\t4C06E58A20EC553A0055D09A /* TDCChannelSpotlightControls.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526B20EB673E00448776 /* TDCChannelSpotlightControls.m */; };\n\t\t4C06E58B20EC553A0055D09A /* TDCChannelSpotlightSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526C20EB673E00448776 /* TDCChannelSpotlightSearchResult.m */; };\n\t\t4C06E58C20EC553A0055D09A /* TDCChannelSpotlightController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526D20EB673E00448776 /* TDCChannelSpotlightController.m */; };\n\t\t4C06E58D20EC553A0055D09A /* TDCChannelSpotlightAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526E20EB673E00448776 /* TDCChannelSpotlightAppearance.m */; };\n\t\t4C06E58E20EC553A0055D09A /* TDCChannelSpotlightSearchResultsTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526F20EB673E00448776 /* TDCChannelSpotlightSearchResultsTable.m */; };\n\t\t4C06E58F20EC553A0055D09A /* TDCFileTransferDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529120EB673E00448776 /* TDCFileTransferDialog.m */; };\n\t\t4C06E59020EC553A0055D09A /* TDCFileTransferDialogTransferController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529220EB673E00448776 /* TDCFileTransferDialogTransferController.m */; };\n\t\t4C06E59120EC553A0055D09A /* TDCFileTransferDialogTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529320EB673E00448776 /* TDCFileTransferDialogTableCell.m */; };\n\t\t4C06E59220EC553A0055D09A /* TDCLicenseUpgradeDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527420EB673E00448776 /* TDCLicenseUpgradeDialog.m */; };\n\t\t4C06E59320EC553A0055D09A /* TDCLicenseUpgradeEligibilitySheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527520EB673E00448776 /* TDCLicenseUpgradeEligibilitySheet.m */; };\n\t\t4C06E59420EC553A0055D09A /* TDCLicenseManagerMigrateAppStoreSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527620EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheet.m */; };\n\t\t4C06E59520EC553A0055D09A /* TDCLicenseUpgradeCommonActions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527720EB673E00448776 /* TDCLicenseUpgradeCommonActions.m */; };\n\t\t4C06E59620EC553A0055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527820EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheet.m */; };\n\t\t4C06E59720EC553A0055D09A /* TDCLicenseUpgradeActivateSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527920EB673E00448776 /* TDCLicenseUpgradeActivateSheet.m */; };\n\t\t4C06E59820EC553A0055D09A /* TDCLicenseManagerDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527A20EB673E00448776 /* TDCLicenseManagerDialog.m */; };\n\t\t4C06E59D20EC553A0055D09A /* TDCPreferencesNotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526820EB673E00448776 /* TDCPreferencesNotificationConfiguration.m */; };\n\t\t4C06E59E20EC553A0055D09A /* TDCPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526920EB673E00448776 /* TDCPreferencesController.m */; };\n\t\t4C06E59F20EC553A0055D09A /* TDCServerEndpointListSheetTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528E20EB673E00448776 /* TDCServerEndpointListSheetTable.m */; };\n\t\t4C06E5A020EC553A0055D09A /* TDCServerEndpointListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528F20EB673E00448776 /* TDCServerEndpointListSheet.m */; };\n\t\t4C06E5A120EC553A0055D09A /* TDCAboutDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528120EB673E00448776 /* TDCAboutDialog.m */; };\n\t\t4C06E5A220EC553A0055D09A /* TDCAddressBookSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527020EB673E00448776 /* TDCAddressBookSheet.m */; };\n\t\t4C06E5A320EC553A0055D09A /* TDCAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528020EB673E00448776 /* TDCAlert.m */; };\n\t\t4C06E5A420EC553A0055D09A /* TDCChannelBanListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528220EB673E00448776 /* TDCChannelBanListSheet.m */; };\n\t\t4C06E5A520EC553A0055D09A /* TDCChannelInviteSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526320EB673E00448776 /* TDCChannelInviteSheet.m */; };\n\t\t4C06E5A620EC553A0055D09A /* TDCChannelModifyModesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526620EB673E00448776 /* TDCChannelModifyModesSheet.m */; };\n\t\t4C06E5A720EC553A0055D09A /* TDCChannelModifyTopicSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528920EB673E00448776 /* TDCChannelModifyTopicSheet.m */; };\n\t\t4C06E5A820EC553A0055D09A /* TDCChannelPropertiesNotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527120EB673E00448776 /* TDCChannelPropertiesNotificationConfiguration.m */; };\n\t\t4C06E5A920EC553A0055D09A /* TDCChannelPropertiesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526420EB673E00448776 /* TDCChannelPropertiesSheet.m */; };\n\t\t4C06E5AA20EC553A0055D09A /* TDCHighlightEntrySheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528320EB673E00448776 /* TDCHighlightEntrySheet.m */; };\n\t\t4C06E5AB20EC553A0055D09A /* TDCInputPrompt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528520EB673E00448776 /* TDCInputPrompt.m */; };\n\t\t4C06E5AC20EC553A0055D09A /* TDCNicknameColorSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529420EB673E00448776 /* TDCNicknameColorSheet.m */; };\n\t\t4C06E5AD20EC553A0055D09A /* TDCProgressIndicatorSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528820EB673E00448776 /* TDCProgressIndicatorSheet.m */; };\n\t\t4C06E5AE20EC553A0055D09A /* TDCServerChangeNicknameSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528C20EB673E00448776 /* TDCServerChangeNicknameSheet.m */; };\n\t\t4C06E5AF20EC553A0055D09A /* TDCServerChannelListDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528620EB673E00448776 /* TDCServerChannelListDialog.m */; };\n\t\t4C06E5B020EC553A0055D09A /* TDCServerHighlightListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528720EB673E00448776 /* TDCServerHighlightListSheet.m */; };\n\t\t4C06E5B120EC553A0055D09A /* TDCServerPropertiesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526520EB673E00448776 /* TDCServerPropertiesSheet.m */; };\n\t\t4C06E5B220EC553A0055D09A /* TDCSheetBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528A20EB673E00448776 /* TDCSheetBase.m */; };\n\t\t4C06E5B320EC553A0055D09A /* TDCWelcomeSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528B20EB673E00448776 /* TDCWelcomeSheet.m */; };\n\t\t4C06E5B420EC553A0055D09A /* TDCWindowBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528420EB673E00448776 /* TDCWindowBase.m */; };\n\t\t4C06E5B520EC553A0055D09A /* NSColorHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E520EB673E00448776 /* NSColorHelper.m */; };\n\t\t4C06E5B620EC553A0055D09A /* NSObjectHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E2A120EC4FA50055D09A /* NSObjectHelper.m */; };\n\t\t4C06E5B720EC553A0055D09A /* NSStringHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E720EB673E00448776 /* NSStringHelper.m */; };\n\t\t4C06E5B820EC553A0055D09A /* NSTableViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E820EB673E00448776 /* NSTableViewHelper.m */; };\n\t\t4C06E5B920EC553A0055D09A /* NSViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E620EB673E00448776 /* NSViewHelper.m */; };\n\t\t4C06E5BA20EC553A0055D09A /* TXAppearanceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E920EB673E00448776 /* TXAppearanceHelper.m */; };\n\t\t4C06E5BB20EC553A0055D09A /* WebScriptObjectHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DC20EB673E00448776 /* WebScriptObjectHelper.m */; };\n\t\t4C06E5BC20EC553A0055D09A /* GTMEncodeHTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DE20EB673E00448776 /* GTMEncodeHTML.m */; };\n\t\t4C06E5BD20EC553A0055D09A /* THOPluginDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E120EB673E00448776 /* THOPluginDispatcher.m */; };\n\t\t4C06E5BE20EC553A0055D09A /* THOPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E220EB673E00448776 /* THOPluginManager.m */; };\n\t\t4C06E5BF20EC553A0055D09A /* THOPluginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E320EB673E00448776 /* THOPluginItem.m */; };\n\t\t4C06E5C020EC553A0055D09A /* THOUnicodeHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DF20EB673E00448776 /* THOUnicodeHelper.m */; };\n\t\t4C06E5C120EC553A0055D09A /* IRCAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512320EB673E00448776 /* IRCAddressBook.m */; };\n\t\t4C06E5C220EC553A0055D09A /* IRCAddressBookMatchCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512B20EB673E00448776 /* IRCAddressBookMatchCache.m */; };\n\t\t4C06E5C320EC553A0055D09A /* IRCAddressBookUserTracking.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513E20EB673E00448776 /* IRCAddressBookUserTracking.m */; };\n\t\t4C06E5C420EC553A0055D09A /* IRCChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512820EB673E00448776 /* IRCChannel.m */; };\n\t\t4C06E5C520EC553A0055D09A /* IRCChannelConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512420EB673E00448776 /* IRCChannelConfig.m */; };\n\t\t4C06E5C620EC553A0055D09A /* IRCChannelMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514020EB673E00448776 /* IRCChannelMode.m */; };\n\t\t4C06E5C720EC553A0055D09A /* IRCChannelUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513D20EB673E00448776 /* IRCChannelUser.m */; };\n\t\t4C06E5C820EC553A0055D09A /* IRCClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513B20EB673E00448776 /* IRCClient.m */; };\n\t\t4C06E5C920EC553A0055D09A /* IRCClientConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513C20EB673E00448776 /* IRCClientConfig.m */; };\n\t\t4C06E5CA20EC553A0055D09A /* IRCClientRequestedCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513820EB673E00448776 /* IRCClientRequestedCommands.m */; };\n\t\t4C06E5CB20EC553A0055D09A /* IRCCommandIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513720EB673E00448776 /* IRCCommandIndex.m */; };\n\t\t4C06E5CC20EC553A0055D09A /* IRCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512E20EB673E00448776 /* IRCConnection.m */; };\n\t\t4C06E5CD20EC553A0055D09A /* IRCConnectionConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29C20EC4F880055D09A /* IRCConnectionConfig.m */; };\n\t\t4C06E5CE20EC553A0055D09A /* IRCExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513120EB673E00448776 /* IRCExtras.m */; };\n\t\t4C06E5CF20EC553A0055D09A /* IRCHighlightLogEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512620EB673E00448776 /* IRCHighlightLogEntry.m */; };\n\t\t4C06E5D020EC553A0055D09A /* IRCHighlightMatchCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512A20EB673E00448776 /* IRCHighlightMatchCondition.m */; };\n\t\t4C06E5D120EC553A0055D09A /* IRCISupportInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514120EB673E00448776 /* IRCISupportInfo.m */; };\n\t\t4C06E5D220EC553A0055D09A /* IRCMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512D20EB673E00448776 /* IRCMessage.m */; };\n\t\t4C06E5D320EC553A0055D09A /* IRCMessageBatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513F20EB673E00448776 /* IRCMessageBatch.m */; };\n\t\t4C06E5D420EC553A0055D09A /* IRCModeInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513020EB673E00448776 /* IRCModeInfo.m */; };\n\t\t4C06E5D520EC553A0055D09A /* IRCNetworkList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513920EB673E00448776 /* IRCNetworkList.m */; };\n\t\t4C06E5D620EC553A0055D09A /* IRCPrefix.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512520EB673E00448776 /* IRCPrefix.m */; };\n\t\t4C06E5D720EC553A0055D09A /* IRCSendingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512C20EB673E00448776 /* IRCSendingMessage.m */; };\n\t\t4C06E5D820EC553A0055D09A /* IRCServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512920EB673E00448776 /* IRCServer.m */; };\n\t\t4C06E5D920EC553A0055D09A /* IRCTimerCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512F20EB673E00448776 /* IRCTimerCommand.m */; };\n\t\t4C06E5DA20EC553A0055D09A /* IRCTreeItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514220EB673E00448776 /* IRCTreeItem.m */; };\n\t\t4C06E5DB20EC553A0055D09A /* IRCWorld.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513A20EB673E00448776 /* IRCWorld.m */; };\n\t\t4C06E5DD20EC553A0055D09A /* IRCUserRelations.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513320EB673E00448776 /* IRCUserRelations.m */; };\n\t\t4C06E5DE20EC553A0055D09A /* IRCUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513420EB673E00448776 /* IRCUser.m */; };\n\t\t4C06E5DF20EC553A0055D09A /* IRCUserNicknameColorStyleGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513520EB673E00448776 /* IRCUserNicknameColorStyleGenerator.m */; };\n\t\t4C06E5E020EC553A0055D09A /* IRCUserPersistentStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513620EB673E00448776 /* IRCUserPersistentStore.m */; };\n\t\t4C06E5E120EC553A0055D09A /* IRCColorFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515F20EB673E00448776 /* IRCColorFormat.m */; };\n\t\t4C06E5E220EC553A0055D09A /* OELReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514820EB673E00448776 /* OELReachability.m */; };\n\t\t4C06E5E320EC553A0055D09A /* TLOLicenseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514E20EB673E00448776 /* TLOLicenseManager.m */; };\n\t\t4C06E5E420EC553A0055D09A /* TLOLicenseManagerDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515020EB673E00448776 /* TLOLicenseManagerDownloader.m */; };\n\t\t4C06E5E520EC553A0055D09A /* TLOLicenseManagerLastGen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514F20EB673E00448776 /* TLOLicenseManagerLastGen.m */; };\n\t\t4C06E5E720EC553A0055D09A /* TLOEncryptionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515320EB673E00448776 /* TLOEncryptionManager.m */; };\n\t\t4C06E5E820EC553A0055D09A /* TLOFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515B20EB673E00448776 /* TLOFileLogger.m */; };\n\t\t4C06E5E920EC553A0055D09A /* TLONotificationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514920EB673E00448776 /* TLONotificationController.m */; };\n\t\t4C06E5EA20EC553A0055D09A /* TLOInputHistory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515420EB673E00448776 /* TLOInputHistory.m */; };\n\t\t4C06E5EB20EC553A0055D09A /* TLOInternetAddressLookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515620EB673E00448776 /* TLOInternetAddressLookup.m */; };\n\t\t4C06E5EC20EC553A0055D09A /* TLOKeyEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514B20EB673E00448776 /* TLOKeyEventHandler.m */; };\n\t\t4C06E5ED20EC553A0055D09A /* TLOLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29220EC4F570055D09A /* TLOLocalization.m */; };\n\t\t4C06E5EE20EC553A0055D09A /* TLONicknameCompletionStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515C20EB673E00448776 /* TLONicknameCompletionStatus.m */; };\n\t\t4C06E5EF20EC553A0055D09A /* TLONotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515D20EB673E00448776 /* TLONotificationConfiguration.m */; };\n\t\t4C06E5F120EC553A0055D09A /* TLOSoundPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515820EB673E00448776 /* TLOSoundPlayer.m */; };\n\t\t4C06E5F220EC553A0055D09A /* TLOSpeechSynthesizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515720EB673E00448776 /* TLOSpeechSynthesizer.m */; };\n\t\t4C06E5F320EC553A0055D09A /* TLOSpokenNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515A20EB673E00448776 /* TLOSpokenNotification.m */; };\n\t\t4C06E5F420EC553A0055D09A /* TLOTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29320EC4F570055D09A /* TLOTimer.m */; };\n\t\t4C06E5F520EC553A0055D09A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514420EB673E00448776 /* main.m */; };\n\t\t4C06E5F820EC553A0055D09A /* TPCThemeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511F20EB673E00448776 /* TPCThemeController.m */; };\n\t\t4C06E5F920EC553A0055D09A /* TPCTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512020EB673E00448776 /* TPCTheme.m */; };\n\t\t4C06E5FA20EC553A0055D09A /* TPCApplicationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511420EB673E00448776 /* TPCApplicationInfo.m */; };\n\t\t4C06E5FB20EC553A0055D09A /* TPCPathInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511A20EB673E00448776 /* TPCPathInfo.m */; };\n\t\t4C06E5FC20EC553A0055D09A /* TPCPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E28820EC4F000055D09A /* TPCPreferences.m */; };\n\t\t4C06E5FD20EC553A0055D09A /* TPCPreferencesLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511520EB673E00448776 /* TPCPreferencesLocal.m */; };\n\t\t4C06E5FE20EC553A0055D09A /* TPCPreferencesImportExport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511620EB673E00448776 /* TPCPreferencesImportExport.m */; };\n\t\t4C06E5FF20EC553A0055D09A /* TPCPreferencesReload.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512120EB673E00448776 /* TPCPreferencesReload.m */; };\n\t\t4C06E60020EC553A0055D09A /* TPCPreferencesUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E28920EC4F000055D09A /* TPCPreferencesUserDefaults.m */; };\n\t\t4C06E60120EC553A0055D09A /* TPCPreferencesUserDefaultsLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511920EB673E00448776 /* TPCPreferencesUserDefaultsLocal.m */; };\n\t\t4C06E60320EC553A0055D09A /* TPCResourceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511820EB673E00448776 /* TPCResourceManager.m */; };\n\t\t4C06E60420EC553A0055D09A /* ICLPayloadLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E34E20EC50D40055D09A /* ICLPayloadLocal.m */; };\n\t\t4C06E60620EC553A0055D09A /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E36320EC51370055D09A /* GCDAsyncSocket.m */; settings = {COMPILER_FLAGS = \"-Wno-implicit-retain-self\"; }; };\n\t\t4C06E60720EC553A0055D09A /* GCDAsyncSocketExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E36520EC51370055D09A /* GCDAsyncSocketExtensions.m */; };\n\t\t4C06E60920EC553A0055D09A /* ICLPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E38B20EC51370055D09A /* ICLPayload.m */; };\n\t\t4C06E60A20EC553A0055D09A /* TVCLogLineXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E38620EC51370055D09A /* TVCLogLineXPC.m */; };\n\t\t4C06E60B20EC553A0055D09A /* TVCChannelSelectionOutlineCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AE20EB673E00448776 /* TVCChannelSelectionOutlineCellView.m */; };\n\t\t4C06E60C20EC553A0055D09A /* TVCChannelSelectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AF20EB673E00448776 /* TVCChannelSelectionViewController.m */; };\n\t\t4C06E60D20EC553A0055D09A /* TVCLogControllerHistoricLogFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C220EB673E00448776 /* TVCLogControllerHistoricLogFile.m */; };\n\t\t4C06E60E20EC553A0055D09A /* TVCLogControllerInlineMediaService.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C120EB673E00448776 /* TVCLogControllerInlineMediaService.m */; };\n\t\t4C06E60F20EC553A0055D09A /* TVCLogControllerOperationQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C320EB673E00448776 /* TVCLogControllerOperationQueue.m */; };\n\t\t4C06E61020EC553A0055D09A /* TVCLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BA20EB673E00448776 /* TVCLogController.m */; };\n\t\t4C06E61120EC553A0055D09A /* TVCLogLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BE20EB673E00448776 /* TVCLogLine.m */; };\n\t\t4C06E61220EC553A0055D09A /* TVCLogPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B820EB673E00448776 /* TVCLogPolicy.m */; };\n\t\t4C06E61320EC553A0055D09A /* TVCLogRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BB20EB673E00448776 /* TVCLogRenderer.m */; };\n\t\t4C06E61420EC553A0055D09A /* TVCLogScriptEventSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B720EB673E00448776 /* TVCLogScriptEventSink.m */; };\n\t\t4C06E61520EC553A0055D09A /* TVCLogView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BD20EB673E00448776 /* TVCLogView.m */; };\n\t\t4C06E61620EC553A0055D09A /* TVCLogViewInternalWK1.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BC20EB673E00448776 /* TVCLogViewInternalWK1.m */; };\n\t\t4C06E61720EC553A0055D09A /* TVCLogViewInternalWK2.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B920EB673E00448776 /* TVCLogViewInternalWK2.m */; };\n\t\t4C06E61820EC553A0055D09A /* TVCWK1AutoScroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BF20EB673E00448776 /* TVCWK1AutoScroller.m */; };\n\t\t4C06E61920EC553A0055D09A /* TVCAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C920EB673E00448776 /* TVCAlert.m */; };\n\t\t4C06E61A20EC553A0055D09A /* TVCErrorMessagePopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C720EB673E00448776 /* TVCErrorMessagePopover.m */; };\n\t\t4C06E61B20EC553A0055D09A /* TVCErrorMessagePopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C820EB673E00448776 /* TVCErrorMessagePopoverController.m */; };\n\t\t4C06E61C20EC553A0055D09A /* TVCAutoExpandingTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AA20EB673E00448776 /* TVCAutoExpandingTextField.m */; };\n\t\t4C06E61D20EC553A0055D09A /* TVCAutoExpandingTokenField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A520EB673E00448776 /* TVCAutoExpandingTokenField.m */; };\n\t\t4C06E61E20EC553A0055D09A /* TVCTextFormatterMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A620EB673E00448776 /* TVCTextFormatterMenu.m */; };\n\t\t4C06E61F20EC553A0055D09A /* TVCTextViewWithIRCFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A720EB673E00448776 /* TVCTextViewWithIRCFormatter.m */; };\n\t\t4C06E62020EC553A0055D09A /* TVCValidatedComboBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A820EB673E00448776 /* TVCValidatedComboBox.m */; };\n\t\t4C06E62120EC553A0055D09A /* TVCValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A920EB673E00448776 /* TVCValidatedTextField.m */; };\n\t\t4C06E62220EC553A0055D09A /* TVCMainWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D120EB673E00448776 /* TVCMainWindow.m */; };\n\t\t4C06E62320EC553A0055D09A /* TVCMainWindowAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D520EB673E00448776 /* TVCMainWindowAppearance.m */; };\n\t\t4C06E62420EC553A0055D09A /* TVCMainWindowChannelView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D820EB673E00448776 /* TVCMainWindowChannelView.m */; };\n\t\t4C06E62520EC553A0055D09A /* TVCMainWindowLoadingScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D220EB673E00448776 /* TVCMainWindowLoadingScreen.m */; };\n\t\t4C06E62620EC553A0055D09A /* TVCMainWindowSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D420EB673E00448776 /* TVCMainWindowSegmentedControl.m */; };\n\t\t4C06E62820EC553A0055D09A /* TVCMainWindowSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D320EB673E00448776 /* TVCMainWindowSplitView.m */; };\n\t\t4C06E62920EC553A0055D09A /* TVCMainWindowTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D620EB673E00448776 /* TVCMainWindowTextView.m */; };\n\t\t4C06E62A20EC553A0055D09A /* TVCMainWindowTextViewAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CF20EB673E00448776 /* TVCMainWindowTextViewAppearance.m */; };\n\t\t4C06E62B20EC553A0055D09A /* TVCMainWindowTitlebarAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D720EB673E00448776 /* TVCMainWindowTitlebarAccessoryView.m */; };\n\t\t4C06E62C20EC553A0055D09A /* TVCNotificationConfigurationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AC20EB673E00448776 /* TVCNotificationConfigurationViewController.m */; };\n\t\t4C06E62D20EC553A0055D09A /* TVCServerList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CC20EB673E00448776 /* TVCServerList.m */; };\n\t\t4C06E62E20EC553A0055D09A /* TVCServerListAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CD20EB673E00448776 /* TVCServerListAppearance.m */; };\n\t\t4C06E62F20EC553A0055D09A /* TVCServerListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CB20EB673E00448776 /* TVCServerListCell.m */; };\n\t\t4C06E63020EC553A0055D09A /* TVCMemberList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B320EB673E00448776 /* TVCMemberList.m */; };\n\t\t4C06E63120EC553A0055D09A /* TVCMemberListAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B220EB673E00448776 /* TVCMemberListAppearance.m */; };\n\t\t4C06E63220EC553A0055D09A /* TVCMemberListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B120EB673E00448776 /* TVCMemberListCell.m */; };\n\t\t4C06E63320EC553A0055D09A /* TVCMemberListUserInfoPopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B420EB673E00448776 /* TVCMemberListUserInfoPopover.m */; };\n\t\t4C06E63420EC553A0055D09A /* TVCAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C420EB673E00448776 /* TVCAppearance.m */; };\n\t\t4C06E63520EC553A0055D09A /* TVCBasicTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A320EB673E00448776 /* TVCBasicTableView.m */; };\n\t\t4C06E63620EC553A0055D09A /* TVCContentNavigationOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B520EB673E00448776 /* TVCContentNavigationOutlineView.m */; };\n\t\t4C06E63720EC553A0055D09A /* TVCDockIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C520EB673E00448776 /* TVCDockIcon.m */; };\n\t\t4C06E63820EC55B90055D09A /* TXAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529E20EB673E00448776 /* TXAppearance.m */; };\n\t\t4C06E63920EC55B90055D09A /* TXApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529C20EB673E00448776 /* TXApplication.m */; };\n\t\t4C06E63A20EC55B90055D09A /* TXGlobalModels.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529B20EB673E00448776 /* TXGlobalModels.m */; };\n\t\t4C06E63B20EC55B90055D09A /* TXMasterController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529F20EB673E00448776 /* TXMasterController.m */; };\n\t\t4C06E63C20EC55B90055D09A /* TXMenuController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A120EB673E00448776 /* TXMenuController.m */; };\n\t\t4C06E63D20EC55B90055D09A /* TXSharedApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529D20EB673E00448776 /* TXSharedApplication.m */; };\n\t\t4C06E63E20EC55B90055D09A /* TXWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A020EB673E00448776 /* TXWindowController.m */; };\n\t\t4C06E64320EC55B90055D09A /* TDCChannelSpotlightControls.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526B20EB673E00448776 /* TDCChannelSpotlightControls.m */; };\n\t\t4C06E64420EC55B90055D09A /* TDCChannelSpotlightSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526C20EB673E00448776 /* TDCChannelSpotlightSearchResult.m */; };\n\t\t4C06E64520EC55B90055D09A /* TDCChannelSpotlightController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526D20EB673E00448776 /* TDCChannelSpotlightController.m */; };\n\t\t4C06E64620EC55B90055D09A /* TDCChannelSpotlightAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526E20EB673E00448776 /* TDCChannelSpotlightAppearance.m */; };\n\t\t4C06E64720EC55B90055D09A /* TDCChannelSpotlightSearchResultsTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526F20EB673E00448776 /* TDCChannelSpotlightSearchResultsTable.m */; };\n\t\t4C06E64820EC55B90055D09A /* TDCFileTransferDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529120EB673E00448776 /* TDCFileTransferDialog.m */; };\n\t\t4C06E64920EC55B90055D09A /* TDCFileTransferDialogTransferController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529220EB673E00448776 /* TDCFileTransferDialogTransferController.m */; };\n\t\t4C06E64A20EC55B90055D09A /* TDCFileTransferDialogTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529320EB673E00448776 /* TDCFileTransferDialogTableCell.m */; };\n\t\t4C06E64B20EC55B90055D09A /* TDCLicenseUpgradeDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527420EB673E00448776 /* TDCLicenseUpgradeDialog.m */; };\n\t\t4C06E64C20EC55B90055D09A /* TDCLicenseUpgradeEligibilitySheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527520EB673E00448776 /* TDCLicenseUpgradeEligibilitySheet.m */; };\n\t\t4C06E64D20EC55B90055D09A /* TDCLicenseManagerMigrateAppStoreSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527620EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheet.m */; };\n\t\t4C06E64E20EC55B90055D09A /* TDCLicenseUpgradeCommonActions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527720EB673E00448776 /* TDCLicenseUpgradeCommonActions.m */; };\n\t\t4C06E64F20EC55B90055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527820EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheet.m */; };\n\t\t4C06E65020EC55B90055D09A /* TDCLicenseUpgradeActivateSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527920EB673E00448776 /* TDCLicenseUpgradeActivateSheet.m */; };\n\t\t4C06E65120EC55B90055D09A /* TDCLicenseManagerDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527A20EB673E00448776 /* TDCLicenseManagerDialog.m */; };\n\t\t4C06E65620EC55B90055D09A /* TDCPreferencesNotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526820EB673E00448776 /* TDCPreferencesNotificationConfiguration.m */; };\n\t\t4C06E65720EC55B90055D09A /* TDCPreferencesController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526920EB673E00448776 /* TDCPreferencesController.m */; };\n\t\t4C06E65820EC55B90055D09A /* TDCServerEndpointListSheetTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528E20EB673E00448776 /* TDCServerEndpointListSheetTable.m */; };\n\t\t4C06E65920EC55B90055D09A /* TDCServerEndpointListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528F20EB673E00448776 /* TDCServerEndpointListSheet.m */; };\n\t\t4C06E65A20EC55B90055D09A /* TDCAboutDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528120EB673E00448776 /* TDCAboutDialog.m */; };\n\t\t4C06E65B20EC55B90055D09A /* TDCAddressBookSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527020EB673E00448776 /* TDCAddressBookSheet.m */; };\n\t\t4C06E65C20EC55B90055D09A /* TDCAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528020EB673E00448776 /* TDCAlert.m */; };\n\t\t4C06E65D20EC55B90055D09A /* TDCChannelBanListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528220EB673E00448776 /* TDCChannelBanListSheet.m */; };\n\t\t4C06E65E20EC55B90055D09A /* TDCChannelInviteSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526320EB673E00448776 /* TDCChannelInviteSheet.m */; };\n\t\t4C06E65F20EC55B90055D09A /* TDCChannelModifyModesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526620EB673E00448776 /* TDCChannelModifyModesSheet.m */; };\n\t\t4C06E66020EC55B90055D09A /* TDCChannelModifyTopicSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528920EB673E00448776 /* TDCChannelModifyTopicSheet.m */; };\n\t\t4C06E66120EC55B90055D09A /* TDCChannelPropertiesNotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31527120EB673E00448776 /* TDCChannelPropertiesNotificationConfiguration.m */; };\n\t\t4C06E66220EC55B90055D09A /* TDCChannelPropertiesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526420EB673E00448776 /* TDCChannelPropertiesSheet.m */; };\n\t\t4C06E66320EC55B90055D09A /* TDCHighlightEntrySheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528320EB673E00448776 /* TDCHighlightEntrySheet.m */; };\n\t\t4C06E66420EC55B90055D09A /* TDCInputPrompt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528520EB673E00448776 /* TDCInputPrompt.m */; };\n\t\t4C06E66520EC55B90055D09A /* TDCNicknameColorSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31529420EB673E00448776 /* TDCNicknameColorSheet.m */; };\n\t\t4C06E66620EC55B90055D09A /* TDCProgressIndicatorSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528820EB673E00448776 /* TDCProgressIndicatorSheet.m */; };\n\t\t4C06E66720EC55B90055D09A /* TDCServerChangeNicknameSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528C20EB673E00448776 /* TDCServerChangeNicknameSheet.m */; };\n\t\t4C06E66820EC55B90055D09A /* TDCServerChannelListDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528620EB673E00448776 /* TDCServerChannelListDialog.m */; };\n\t\t4C06E66920EC55B90055D09A /* TDCServerHighlightListSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528720EB673E00448776 /* TDCServerHighlightListSheet.m */; };\n\t\t4C06E66A20EC55B90055D09A /* TDCServerPropertiesSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31526520EB673E00448776 /* TDCServerPropertiesSheet.m */; };\n\t\t4C06E66B20EC55B90055D09A /* TDCSheetBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528A20EB673E00448776 /* TDCSheetBase.m */; };\n\t\t4C06E66C20EC55B90055D09A /* TDCWelcomeSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528B20EB673E00448776 /* TDCWelcomeSheet.m */; };\n\t\t4C06E66D20EC55B90055D09A /* TDCWindowBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31528420EB673E00448776 /* TDCWindowBase.m */; };\n\t\t4C06E66E20EC55B90055D09A /* NSColorHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E520EB673E00448776 /* NSColorHelper.m */; };\n\t\t4C06E66F20EC55B90055D09A /* NSObjectHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E2A120EC4FA50055D09A /* NSObjectHelper.m */; };\n\t\t4C06E67020EC55B90055D09A /* NSStringHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E720EB673E00448776 /* NSStringHelper.m */; };\n\t\t4C06E67120EC55B90055D09A /* NSTableViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E820EB673E00448776 /* NSTableViewHelper.m */; };\n\t\t4C06E67220EC55B90055D09A /* NSViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E620EB673E00448776 /* NSViewHelper.m */; };\n\t\t4C06E67320EC55B90055D09A /* TXAppearanceHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E920EB673E00448776 /* TXAppearanceHelper.m */; };\n\t\t4C06E67420EC55B90055D09A /* WebScriptObjectHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DC20EB673E00448776 /* WebScriptObjectHelper.m */; };\n\t\t4C06E67520EC55B90055D09A /* GTMEncodeHTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DE20EB673E00448776 /* GTMEncodeHTML.m */; };\n\t\t4C06E67620EC55B90055D09A /* THOPluginDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E120EB673E00448776 /* THOPluginDispatcher.m */; };\n\t\t4C06E67720EC55B90055D09A /* THOPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E220EB673E00448776 /* THOPluginManager.m */; };\n\t\t4C06E67820EC55B90055D09A /* THOPluginItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152E320EB673E00448776 /* THOPluginItem.m */; };\n\t\t4C06E67920EC55B90055D09A /* THOUnicodeHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152DF20EB673E00448776 /* THOUnicodeHelper.m */; };\n\t\t4C06E67A20EC55B90055D09A /* IRCAddressBook.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512320EB673E00448776 /* IRCAddressBook.m */; };\n\t\t4C06E67B20EC55B90055D09A /* IRCAddressBookMatchCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512B20EB673E00448776 /* IRCAddressBookMatchCache.m */; };\n\t\t4C06E67C20EC55B90055D09A /* IRCAddressBookUserTracking.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513E20EB673E00448776 /* IRCAddressBookUserTracking.m */; };\n\t\t4C06E67D20EC55B90055D09A /* IRCChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512820EB673E00448776 /* IRCChannel.m */; };\n\t\t4C06E67E20EC55B90055D09A /* IRCChannelConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512420EB673E00448776 /* IRCChannelConfig.m */; };\n\t\t4C06E67F20EC55B90055D09A /* IRCChannelMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514020EB673E00448776 /* IRCChannelMode.m */; };\n\t\t4C06E68020EC55B90055D09A /* IRCChannelUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513D20EB673E00448776 /* IRCChannelUser.m */; };\n\t\t4C06E68120EC55B90055D09A /* IRCClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513B20EB673E00448776 /* IRCClient.m */; };\n\t\t4C06E68220EC55B90055D09A /* IRCClientConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513C20EB673E00448776 /* IRCClientConfig.m */; };\n\t\t4C06E68320EC55B90055D09A /* IRCClientRequestedCommands.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513820EB673E00448776 /* IRCClientRequestedCommands.m */; };\n\t\t4C06E68420EC55B90055D09A /* IRCCommandIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513720EB673E00448776 /* IRCCommandIndex.m */; };\n\t\t4C06E68520EC55B90055D09A /* IRCConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512E20EB673E00448776 /* IRCConnection.m */; };\n\t\t4C06E68620EC55B90055D09A /* IRCConnectionConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29C20EC4F880055D09A /* IRCConnectionConfig.m */; };\n\t\t4C06E68720EC55B90055D09A /* IRCExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513120EB673E00448776 /* IRCExtras.m */; };\n\t\t4C06E68820EC55B90055D09A /* IRCHighlightLogEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512620EB673E00448776 /* IRCHighlightLogEntry.m */; };\n\t\t4C06E68920EC55B90055D09A /* IRCHighlightMatchCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512A20EB673E00448776 /* IRCHighlightMatchCondition.m */; };\n\t\t4C06E68A20EC55B90055D09A /* IRCISupportInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514120EB673E00448776 /* IRCISupportInfo.m */; };\n\t\t4C06E68B20EC55B90055D09A /* IRCMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512D20EB673E00448776 /* IRCMessage.m */; };\n\t\t4C06E68C20EC55B90055D09A /* IRCMessageBatch.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513F20EB673E00448776 /* IRCMessageBatch.m */; };\n\t\t4C06E68D20EC55B90055D09A /* IRCModeInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513020EB673E00448776 /* IRCModeInfo.m */; };\n\t\t4C06E68E20EC55B90055D09A /* IRCNetworkList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513920EB673E00448776 /* IRCNetworkList.m */; };\n\t\t4C06E68F20EC55B90055D09A /* IRCPrefix.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512520EB673E00448776 /* IRCPrefix.m */; };\n\t\t4C06E69020EC55B90055D09A /* IRCSendingMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512C20EB673E00448776 /* IRCSendingMessage.m */; };\n\t\t4C06E69120EC55B90055D09A /* IRCServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512920EB673E00448776 /* IRCServer.m */; };\n\t\t4C06E69220EC55B90055D09A /* IRCTimerCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512F20EB673E00448776 /* IRCTimerCommand.m */; };\n\t\t4C06E69320EC55B90055D09A /* IRCTreeItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514220EB673E00448776 /* IRCTreeItem.m */; };\n\t\t4C06E69420EC55B90055D09A /* IRCWorld.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513A20EB673E00448776 /* IRCWorld.m */; };\n\t\t4C06E69620EC55B90055D09A /* IRCUserRelations.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513320EB673E00448776 /* IRCUserRelations.m */; };\n\t\t4C06E69720EC55B90055D09A /* IRCUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513420EB673E00448776 /* IRCUser.m */; };\n\t\t4C06E69820EC55B90055D09A /* IRCUserNicknameColorStyleGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513520EB673E00448776 /* IRCUserNicknameColorStyleGenerator.m */; };\n\t\t4C06E69920EC55B90055D09A /* IRCUserPersistentStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31513620EB673E00448776 /* IRCUserPersistentStore.m */; };\n\t\t4C06E69A20EC55B90055D09A /* IRCColorFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515F20EB673E00448776 /* IRCColorFormat.m */; };\n\t\t4C06E69B20EC55B90055D09A /* OELReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514820EB673E00448776 /* OELReachability.m */; };\n\t\t4C06E69C20EC55B90055D09A /* TLOLicenseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514E20EB673E00448776 /* TLOLicenseManager.m */; };\n\t\t4C06E69D20EC55B90055D09A /* TLOLicenseManagerDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515020EB673E00448776 /* TLOLicenseManagerDownloader.m */; };\n\t\t4C06E69E20EC55B90055D09A /* TLOLicenseManagerLastGen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514F20EB673E00448776 /* TLOLicenseManagerLastGen.m */; };\n\t\t4C06E6A020EC55B90055D09A /* TLOEncryptionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515320EB673E00448776 /* TLOEncryptionManager.m */; };\n\t\t4C06E6A120EC55B90055D09A /* TLOFileLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515B20EB673E00448776 /* TLOFileLogger.m */; };\n\t\t4C06E6A220EC55B90055D09A /* TLONotificationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514920EB673E00448776 /* TLONotificationController.m */; };\n\t\t4C06E6A320EC55B90055D09A /* TLOInputHistory.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515420EB673E00448776 /* TLOInputHistory.m */; };\n\t\t4C06E6A420EC55B90055D09A /* TLOInternetAddressLookup.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515620EB673E00448776 /* TLOInternetAddressLookup.m */; };\n\t\t4C06E6A520EC55B90055D09A /* TLOKeyEventHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514B20EB673E00448776 /* TLOKeyEventHandler.m */; };\n\t\t4C06E6A620EC55B90055D09A /* TLOLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29220EC4F570055D09A /* TLOLocalization.m */; };\n\t\t4C06E6A720EC55B90055D09A /* TLONicknameCompletionStatus.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515C20EB673E00448776 /* TLONicknameCompletionStatus.m */; };\n\t\t4C06E6A820EC55B90055D09A /* TLONotificationConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515D20EB673E00448776 /* TLONotificationConfiguration.m */; };\n\t\t4C06E6AA20EC55B90055D09A /* TLOSoundPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515820EB673E00448776 /* TLOSoundPlayer.m */; };\n\t\t4C06E6AB20EC55B90055D09A /* TLOSpeechSynthesizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515720EB673E00448776 /* TLOSpeechSynthesizer.m */; };\n\t\t4C06E6AC20EC55B90055D09A /* TLOSpokenNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515A20EB673E00448776 /* TLOSpokenNotification.m */; };\n\t\t4C06E6AD20EC55B90055D09A /* TLOTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E29320EC4F570055D09A /* TLOTimer.m */; };\n\t\t4C06E6AE20EC55B90055D09A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31514420EB673E00448776 /* main.m */; };\n\t\t4C06E6B120EC55B90055D09A /* TPCThemeController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511F20EB673E00448776 /* TPCThemeController.m */; };\n\t\t4C06E6B220EC55B90055D09A /* TPCTheme.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512020EB673E00448776 /* TPCTheme.m */; };\n\t\t4C06E6B320EC55B90055D09A /* TPCApplicationInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511420EB673E00448776 /* TPCApplicationInfo.m */; };\n\t\t4C06E6B420EC55B90055D09A /* TPCPathInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511A20EB673E00448776 /* TPCPathInfo.m */; };\n\t\t4C06E6B520EC55B90055D09A /* TPCPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E28820EC4F000055D09A /* TPCPreferences.m */; };\n\t\t4C06E6B620EC55B90055D09A /* TPCPreferencesLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511520EB673E00448776 /* TPCPreferencesLocal.m */; };\n\t\t4C06E6B720EC55B90055D09A /* TPCPreferencesImportExport.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511620EB673E00448776 /* TPCPreferencesImportExport.m */; };\n\t\t4C06E6B820EC55B90055D09A /* TPCPreferencesReload.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31512120EB673E00448776 /* TPCPreferencesReload.m */; };\n\t\t4C06E6B920EC55B90055D09A /* TPCPreferencesUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E28920EC4F000055D09A /* TPCPreferencesUserDefaults.m */; };\n\t\t4C06E6BA20EC55B90055D09A /* TPCPreferencesUserDefaultsLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511920EB673E00448776 /* TPCPreferencesUserDefaultsLocal.m */; };\n\t\t4C06E6BC20EC55B90055D09A /* TPCResourceManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C31511820EB673E00448776 /* TPCResourceManager.m */; };\n\t\t4C06E6BD20EC55B90055D09A /* ICLPayloadLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E34E20EC50D40055D09A /* ICLPayloadLocal.m */; };\n\t\t4C06E6BF20EC55B90055D09A /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E36320EC51370055D09A /* GCDAsyncSocket.m */; settings = {COMPILER_FLAGS = \"-Wno-implicit-retain-self\"; }; };\n\t\t4C06E6C020EC55B90055D09A /* GCDAsyncSocketExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E36520EC51370055D09A /* GCDAsyncSocketExtensions.m */; };\n\t\t4C06E6C220EC55B90055D09A /* ICLPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E38B20EC51370055D09A /* ICLPayload.m */; };\n\t\t4C06E6C320EC55B90055D09A /* TVCLogLineXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C06E38620EC51370055D09A /* TVCLogLineXPC.m */; };\n\t\t4C06E6C420EC55B90055D09A /* TVCChannelSelectionOutlineCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AE20EB673E00448776 /* TVCChannelSelectionOutlineCellView.m */; };\n\t\t4C06E6C520EC55B90055D09A /* TVCChannelSelectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AF20EB673E00448776 /* TVCChannelSelectionViewController.m */; };\n\t\t4C06E6C620EC55B90055D09A /* TVCLogControllerHistoricLogFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C220EB673E00448776 /* TVCLogControllerHistoricLogFile.m */; };\n\t\t4C06E6C720EC55B90055D09A /* TVCLogControllerInlineMediaService.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C120EB673E00448776 /* TVCLogControllerInlineMediaService.m */; };\n\t\t4C06E6C820EC55B90055D09A /* TVCLogControllerOperationQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C320EB673E00448776 /* TVCLogControllerOperationQueue.m */; };\n\t\t4C06E6C920EC55B90055D09A /* TVCLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BA20EB673E00448776 /* TVCLogController.m */; };\n\t\t4C06E6CA20EC55B90055D09A /* TVCLogLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BE20EB673E00448776 /* TVCLogLine.m */; };\n\t\t4C06E6CB20EC55B90055D09A /* TVCLogPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B820EB673E00448776 /* TVCLogPolicy.m */; };\n\t\t4C06E6CC20EC55B90055D09A /* TVCLogRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BB20EB673E00448776 /* TVCLogRenderer.m */; };\n\t\t4C06E6CD20EC55B90055D09A /* TVCLogScriptEventSink.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B720EB673E00448776 /* TVCLogScriptEventSink.m */; };\n\t\t4C06E6CE20EC55B90055D09A /* TVCLogView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BD20EB673E00448776 /* TVCLogView.m */; };\n\t\t4C06E6CF20EC55B90055D09A /* TVCLogViewInternalWK1.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BC20EB673E00448776 /* TVCLogViewInternalWK1.m */; };\n\t\t4C06E6D020EC55B90055D09A /* TVCLogViewInternalWK2.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B920EB673E00448776 /* TVCLogViewInternalWK2.m */; };\n\t\t4C06E6D120EC55B90055D09A /* TVCWK1AutoScroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152BF20EB673E00448776 /* TVCWK1AutoScroller.m */; };\n\t\t4C06E6D220EC55B90055D09A /* TVCAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C920EB673E00448776 /* TVCAlert.m */; };\n\t\t4C06E6D320EC55B90055D09A /* TVCErrorMessagePopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C720EB673E00448776 /* TVCErrorMessagePopover.m */; };\n\t\t4C06E6D420EC55B90055D09A /* TVCErrorMessagePopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C820EB673E00448776 /* TVCErrorMessagePopoverController.m */; };\n\t\t4C06E6D520EC55B90055D09A /* TVCAutoExpandingTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AA20EB673E00448776 /* TVCAutoExpandingTextField.m */; };\n\t\t4C06E6D620EC55B90055D09A /* TVCAutoExpandingTokenField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A520EB673E00448776 /* TVCAutoExpandingTokenField.m */; };\n\t\t4C06E6D720EC55B90055D09A /* TVCTextFormatterMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A620EB673E00448776 /* TVCTextFormatterMenu.m */; };\n\t\t4C06E6D820EC55B90055D09A /* TVCTextViewWithIRCFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A720EB673E00448776 /* TVCTextViewWithIRCFormatter.m */; };\n\t\t4C06E6D920EC55B90055D09A /* TVCValidatedComboBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A820EB673E00448776 /* TVCValidatedComboBox.m */; };\n\t\t4C06E6DA20EC55B90055D09A /* TVCValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A920EB673E00448776 /* TVCValidatedTextField.m */; };\n\t\t4C06E6DB20EC55B90055D09A /* TVCMainWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D120EB673E00448776 /* TVCMainWindow.m */; };\n\t\t4C06E6DC20EC55B90055D09A /* TVCMainWindowAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D520EB673E00448776 /* TVCMainWindowAppearance.m */; };\n\t\t4C06E6DD20EC55B90055D09A /* TVCMainWindowChannelView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D820EB673E00448776 /* TVCMainWindowChannelView.m */; };\n\t\t4C06E6DE20EC55B90055D09A /* TVCMainWindowLoadingScreen.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D220EB673E00448776 /* TVCMainWindowLoadingScreen.m */; };\n\t\t4C06E6DF20EC55B90055D09A /* TVCMainWindowSegmentedControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D420EB673E00448776 /* TVCMainWindowSegmentedControl.m */; };\n\t\t4C06E6E120EC55B90055D09A /* TVCMainWindowSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D320EB673E00448776 /* TVCMainWindowSplitView.m */; };\n\t\t4C06E6E220EC55B90055D09A /* TVCMainWindowTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D620EB673E00448776 /* TVCMainWindowTextView.m */; };\n\t\t4C06E6E320EC55B90055D09A /* TVCMainWindowTextViewAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CF20EB673E00448776 /* TVCMainWindowTextViewAppearance.m */; };\n\t\t4C06E6E420EC55B90055D09A /* TVCMainWindowTitlebarAccessoryView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152D720EB673E00448776 /* TVCMainWindowTitlebarAccessoryView.m */; };\n\t\t4C06E6E520EC55B90055D09A /* TVCNotificationConfigurationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152AC20EB673E00448776 /* TVCNotificationConfigurationViewController.m */; };\n\t\t4C06E6E620EC55B90055D09A /* TVCServerList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CC20EB673E00448776 /* TVCServerList.m */; };\n\t\t4C06E6E720EC55B90055D09A /* TVCServerListAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CD20EB673E00448776 /* TVCServerListAppearance.m */; };\n\t\t4C06E6E820EC55B90055D09A /* TVCServerListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152CB20EB673E00448776 /* TVCServerListCell.m */; };\n\t\t4C06E6E920EC55B90055D09A /* TVCMemberList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B320EB673E00448776 /* TVCMemberList.m */; };\n\t\t4C06E6EA20EC55B90055D09A /* TVCMemberListAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B220EB673E00448776 /* TVCMemberListAppearance.m */; };\n\t\t4C06E6EB20EC55B90055D09A /* TVCMemberListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B120EB673E00448776 /* TVCMemberListCell.m */; };\n\t\t4C06E6EC20EC55B90055D09A /* TVCMemberListUserInfoPopover.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B420EB673E00448776 /* TVCMemberListUserInfoPopover.m */; };\n\t\t4C06E6ED20EC55B90055D09A /* TVCAppearance.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C420EB673E00448776 /* TVCAppearance.m */; };\n\t\t4C06E6EE20EC55B90055D09A /* TVCBasicTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152A320EB673E00448776 /* TVCBasicTableView.m */; };\n\t\t4C06E6EF20EC55B90055D09A /* TVCContentNavigationOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152B520EB673E00448776 /* TVCContentNavigationOutlineView.m */; };\n\t\t4C06E6F020EC55B90055D09A /* TVCDockIcon.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3152C520EB673E00448776 /* TVCDockIcon.m */; };\n\t\t4C0A31152C374A5B0081EF1F /* KeysExcludedFromMigrate.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C0A31122C37419D0081EF1F /* KeysExcludedFromMigrate.plist */; };\n\t\t4C0A31162C374A610081EF1F /* KeysExcludedFromMigrate.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C0A31122C37419D0081EF1F /* KeysExcludedFromMigrate.plist */; };\n\t\t4C17167D254A58BD004BE8AE /* Inline Content Loader.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C171669254A589D004BE8AE /* Inline Content Loader.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C17167E254A58BD004BE8AE /* IRC Connection Host.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C171668254A589D004BE8AE /* IRC Connection Host.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C17167F254A58BD004BE8AE /* Scrollback History Manager.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C17166A254A589E004BE8AE /* Scrollback History Manager.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C171681254A58C2004BE8AE /* Inline Content Loader.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C171669254A589D004BE8AE /* Inline Content Loader.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C171682254A58C2004BE8AE /* IRC Connection Host.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C171668254A589D004BE8AE /* IRC Connection Host.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C171683254A58C2004BE8AE /* Scrollback History Manager.xpc in Copy XPC Services */ = {isa = PBXBuildFile; fileRef = 4C17166A254A589E004BE8AE /* Scrollback History Manager.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };\n\t\t4C17305522B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C17305222B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib */; };\n\t\t4C17305622B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C17305222B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib */; };\n\t\t4C2BEB642C3866DF008F8F0D /* KeysExcludedFromContainer.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C2BEB632C3864C1008F8F0D /* KeysExcludedFromContainer.plist */; };\n\t\t4C2BEB652C3866E2008F8F0D /* KeysExcludedFromContainer.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C2BEB632C3864C1008F8F0D /* KeysExcludedFromContainer.plist */; };\n\t\t4C2E92212C1E446E003BB92D /* Caffeine.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C2E92202C1E4463003BB92D /* Caffeine.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C2E92232C1E447E003BB92D /* Caffeine.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C2E92202C1E4463003BB92D /* Caffeine.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4C2F42052C3F4218000D962D /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C2F42042C3F4218000D962D /* UserNotifications.framework */; };\n\t\t4C2F42062C3F4218000D962D /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C2F42042C3F4218000D962D /* UserNotifications.framework */; };\n\t\t4C31554C20EB6CB300448776 /* IRC.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524120EB673E00448776 /* IRC.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31554D20EB6CB300448776 /* IRCAddressBook.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A720EB673E00448776 /* IRCAddressBook.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31554E20EB6CB300448776 /* IRCAddressBookUserTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517620EB673E00448776 /* IRCAddressBookUserTracking.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31554F20EB6CB300448776 /* IRCChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524B20EB673E00448776 /* IRCChannel.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555020EB6CB300448776 /* IRCChannelConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A420EB673E00448776 /* IRCChannelConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555120EB6CB300448776 /* IRCChannelMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519A20EB673E00448776 /* IRCChannelMode.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555220EB6CB300448776 /* IRCChannelUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517920EB673E00448776 /* IRCChannelUser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555320EB6CB300448776 /* IRCClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517C20EB673E00448776 /* IRCClient.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555420EB6CB300448776 /* IRCClientConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517F20EB673E00448776 /* IRCClientConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555520EB6CB300448776 /* IRCColorFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31526120EB673E00448776 /* IRCColorFormat.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555620EB6CB300448776 /* IRCCommandIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517120EB673E00448776 /* IRCCommandIndex.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555720EB6CB300448776 /* IRCConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31526020EB673E00448776 /* IRCConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555820EB6CB300448776 /* IRCHighlightLogEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A120EB673E00448776 /* IRCHighlightLogEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555920EB6CB300448776 /* IRCHighlightMatchCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524720EB673E00448776 /* IRCHighlightMatchCondition.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555A20EB6CB300448776 /* IRCISupportInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519820EB673E00448776 /* IRCISupportInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555B20EB6CB300448776 /* IRCMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525320EB673E00448776 /* IRCMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555C20EB6CB300448776 /* IRCModeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516C20EB673E00448776 /* IRCModeInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555D20EB6CB300448776 /* IRCNetworkList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518120EB673E00448776 /* IRCNetworkList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555E20EB6CB300448776 /* IRCNumerics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516620EB673E00448776 /* IRCNumerics.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31555F20EB6CB300448776 /* IRCPrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A520EB673E00448776 /* IRCPrefix.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556020EB6CB300448776 /* IRCSendingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525520EB673E00448776 /* IRCSendingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556120EB6CB300448776 /* IRCServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524620EB673E00448776 /* IRCServer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556220EB6CB300448776 /* IRCTreeItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519720EB673E00448776 /* IRCTreeItem.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556320EB6CB300448776 /* IRCUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524E20EB673E00448776 /* IRCUser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556420EB6CB300448776 /* IRCUserRelations.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524F20EB673E00448776 /* IRCUserRelations.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556520EB6CB300448776 /* IRCWorld.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518020EB673E00448776 /* IRCWorld.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556620EB6CB300448776 /* NSColorHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519E20EB673E00448776 /* NSColorHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556720EB6CB300448776 /* NSStringHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525820EB673E00448776 /* NSStringHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556820EB6CB300448776 /* NSViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524320EB673E00448776 /* NSViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556920EB6CB300448776 /* TDCAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524920EB673E00448776 /* TDCAlert.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556A20EB6CB300448776 /* TDCInputPrompt.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516A20EB673E00448776 /* TDCInputPrompt.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556B20EB6CB300448776 /* TDCSheetBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518220EB673E00448776 /* TDCSheetBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556C20EB6CB300448776 /* TDCWindowBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525C20EB673E00448776 /* TDCWindowBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556D20EB6CB300448776 /* Textual.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525F20EB673E00448776 /* Textual.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556E20EB6CB300448776 /* TextualApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517720EB673E00448776 /* TextualApplication.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31556F20EB6CB300448776 /* THOPluginProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517820EB673E00448776 /* THOPluginProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557020EB6CB300448776 /* THOUnicodeHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A620EB673E00448776 /* THOUnicodeHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557120EB6CB300448776 /* TLOEncryptionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524520EB673E00448776 /* TLOEncryptionManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557220EB6CB300448776 /* TLONotificationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AA20EB673E00448776 /* TLONotificationController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557320EB6CB300448776 /* TLOInternetAddressLookup.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525B20EB673E00448776 /* TLOInternetAddressLookup.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557420EB6CB300448776 /* TLOKeyEventHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A820EB673E00448776 /* TLOKeyEventHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557520EB6CB300448776 /* TLOLinkParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519D20EB673E00448776 /* TLOLinkParser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557620EB6CB300448776 /* TLOpenLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517B20EB673E00448776 /* TLOpenLink.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557820EB6CB300448776 /* TLOSoundPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516420EB673E00448776 /* TLOSoundPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557920EB6CB300448776 /* TPCApplicationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524020EB673E00448776 /* TPCApplicationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557A20EB6CB300448776 /* TPCPathInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517D20EB673E00448776 /* TPCPathInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557D20EB6CB300448776 /* TPCPreferencesImportExport.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524A20EB673E00448776 /* TPCPreferencesImportExport.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557E20EB6CB300448776 /* TPCPreferencesLocal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516820EB673E00448776 /* TPCPreferencesLocal.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31557F20EB6CB300448776 /* TPCPreferencesReload.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519C20EB673E00448776 /* TPCPreferencesReload.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558020EB6CB300448776 /* TPCPreferencesUserDefaultsLocal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519F20EB673E00448776 /* TPCPreferencesUserDefaultsLocal.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558120EB6CB300448776 /* TPCResourceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516520EB673E00448776 /* TPCResourceManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558220EB6CB300448776 /* TPCThemeController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517220EB673E00448776 /* TPCThemeController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558320EB6CB300448776 /* TPCTheme.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517020EB673E00448776 /* TPCTheme.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558420EB6CB300448776 /* TVCAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516F20EB673E00448776 /* TVCAlert.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558520EB6CB300448776 /* TVCAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516E20EB673E00448776 /* TVCAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558620EB6CB300448776 /* TVCAutoExpandingTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517E20EB673E00448776 /* TVCAutoExpandingTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558720EB6CB300448776 /* TVCAutoExpandingTokenField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A320EB673E00448776 /* TVCAutoExpandingTokenField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558820EB6CB300448776 /* TVCBasicTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A220EB673E00448776 /* TVCBasicTableView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558920EB6CB300448776 /* TVCChannelSelectionViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519620EB673E00448776 /* TVCChannelSelectionViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558A20EB6CB300448776 /* TVCErrorMessagePopoverControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517520EB673E00448776 /* TVCErrorMessagePopoverControllerPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558B20EB6CB300448776 /* TVCErrorMessagePopoverPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A020EB673E00448776 /* TVCErrorMessagePopoverPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558C20EB6CB300448776 /* TVCLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525620EB673E00448776 /* TVCLogController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558D20EB6CB300448776 /* TVCLogLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519920EB673E00448776 /* TVCLogLine.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558E20EB6CB300448776 /* TVCLogRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525420EB673E00448776 /* TVCLogRenderer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31558F20EB6CB300448776 /* TVCLogView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524D20EB673E00448776 /* TVCLogView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559020EB6CB300448776 /* TVCMainWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524C20EB673E00448776 /* TVCMainWindow.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559120EB6CB300448776 /* TVCMainWindowAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525A20EB673E00448776 /* TVCMainWindowAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559220EB6CB300448776 /* TVCMainWindowLoadingScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525720EB673E00448776 /* TVCMainWindowLoadingScreen.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559320EB6CB300448776 /* TVCMainWindowSplitView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525220EB673E00448776 /* TVCMainWindowSplitView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559420EB6CB300448776 /* TVCMainWindowTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525920EB673E00448776 /* TVCMainWindowTextView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559520EB6CB300448776 /* TVCMainWindowTextViewAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524220EB673E00448776 /* TVCMainWindowTextViewAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559620EB6CB300448776 /* TVCMemberList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516920EB673E00448776 /* TVCMemberList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559720EB6CB300448776 /* TVCMemberListAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525120EB673E00448776 /* TVCMemberListAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559820EB6CB300448776 /* TVCServerList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516720EB673E00448776 /* TVCServerList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559920EB6CB300448776 /* TVCServerListAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516D20EB673E00448776 /* TVCServerListAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559A20EB6CB300448776 /* TVCTextViewWithIRCFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524420EB673E00448776 /* TVCTextViewWithIRCFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559B20EB6CB300448776 /* TVCValidatedComboBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525020EB673E00448776 /* TVCValidatedComboBox.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559C20EB6CB300448776 /* TVCValidatedTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525E20EB673E00448776 /* TVCValidatedTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559D20EB6CB300448776 /* TXAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517320EB673E00448776 /* TXAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559E20EB6CB300448776 /* TXAppearanceHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517420EB673E00448776 /* TXAppearanceHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C31559F20EB6CB300448776 /* TXGlobalModels.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524820EB673E00448776 /* TXGlobalModels.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A020EB6CB300448776 /* TXMasterController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517A20EB673E00448776 /* TXMasterController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A120EB6CB300448776 /* TXMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519B20EB673E00448776 /* TXMenuController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A220EB6CB300448776 /* TXSharedApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516B20EB673E00448776 /* TXSharedApplication.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A320EB6CB400448776 /* IRC.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524120EB673E00448776 /* IRC.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A420EB6CB400448776 /* IRCAddressBook.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A720EB673E00448776 /* IRCAddressBook.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A520EB6CB400448776 /* IRCAddressBookUserTracking.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517620EB673E00448776 /* IRCAddressBookUserTracking.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A620EB6CB400448776 /* IRCChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524B20EB673E00448776 /* IRCChannel.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A720EB6CB400448776 /* IRCChannelConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A420EB673E00448776 /* IRCChannelConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A820EB6CB400448776 /* IRCChannelMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519A20EB673E00448776 /* IRCChannelMode.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155A920EB6CB400448776 /* IRCChannelUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517920EB673E00448776 /* IRCChannelUser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AA20EB6CB400448776 /* IRCClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517C20EB673E00448776 /* IRCClient.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AB20EB6CB400448776 /* IRCClientConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517F20EB673E00448776 /* IRCClientConfig.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AC20EB6CB400448776 /* IRCColorFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31526120EB673E00448776 /* IRCColorFormat.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AD20EB6CB400448776 /* IRCCommandIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517120EB673E00448776 /* IRCCommandIndex.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AE20EB6CB400448776 /* IRCConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31526020EB673E00448776 /* IRCConnection.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155AF20EB6CB400448776 /* IRCHighlightLogEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A120EB673E00448776 /* IRCHighlightLogEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B020EB6CB400448776 /* IRCHighlightMatchCondition.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524720EB673E00448776 /* IRCHighlightMatchCondition.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B120EB6CB400448776 /* IRCISupportInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519820EB673E00448776 /* IRCISupportInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B220EB6CB400448776 /* IRCMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525320EB673E00448776 /* IRCMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B320EB6CB400448776 /* IRCModeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516C20EB673E00448776 /* IRCModeInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B420EB6CB400448776 /* IRCNetworkList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518120EB673E00448776 /* IRCNetworkList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B520EB6CB400448776 /* IRCNumerics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516620EB673E00448776 /* IRCNumerics.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B620EB6CB400448776 /* IRCPrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A520EB673E00448776 /* IRCPrefix.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B720EB6CB400448776 /* IRCSendingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525520EB673E00448776 /* IRCSendingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B820EB6CB400448776 /* IRCServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524620EB673E00448776 /* IRCServer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155B920EB6CB400448776 /* IRCTreeItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519720EB673E00448776 /* IRCTreeItem.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BA20EB6CB400448776 /* IRCUser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524E20EB673E00448776 /* IRCUser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BB20EB6CB400448776 /* IRCUserRelations.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524F20EB673E00448776 /* IRCUserRelations.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BC20EB6CB400448776 /* IRCWorld.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518020EB673E00448776 /* IRCWorld.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BD20EB6CB400448776 /* NSColorHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519E20EB673E00448776 /* NSColorHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BE20EB6CB400448776 /* NSStringHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525820EB673E00448776 /* NSStringHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155BF20EB6CB400448776 /* NSViewHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524320EB673E00448776 /* NSViewHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C020EB6CB400448776 /* TDCAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524920EB673E00448776 /* TDCAlert.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C120EB6CB400448776 /* TDCInputPrompt.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516A20EB673E00448776 /* TDCInputPrompt.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C220EB6CB400448776 /* TDCSheetBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518220EB673E00448776 /* TDCSheetBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C320EB6CB400448776 /* TDCWindowBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525C20EB673E00448776 /* TDCWindowBase.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C420EB6CB400448776 /* Textual.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525F20EB673E00448776 /* Textual.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C520EB6CB400448776 /* TextualApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517720EB673E00448776 /* TextualApplication.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C620EB6CB400448776 /* THOPluginProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517820EB673E00448776 /* THOPluginProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C720EB6CB400448776 /* THOUnicodeHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A620EB673E00448776 /* THOUnicodeHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C820EB6CB400448776 /* TLOEncryptionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524520EB673E00448776 /* TLOEncryptionManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155C920EB6CB400448776 /* TLONotificationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AA20EB673E00448776 /* TLONotificationController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155CA20EB6CB400448776 /* TLOInternetAddressLookup.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525B20EB673E00448776 /* TLOInternetAddressLookup.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155CB20EB6CB400448776 /* TLOKeyEventHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A820EB673E00448776 /* TLOKeyEventHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155CC20EB6CB400448776 /* TLOLinkParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519D20EB673E00448776 /* TLOLinkParser.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155CD20EB6CB400448776 /* TLOpenLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517B20EB673E00448776 /* TLOpenLink.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155CF20EB6CB400448776 /* TLOSoundPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516420EB673E00448776 /* TLOSoundPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D020EB6CB400448776 /* TPCApplicationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524020EB673E00448776 /* TPCApplicationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D120EB6CB400448776 /* TPCPathInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517D20EB673E00448776 /* TPCPathInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D420EB6CB400448776 /* TPCPreferencesImportExport.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524A20EB673E00448776 /* TPCPreferencesImportExport.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D520EB6CB400448776 /* TPCPreferencesLocal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516820EB673E00448776 /* TPCPreferencesLocal.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D620EB6CB400448776 /* TPCPreferencesReload.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519C20EB673E00448776 /* TPCPreferencesReload.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D720EB6CB400448776 /* TPCPreferencesUserDefaultsLocal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519F20EB673E00448776 /* TPCPreferencesUserDefaultsLocal.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D820EB6CB400448776 /* TPCResourceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516520EB673E00448776 /* TPCResourceManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155D920EB6CB400448776 /* TPCThemeController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517220EB673E00448776 /* TPCThemeController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DA20EB6CB400448776 /* TPCTheme.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517020EB673E00448776 /* TPCTheme.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DB20EB6CB400448776 /* TVCAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516F20EB673E00448776 /* TVCAlert.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DC20EB6CB400448776 /* TVCAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516E20EB673E00448776 /* TVCAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DD20EB6CB400448776 /* TVCAutoExpandingTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517E20EB673E00448776 /* TVCAutoExpandingTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DE20EB6CB400448776 /* TVCAutoExpandingTokenField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A320EB673E00448776 /* TVCAutoExpandingTokenField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155DF20EB6CB400448776 /* TVCBasicTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A220EB673E00448776 /* TVCBasicTableView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E020EB6CB400448776 /* TVCChannelSelectionViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519620EB673E00448776 /* TVCChannelSelectionViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E120EB6CB400448776 /* TVCErrorMessagePopoverControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517520EB673E00448776 /* TVCErrorMessagePopoverControllerPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E220EB6CB400448776 /* TVCErrorMessagePopoverPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151A020EB673E00448776 /* TVCErrorMessagePopoverPrivate.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E320EB6CB400448776 /* TVCLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525620EB673E00448776 /* TVCLogController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E420EB6CB400448776 /* TVCLogLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519920EB673E00448776 /* TVCLogLine.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E520EB6CB400448776 /* TVCLogRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525420EB673E00448776 /* TVCLogRenderer.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E620EB6CB400448776 /* TVCLogView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524D20EB673E00448776 /* TVCLogView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E720EB6CB400448776 /* TVCMainWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524C20EB673E00448776 /* TVCMainWindow.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E820EB6CB400448776 /* TVCMainWindowAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525A20EB673E00448776 /* TVCMainWindowAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155E920EB6CB400448776 /* TVCMainWindowLoadingScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525720EB673E00448776 /* TVCMainWindowLoadingScreen.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155EA20EB6CB400448776 /* TVCMainWindowSplitView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525220EB673E00448776 /* TVCMainWindowSplitView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155EB20EB6CB400448776 /* TVCMainWindowTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525920EB673E00448776 /* TVCMainWindowTextView.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155EC20EB6CB400448776 /* TVCMainWindowTextViewAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524220EB673E00448776 /* TVCMainWindowTextViewAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155ED20EB6CB400448776 /* TVCMemberList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516920EB673E00448776 /* TVCMemberList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155EE20EB6CB400448776 /* TVCMemberListAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525120EB673E00448776 /* TVCMemberListAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155EF20EB6CB400448776 /* TVCServerList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516720EB673E00448776 /* TVCServerList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F020EB6CB400448776 /* TVCServerListAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516D20EB673E00448776 /* TVCServerListAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F120EB6CB400448776 /* TVCTextViewWithIRCFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524420EB673E00448776 /* TVCTextViewWithIRCFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F220EB6CB400448776 /* TVCValidatedComboBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525020EB673E00448776 /* TVCValidatedComboBox.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F320EB6CB400448776 /* TVCValidatedTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31525E20EB673E00448776 /* TVCValidatedTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F420EB6CB400448776 /* TXAppearance.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517320EB673E00448776 /* TXAppearance.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F520EB6CB400448776 /* TXAppearanceHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517420EB673E00448776 /* TXAppearanceHelper.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F620EB6CB400448776 /* TXGlobalModels.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31524820EB673E00448776 /* TXGlobalModels.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F720EB6CB400448776 /* TXMasterController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31517A20EB673E00448776 /* TXMasterController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F820EB6CB400448776 /* TXMenuController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519B20EB673E00448776 /* TXMenuController.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3155F920EB6CB400448776 /* TXSharedApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516B20EB673E00448776 /* TXSharedApplication.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C3156E420EB6D0500448776 /* WebScriptObjectHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AD20EB673E00448776 /* WebScriptObjectHelperPrivate.h */; };\n\t\t4C3156E620EB6D0500448776 /* IRCAddressBookMatchCachePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E020EB673E00448776 /* IRCAddressBookMatchCachePrivate.h */; };\n\t\t4C3156E720EB6D0500448776 /* IRCAddressBookUserTrackingPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EA20EB673E00448776 /* IRCAddressBookUserTrackingPrivate.h */; };\n\t\t4C3156E820EB6D0500448776 /* IRCChannelConfigPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522120EB673E00448776 /* IRCChannelConfigPrivate.h */; };\n\t\t4C3156E920EB6D0500448776 /* IRCChannelModePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522920EB673E00448776 /* IRCChannelModePrivate.h */; };\n\t\t4C3156EA20EB6D0500448776 /* IRCChannelPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520220EB673E00448776 /* IRCChannelPrivate.h */; };\n\t\t4C3156EB20EB6D0500448776 /* IRCChannelUserPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521120EB673E00448776 /* IRCChannelUserPrivate.h */; };\n\t\t4C3156EC20EB6D0500448776 /* IRCClientConfigPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C720EB673E00448776 /* IRCClientConfigPrivate.h */; };\n\t\t4C3156ED20EB6D0500448776 /* IRCClientPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520B20EB673E00448776 /* IRCClientPrivate.h */; };\n\t\t4C3156EE20EB6D0500448776 /* IRCClientRequestedCommandsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523F20EB673E00448776 /* IRCClientRequestedCommandsPrivate.h */; };\n\t\t4C3156EF20EB6D0500448776 /* IRCColorFormatPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B120EB673E00448776 /* IRCColorFormatPrivate.h */; };\n\t\t4C3156F020EB6D0500448776 /* IRCCommandIndexPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AE20EB673E00448776 /* IRCCommandIndexPrivate.h */; };\n\t\t4C3156F120EB6D0500448776 /* IRCConnectionPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522020EB673E00448776 /* IRCConnectionPrivate.h */; };\n\t\t4C3156F220EB6D0500448776 /* IRCExtrasPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F620EB673E00448776 /* IRCExtrasPrivate.h */; };\n\t\t4C3156F320EB6D0500448776 /* IRCHighlightLogEntryPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B220EB673E00448776 /* IRCHighlightLogEntryPrivate.h */; };\n\t\t4C3156F420EB6D0500448776 /* IRCISupportInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151ED20EB673E00448776 /* IRCISupportInfoPrivate.h */; };\n\t\t4C3156F520EB6D0500448776 /* IRCMessageBatchPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E120EB673E00448776 /* IRCMessageBatchPrivate.h */; };\n\t\t4C3156F620EB6D0500448776 /* IRCMessagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BE20EB673E00448776 /* IRCMessagePrivate.h */; };\n\t\t4C3156F720EB6D0500448776 /* IRCServerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C120EB673E00448776 /* IRCServerPrivate.h */; };\n\t\t4C3156F820EB6D0500448776 /* IRCTimerCommandPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B820EB673E00448776 /* IRCTimerCommandPrivate.h */; };\n\t\t4C3156F920EB6D0500448776 /* IRCTreeItemPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E320EB673E00448776 /* IRCTreeItemPrivate.h */; };\n\t\t4C3156FA20EB6D0500448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FF20EB673E00448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h */; };\n\t\t4C3156FB20EB6D0500448776 /* IRCUserPersistentStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BC20EB673E00448776 /* IRCUserPersistentStorePrivate.h */; };\n\t\t4C3156FC20EB6D0500448776 /* IRCUserPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E720EB673E00448776 /* IRCUserPrivate.h */; };\n\t\t4C3156FD20EB6D0500448776 /* IRCUserRelationsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B420EB673E00448776 /* IRCUserRelationsPrivate.h */; };\n\t\t4C3156FE20EB6D0500448776 /* IRCWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DB20EB673E00448776 /* IRCWorldPrivate.h */; };\n\t\t4C31570020EB6D0500448776 /* NSTableVIewHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E220EB673E00448776 /* NSTableVIewHelperPrivate.h */; };\n\t\t4C31570120EB6D0500448776 /* NSViewHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521420EB673E00448776 /* NSViewHelperPrivate.h */; };\n\t\t4C31570220EB6D0500448776 /* SwiftBridgingHeaderPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520A20EB673E00448776 /* SwiftBridgingHeaderPrivate.h */; };\n\t\t4C31570320EB6D0500448776 /* TDCAboutDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522820EB673E00448776 /* TDCAboutDialogPrivate.h */; };\n\t\t4C31570420EB6D0500448776 /* TDCAddressBookSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BA20EB673E00448776 /* TDCAddressBookSheetPrivate.h */; };\n\t\t4C31570920EB6D0500448776 /* TDCChannelBanListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B920EB673E00448776 /* TDCChannelBanListSheetPrivate.h */; };\n\t\t4C31570A20EB6D0500448776 /* TDCChannelInviteSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523E20EB673E00448776 /* TDCChannelInviteSheetPrivate.h */; };\n\t\t4C31570B20EB6D0500448776 /* TDCChannelModifyModesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523D20EB673E00448776 /* TDCChannelModifyModesSheetPrivate.h */; };\n\t\t4C31570C20EB6D0500448776 /* TDCChannelModifyTopicSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E820EB673E00448776 /* TDCChannelModifyTopicSheetPrivate.h */; };\n\t\t4C31570D20EB6D0500448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B520EB673E00448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h */; };\n\t\t4C31570E20EB6D0500448776 /* TDCChannelPropertiesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523B20EB673E00448776 /* TDCChannelPropertiesSheetPrivate.h */; };\n\t\t4C31570F20EB6D0500448776 /* TDCChannelSpotlightAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521B20EB673E00448776 /* TDCChannelSpotlightAppearancePrivate.h */; };\n\t\t4C31571020EB6D0500448776 /* TDCChannelSpotlightControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522B20EB673E00448776 /* TDCChannelSpotlightControllerPrivate.h */; };\n\t\t4C31571120EB6D0500448776 /* TDCChannelSpotlightControlsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D120EB673E00448776 /* TDCChannelSpotlightControlsPrivate.h */; };\n\t\t4C31571220EB6D0500448776 /* TDCChannelSpotlightSearchResultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D920EB673E00448776 /* TDCChannelSpotlightSearchResultPrivate.h */; };\n\t\t4C31571320EB6D0500448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522C20EB673E00448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h */; };\n\t\t4C31571420EB6D0500448776 /* TDCFileTransferDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521220EB673E00448776 /* TDCFileTransferDialogPrivate.h */; };\n\t\t4C31571520EB6D0500448776 /* TDCFileTransferDialogTableCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BD20EB673E00448776 /* TDCFileTransferDialogTableCellPrivate.h */; };\n\t\t4C31571620EB6D0500448776 /* TDCFileTransferDialogTransferControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520720EB673E00448776 /* TDCFileTransferDialogTransferControllerPrivate.h */; };\n\t\t4C31571720EB6D0500448776 /* TDCHighlightEntrySheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D720EB673E00448776 /* TDCHighlightEntrySheetPrivate.h */; };\n\t\t4C31571C20EB6D0500448776 /* TDCLicenseManagerDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523720EB673E00448776 /* TDCLicenseManagerDialogPrivate.h */; };\n\t\t4C31571D20EB6D0500448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FD20EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h */; };\n\t\t4C31571E20EB6D0500448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523C20EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h */; };\n\t\t4C31571F20EB6D0500448776 /* TDCLicenseUpgradeActivateSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520E20EB673E00448776 /* TDCLicenseUpgradeActivateSheetPrivate.h */; };\n\t\t4C31572020EB6D0500448776 /* TDCLicenseUpgradeCommonActionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D320EB673E00448776 /* TDCLicenseUpgradeCommonActionsPrivate.h */; };\n\t\t4C31572120EB6D0500448776 /* TDCLicenseUpgradeDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CC20EB673E00448776 /* TDCLicenseUpgradeDialogPrivate.h */; };\n\t\t4C31572220EB6D0500448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FC20EB673E00448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h */; };\n\t\t4C31572320EB6D0500448776 /* TDCNicknameColorSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E620EB673E00448776 /* TDCNicknameColorSheetPrivate.h */; };\n\t\t4C31572420EB6D0500448776 /* TDCPreferencesControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F120EB673E00448776 /* TDCPreferencesControllerPrivate.h */; };\n\t\t4C31572520EB6D0500448776 /* TDCPreferencesNotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523920EB673E00448776 /* TDCPreferencesNotificationConfigurationPrivate.h */; };\n\t\t4C31572620EB6D0500448776 /* TDCProgressIndicatorSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DC20EB673E00448776 /* TDCProgressIndicatorSheetPrivate.h */; };\n\t\t4C31572720EB6D0500448776 /* TDCServerChangeNicknameSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EF20EB673E00448776 /* TDCServerChangeNicknameSheetPrivate.h */; };\n\t\t4C31572820EB6D0500448776 /* TDCServerChannelListDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C320EB673E00448776 /* TDCServerChannelListDialogPrivate.h */; };\n\t\t4C31572920EB6D0500448776 /* TDCServerEndpointListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522F20EB673E00448776 /* TDCServerEndpointListSheetPrivate.h */; };\n\t\t4C31572A20EB6D0500448776 /* TDCServerEndpointListSheetTablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EB20EB673E00448776 /* TDCServerEndpointListSheetTablePrivate.h */; };\n\t\t4C31572B20EB6D0500448776 /* TDCServerHighlightListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520F20EB673E00448776 /* TDCServerHighlightListSheetPrivate.h */; };\n\t\t4C31572C20EB6D0500448776 /* TDCServerPropertiesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E920EB673E00448776 /* TDCServerPropertiesSheetPrivate.h */; };\n\t\t4C31572D20EB6D0500448776 /* TDCSharedProtocolDefinitionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FB20EB673E00448776 /* TDCSharedProtocolDefinitionsPrivate.h */; };\n\t\t4C31572E20EB6D0500448776 /* TDCWelcomeSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C420EB673E00448776 /* TDCWelcomeSheetPrivate.h */; };\n\t\t4C31572F20EB6D0500448776 /* TextualPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D820EB673E00448776 /* TextualPrivate.h */; };\n\t\t4C31573020EB6D0500448776 /* THOPluginDispatcherPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521620EB673E00448776 /* THOPluginDispatcherPrivate.h */; };\n\t\t4C31573120EB6D0500448776 /* THOPluginItemPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521920EB673E00448776 /* THOPluginItemPrivate.h */; };\n\t\t4C31573220EB6D0500448776 /* THOPluginManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CF20EB673E00448776 /* THOPluginManagerPrivate.h */; };\n\t\t4C31573320EB6D0500448776 /* THOPluginProtocolPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B320EB673E00448776 /* THOPluginProtocolPrivate.h */; };\n\t\t4C31573520EB6D0500448776 /* TLOEncryptionManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520120EB673E00448776 /* TLOEncryptionManagerPrivate.h */; };\n\t\t4C31573620EB6D0500448776 /* TLOFileLoggerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F220EB673E00448776 /* TLOFileLoggerPrivate.h */; };\n\t\t4C31573720EB6D0500448776 /* TLONotificationControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AF20EB673E00448776 /* TLONotificationControllerPrivate.h */; };\n\t\t4C31573820EB6D0500448776 /* TLOInputHistoryPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DA20EB673E00448776 /* TLOInputHistoryPrivate.h */; };\n\t\t4C31573920EB6D0500448776 /* TLOLicenseManagerDownloaderPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520920EB673E00448776 /* TLOLicenseManagerDownloaderPrivate.h */; };\n\t\t4C31573A20EB6D0500448776 /* TLOLicenseManagerLastGenPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523320EB673E00448776 /* TLOLicenseManagerLastGenPrivate.h */; };\n\t\t4C31573B20EB6D0500448776 /* TLOLicenseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522220EB673E00448776 /* TLOLicenseManagerPrivate.h */; };\n\t\t4C31573C20EB6D0500448776 /* TLONicknameCompletionStatusPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523520EB673E00448776 /* TLONicknameCompletionStatusPrivate.h */; };\n\t\t4C31573D20EB6D0500448776 /* TLONotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523420EB673E00448776 /* TLONotificationConfigurationPrivate.h */; };\n\t\t4C31573E20EB6D0500448776 /* TLOSpeechSynthesizerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523620EB673E00448776 /* TLOSpeechSynthesizerPrivate.h */; };\n\t\t4C31573F20EB6D0500448776 /* TLOSpokenNotificationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520320EB673E00448776 /* TLOSpokenNotificationPrivate.h */; };\n\t\t4C31574020EB6D0500448776 /* TPCApplicationInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EE20EB673E00448776 /* TPCApplicationInfoPrivate.h */; };\n\t\t4C31574120EB6D0500448776 /* TPCPathInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D220EB673E00448776 /* TPCPathInfoPrivate.h */; };\n\t\t4C31574420EB6D0500448776 /* TPCPreferencesImportExportPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E420EB673E00448776 /* TPCPreferencesImportExportPrivate.h */; };\n\t\t4C31574520EB6D0500448776 /* TPCPreferencesLocalPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521820EB673E00448776 /* TPCPreferencesLocalPrivate.h */; };\n\t\t4C31574820EB6D0500448776 /* TPCResourceManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522520EB673E00448776 /* TPCResourceManagerPrivate.h */; };\n\t\t4C31574920EB6D0500448776 /* TPCThemeControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521020EB673E00448776 /* TPCThemeControllerPrivate.h */; };\n\t\t4C31574A20EB6D0500448776 /* TPCThemePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D620EB673E00448776 /* TPCThemePrivate.h */; };\n\t\t4C31574B20EB6D0500448776 /* TVCAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D520EB673E00448776 /* TVCAppearancePrivate.h */; };\n\t\t4C31574C20EB6D0500448776 /* TVCChannelSelectionOutlineViewCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F820EB673E00448776 /* TVCChannelSelectionOutlineViewCellPrivate.h */; };\n\t\t4C31574D20EB6D0500448776 /* TVCChannelSelectionViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520520EB673E00448776 /* TVCChannelSelectionViewControllerPrivate.h */; };\n\t\t4C31574E20EB6D0500448776 /* TVCContentNavigationOutlineViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521F20EB673E00448776 /* TVCContentNavigationOutlineViewPrivate.h */; };\n\t\t4C31574F20EB6D0500448776 /* TVCDockIconPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522720EB673E00448776 /* TVCDockIconPrivate.h */; };\n\t\t4C31575020EB6D0500448776 /* TVCLogControllerHistoricLogFilePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522420EB673E00448776 /* TVCLogControllerHistoricLogFilePrivate.h */; };\n\t\t4C31575120EB6D0500448776 /* TVCLogControllerInlineMediaServicePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C220EB673E00448776 /* TVCLogControllerInlineMediaServicePrivate.h */; };\n\t\t4C31575220EB6D0500448776 /* TVCLogControllerOperationQueuePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C920EB673E00448776 /* TVCLogControllerOperationQueuePrivate.h */; };\n\t\t4C31575320EB6D0500448776 /* TVCLogControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521520EB673E00448776 /* TVCLogControllerPrivate.h */; };\n\t\t4C31575420EB6D0500448776 /* TVCLogLinePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523020EB673E00448776 /* TVCLogLinePrivate.h */; };\n\t\t4C31575520EB6D0500448776 /* TVCLogPolicyPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DD20EB673E00448776 /* TVCLogPolicyPrivate.h */; };\n\t\t4C31575620EB6D0500448776 /* TVCLogScriptEventSinkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B020EB673E00448776 /* TVCLogScriptEventSinkPrivate.h */; };\n\t\t4C31575720EB6D0500448776 /* TVCLogViewInternalWK1.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521D20EB673E00448776 /* TVCLogViewInternalWK1.h */; };\n\t\t4C31575820EB6D0500448776 /* TVCLogViewInternalWK2.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F020EB673E00448776 /* TVCLogViewInternalWK2.h */; };\n\t\t4C31575920EB6D0500448776 /* TVCLogViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520D20EB673E00448776 /* TVCLogViewPrivate.h */; };\n\t\t4C31575A20EB6D0500448776 /* TVCMainWindowAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520020EB673E00448776 /* TVCMainWindowAppearancePrivate.h */; };\n\t\t4C31575B20EB6D0500448776 /* TVCMainWindowChannelViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C820EB673E00448776 /* TVCMainWindowChannelViewPrivate.h */; };\n\t\t4C31575C20EB6D0500448776 /* TVCMainWindowLoadingScreenPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F420EB673E00448776 /* TVCMainWindowLoadingScreenPrivate.h */; };\n\t\t4C31575D20EB6D0500448776 /* TVCMainWindowPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523820EB673E00448776 /* TVCMainWindowPrivate.h */; };\n\t\t4C31575E20EB6D0500448776 /* TVCMainWindowSegmentedControlPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522D20EB673E00448776 /* TVCMainWindowSegmentedControlPrivate.h */; };\n\t\t4C31576020EB6D0500448776 /* TVCMainWindowSplitViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CE20EB673E00448776 /* TVCMainWindowSplitViewPrivate.h */; };\n\t\t4C31576120EB6D0500448776 /* TVCMainWindowTextViewAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F320EB673E00448776 /* TVCMainWindowTextViewAppearancePrivate.h */; };\n\t\t4C31576220EB6D0500448776 /* TVCMainWindowTextViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BB20EB673E00448776 /* TVCMainWindowTextViewPrivate.h */; };\n\t\t4C31576320EB6D0500448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DF20EB673E00448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h */; };\n\t\t4C31576420EB6D0500448776 /* TVCMemberListAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521A20EB673E00448776 /* TVCMemberListAppearancePrivate.h */; };\n\t\t4C31576520EB6D0500448776 /* TVCMemberListCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C520EB673E00448776 /* TVCMemberListCellPrivate.h */; };\n\t\t4C31576620EB6D0500448776 /* TVCMemberListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BF20EB673E00448776 /* TVCMemberListPrivate.h */; };\n\t\t4C31576720EB6D0500448776 /* TVCMemberListUserInfoPopoverPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B620EB673E00448776 /* TVCMemberListUserInfoPopoverPrivate.h */; };\n\t\t4C31576820EB6D0500448776 /* TVCNotificationConfigurationViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522320EB673E00448776 /* TVCNotificationConfigurationViewControllerPrivate.h */; };\n\t\t4C31576920EB6D0500448776 /* TVCServerListAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521720EB673E00448776 /* TVCServerListAppearancePrivate.h */; };\n\t\t4C31576A20EB6D0500448776 /* TVCServerListCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F720EB673E00448776 /* TVCServerListCellPrivate.h */; };\n\t\t4C31576B20EB6D0500448776 /* TVCServerListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CA20EB673E00448776 /* TVCServerListPrivate.h */; };\n\t\t4C31576C20EB6D0500448776 /* TVCTextFormatterMenuPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522620EB673E00448776 /* TVCTextFormatterMenuPrivate.h */; };\n\t\t4C31576D20EB6D0500448776 /* TVCTextViewWithIRCFormatterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520820EB673E00448776 /* TVCTextViewWithIRCFormatterPrivate.h */; };\n\t\t4C31576E20EB6D0500448776 /* TVCWK1AutoScrollerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CD20EB673E00448776 /* TVCWK1AutoScrollerPrivate.h */; };\n\t\t4C31576F20EB6D0500448776 /* TXAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523A20EB673E00448776 /* TXAppearancePrivate.h */; };\n\t\t4C31577020EB6D0500448776 /* TXApplicationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520620EB673E00448776 /* TXApplicationPrivate.h */; };\n\t\t4C31577120EB6D0500448776 /* TXGlobalModelsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523220EB673E00448776 /* TXGlobalModelsPrivate.h */; };\n\t\t4C31577220EB6D0500448776 /* TXMasterControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520420EB673E00448776 /* TXMasterControllerPrivate.h */; };\n\t\t4C31577320EB6D0500448776 /* TXMenuControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DE20EB673E00448776 /* TXMenuControllerPrivate.h */; };\n\t\t4C31577420EB6D0500448776 /* TXSharedApplicationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C620EB673E00448776 /* TXSharedApplicationPrivate.h */; };\n\t\t4C31577520EB6D0500448776 /* TXWindowControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522A20EB673E00448776 /* TXWindowControllerPrivate.h */; };\n\t\t4C31577620EB6D0500448776 /* WKWebViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523120EB673E00448776 /* WKWebViewPrivate.h */; };\n\t\t4C31577720EB6D0600448776 /* WebScriptObjectHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AD20EB673E00448776 /* WebScriptObjectHelperPrivate.h */; };\n\t\t4C31577920EB6D0600448776 /* IRCAddressBookMatchCachePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E020EB673E00448776 /* IRCAddressBookMatchCachePrivate.h */; };\n\t\t4C31577A20EB6D0600448776 /* IRCAddressBookUserTrackingPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EA20EB673E00448776 /* IRCAddressBookUserTrackingPrivate.h */; };\n\t\t4C31577B20EB6D0600448776 /* IRCChannelConfigPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522120EB673E00448776 /* IRCChannelConfigPrivate.h */; };\n\t\t4C31577C20EB6D0600448776 /* IRCChannelModePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522920EB673E00448776 /* IRCChannelModePrivate.h */; };\n\t\t4C31577D20EB6D0600448776 /* IRCChannelPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520220EB673E00448776 /* IRCChannelPrivate.h */; };\n\t\t4C31577E20EB6D0600448776 /* IRCChannelUserPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521120EB673E00448776 /* IRCChannelUserPrivate.h */; };\n\t\t4C31577F20EB6D0600448776 /* IRCClientConfigPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C720EB673E00448776 /* IRCClientConfigPrivate.h */; };\n\t\t4C31578020EB6D0600448776 /* IRCClientPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520B20EB673E00448776 /* IRCClientPrivate.h */; };\n\t\t4C31578120EB6D0600448776 /* IRCClientRequestedCommandsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523F20EB673E00448776 /* IRCClientRequestedCommandsPrivate.h */; };\n\t\t4C31578220EB6D0600448776 /* IRCColorFormatPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B120EB673E00448776 /* IRCColorFormatPrivate.h */; };\n\t\t4C31578320EB6D0600448776 /* IRCCommandIndexPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AE20EB673E00448776 /* IRCCommandIndexPrivate.h */; };\n\t\t4C31578420EB6D0600448776 /* IRCConnectionPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522020EB673E00448776 /* IRCConnectionPrivate.h */; };\n\t\t4C31578520EB6D0600448776 /* IRCExtrasPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F620EB673E00448776 /* IRCExtrasPrivate.h */; };\n\t\t4C31578620EB6D0600448776 /* IRCHighlightLogEntryPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B220EB673E00448776 /* IRCHighlightLogEntryPrivate.h */; };\n\t\t4C31578720EB6D0600448776 /* IRCISupportInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151ED20EB673E00448776 /* IRCISupportInfoPrivate.h */; };\n\t\t4C31578820EB6D0600448776 /* IRCMessageBatchPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E120EB673E00448776 /* IRCMessageBatchPrivate.h */; };\n\t\t4C31578920EB6D0600448776 /* IRCMessagePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BE20EB673E00448776 /* IRCMessagePrivate.h */; };\n\t\t4C31578A20EB6D0600448776 /* IRCServerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C120EB673E00448776 /* IRCServerPrivate.h */; };\n\t\t4C31578B20EB6D0600448776 /* IRCTimerCommandPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B820EB673E00448776 /* IRCTimerCommandPrivate.h */; };\n\t\t4C31578C20EB6D0600448776 /* IRCTreeItemPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E320EB673E00448776 /* IRCTreeItemPrivate.h */; };\n\t\t4C31578D20EB6D0600448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FF20EB673E00448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h */; };\n\t\t4C31578E20EB6D0600448776 /* IRCUserPersistentStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BC20EB673E00448776 /* IRCUserPersistentStorePrivate.h */; };\n\t\t4C31578F20EB6D0600448776 /* IRCUserPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E720EB673E00448776 /* IRCUserPrivate.h */; };\n\t\t4C31579020EB6D0600448776 /* IRCUserRelationsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B420EB673E00448776 /* IRCUserRelationsPrivate.h */; };\n\t\t4C31579120EB6D0600448776 /* IRCWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DB20EB673E00448776 /* IRCWorldPrivate.h */; };\n\t\t4C31579320EB6D0600448776 /* NSTableVIewHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E220EB673E00448776 /* NSTableVIewHelperPrivate.h */; };\n\t\t4C31579420EB6D0600448776 /* NSViewHelperPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521420EB673E00448776 /* NSViewHelperPrivate.h */; };\n\t\t4C31579520EB6D0600448776 /* SwiftBridgingHeaderPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520A20EB673E00448776 /* SwiftBridgingHeaderPrivate.h */; };\n\t\t4C31579620EB6D0600448776 /* TDCAboutDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522820EB673E00448776 /* TDCAboutDialogPrivate.h */; };\n\t\t4C31579720EB6D0600448776 /* TDCAddressBookSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BA20EB673E00448776 /* TDCAddressBookSheetPrivate.h */; };\n\t\t4C31579C20EB6D0600448776 /* TDCChannelBanListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B920EB673E00448776 /* TDCChannelBanListSheetPrivate.h */; };\n\t\t4C31579D20EB6D0600448776 /* TDCChannelInviteSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523E20EB673E00448776 /* TDCChannelInviteSheetPrivate.h */; };\n\t\t4C31579E20EB6D0600448776 /* TDCChannelModifyModesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523D20EB673E00448776 /* TDCChannelModifyModesSheetPrivate.h */; };\n\t\t4C31579F20EB6D0600448776 /* TDCChannelModifyTopicSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E820EB673E00448776 /* TDCChannelModifyTopicSheetPrivate.h */; };\n\t\t4C3157A020EB6D0600448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B520EB673E00448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h */; };\n\t\t4C3157A120EB6D0600448776 /* TDCChannelPropertiesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523B20EB673E00448776 /* TDCChannelPropertiesSheetPrivate.h */; };\n\t\t4C3157A220EB6D0600448776 /* TDCChannelSpotlightAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521B20EB673E00448776 /* TDCChannelSpotlightAppearancePrivate.h */; };\n\t\t4C3157A320EB6D0600448776 /* TDCChannelSpotlightControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522B20EB673E00448776 /* TDCChannelSpotlightControllerPrivate.h */; };\n\t\t4C3157A420EB6D0600448776 /* TDCChannelSpotlightControlsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D120EB673E00448776 /* TDCChannelSpotlightControlsPrivate.h */; };\n\t\t4C3157A520EB6D0600448776 /* TDCChannelSpotlightSearchResultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D920EB673E00448776 /* TDCChannelSpotlightSearchResultPrivate.h */; };\n\t\t4C3157A620EB6D0600448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522C20EB673E00448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h */; };\n\t\t4C3157A720EB6D0600448776 /* TDCFileTransferDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521220EB673E00448776 /* TDCFileTransferDialogPrivate.h */; };\n\t\t4C3157A820EB6D0600448776 /* TDCFileTransferDialogTableCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BD20EB673E00448776 /* TDCFileTransferDialogTableCellPrivate.h */; };\n\t\t4C3157A920EB6D0600448776 /* TDCFileTransferDialogTransferControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520720EB673E00448776 /* TDCFileTransferDialogTransferControllerPrivate.h */; };\n\t\t4C3157AA20EB6D0600448776 /* TDCHighlightEntrySheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D720EB673E00448776 /* TDCHighlightEntrySheetPrivate.h */; };\n\t\t4C3157AF20EB6D0600448776 /* TDCLicenseManagerDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523720EB673E00448776 /* TDCLicenseManagerDialogPrivate.h */; };\n\t\t4C3157B020EB6D0600448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FD20EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h */; };\n\t\t4C3157B120EB6D0600448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523C20EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h */; };\n\t\t4C3157B220EB6D0600448776 /* TDCLicenseUpgradeActivateSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520E20EB673E00448776 /* TDCLicenseUpgradeActivateSheetPrivate.h */; };\n\t\t4C3157B320EB6D0600448776 /* TDCLicenseUpgradeCommonActionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D320EB673E00448776 /* TDCLicenseUpgradeCommonActionsPrivate.h */; };\n\t\t4C3157B420EB6D0600448776 /* TDCLicenseUpgradeDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CC20EB673E00448776 /* TDCLicenseUpgradeDialogPrivate.h */; };\n\t\t4C3157B520EB6D0600448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FC20EB673E00448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h */; };\n\t\t4C3157B620EB6D0600448776 /* TDCNicknameColorSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E620EB673E00448776 /* TDCNicknameColorSheetPrivate.h */; };\n\t\t4C3157B720EB6D0600448776 /* TDCPreferencesControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F120EB673E00448776 /* TDCPreferencesControllerPrivate.h */; };\n\t\t4C3157B820EB6D0600448776 /* TDCPreferencesNotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523920EB673E00448776 /* TDCPreferencesNotificationConfigurationPrivate.h */; };\n\t\t4C3157B920EB6D0600448776 /* TDCProgressIndicatorSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DC20EB673E00448776 /* TDCProgressIndicatorSheetPrivate.h */; };\n\t\t4C3157BA20EB6D0600448776 /* TDCServerChangeNicknameSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EF20EB673E00448776 /* TDCServerChangeNicknameSheetPrivate.h */; };\n\t\t4C3157BB20EB6D0600448776 /* TDCServerChannelListDialogPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C320EB673E00448776 /* TDCServerChannelListDialogPrivate.h */; };\n\t\t4C3157BC20EB6D0600448776 /* TDCServerEndpointListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522F20EB673E00448776 /* TDCServerEndpointListSheetPrivate.h */; };\n\t\t4C3157BD20EB6D0600448776 /* TDCServerEndpointListSheetTablePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EB20EB673E00448776 /* TDCServerEndpointListSheetTablePrivate.h */; };\n\t\t4C3157BE20EB6D0600448776 /* TDCServerHighlightListSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520F20EB673E00448776 /* TDCServerHighlightListSheetPrivate.h */; };\n\t\t4C3157BF20EB6D0600448776 /* TDCServerPropertiesSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E920EB673E00448776 /* TDCServerPropertiesSheetPrivate.h */; };\n\t\t4C3157C020EB6D0600448776 /* TDCSharedProtocolDefinitionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151FB20EB673E00448776 /* TDCSharedProtocolDefinitionsPrivate.h */; };\n\t\t4C3157C120EB6D0600448776 /* TDCWelcomeSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C420EB673E00448776 /* TDCWelcomeSheetPrivate.h */; };\n\t\t4C3157C220EB6D0600448776 /* TextualPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D820EB673E00448776 /* TextualPrivate.h */; };\n\t\t4C3157C320EB6D0600448776 /* THOPluginDispatcherPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521620EB673E00448776 /* THOPluginDispatcherPrivate.h */; };\n\t\t4C3157C420EB6D0600448776 /* THOPluginItemPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521920EB673E00448776 /* THOPluginItemPrivate.h */; };\n\t\t4C3157C520EB6D0600448776 /* THOPluginManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CF20EB673E00448776 /* THOPluginManagerPrivate.h */; };\n\t\t4C3157C620EB6D0600448776 /* THOPluginProtocolPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B320EB673E00448776 /* THOPluginProtocolPrivate.h */; };\n\t\t4C3157C820EB6D0600448776 /* TLOEncryptionManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520120EB673E00448776 /* TLOEncryptionManagerPrivate.h */; };\n\t\t4C3157C920EB6D0600448776 /* TLOFileLoggerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F220EB673E00448776 /* TLOFileLoggerPrivate.h */; };\n\t\t4C3157CA20EB6D0600448776 /* TLONotificationControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151AF20EB673E00448776 /* TLONotificationControllerPrivate.h */; };\n\t\t4C3157CB20EB6D0600448776 /* TLOInputHistoryPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DA20EB673E00448776 /* TLOInputHistoryPrivate.h */; };\n\t\t4C3157CC20EB6D0600448776 /* TLOLicenseManagerDownloaderPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520920EB673E00448776 /* TLOLicenseManagerDownloaderPrivate.h */; };\n\t\t4C3157CD20EB6D0600448776 /* TLOLicenseManagerLastGenPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523320EB673E00448776 /* TLOLicenseManagerLastGenPrivate.h */; };\n\t\t4C3157CE20EB6D0600448776 /* TLOLicenseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522220EB673E00448776 /* TLOLicenseManagerPrivate.h */; };\n\t\t4C3157CF20EB6D0600448776 /* TLONicknameCompletionStatusPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523520EB673E00448776 /* TLONicknameCompletionStatusPrivate.h */; };\n\t\t4C3157D020EB6D0600448776 /* TLONotificationConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523420EB673E00448776 /* TLONotificationConfigurationPrivate.h */; };\n\t\t4C3157D120EB6D0600448776 /* TLOSpeechSynthesizerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523620EB673E00448776 /* TLOSpeechSynthesizerPrivate.h */; };\n\t\t4C3157D220EB6D0600448776 /* TLOSpokenNotificationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520320EB673E00448776 /* TLOSpokenNotificationPrivate.h */; };\n\t\t4C3157D320EB6D0600448776 /* TPCApplicationInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151EE20EB673E00448776 /* TPCApplicationInfoPrivate.h */; };\n\t\t4C3157D420EB6D0600448776 /* TPCPathInfoPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D220EB673E00448776 /* TPCPathInfoPrivate.h */; };\n\t\t4C3157D720EB6D0600448776 /* TPCPreferencesImportExportPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151E420EB673E00448776 /* TPCPreferencesImportExportPrivate.h */; };\n\t\t4C3157D820EB6D0600448776 /* TPCPreferencesLocalPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521820EB673E00448776 /* TPCPreferencesLocalPrivate.h */; };\n\t\t4C3157DB20EB6D0600448776 /* TPCResourceManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522520EB673E00448776 /* TPCResourceManagerPrivate.h */; };\n\t\t4C3157DC20EB6D0600448776 /* TPCThemeControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521020EB673E00448776 /* TPCThemeControllerPrivate.h */; };\n\t\t4C3157DD20EB6D0600448776 /* TPCThemePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D620EB673E00448776 /* TPCThemePrivate.h */; };\n\t\t4C3157DE20EB6D0600448776 /* TVCAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151D520EB673E00448776 /* TVCAppearancePrivate.h */; };\n\t\t4C3157DF20EB6D0600448776 /* TVCChannelSelectionOutlineViewCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F820EB673E00448776 /* TVCChannelSelectionOutlineViewCellPrivate.h */; };\n\t\t4C3157E020EB6D0600448776 /* TVCChannelSelectionViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520520EB673E00448776 /* TVCChannelSelectionViewControllerPrivate.h */; };\n\t\t4C3157E120EB6D0600448776 /* TVCContentNavigationOutlineViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521F20EB673E00448776 /* TVCContentNavigationOutlineViewPrivate.h */; };\n\t\t4C3157E220EB6D0600448776 /* TVCDockIconPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522720EB673E00448776 /* TVCDockIconPrivate.h */; };\n\t\t4C3157E320EB6D0600448776 /* TVCLogControllerHistoricLogFilePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522420EB673E00448776 /* TVCLogControllerHistoricLogFilePrivate.h */; };\n\t\t4C3157E420EB6D0600448776 /* TVCLogControllerInlineMediaServicePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C220EB673E00448776 /* TVCLogControllerInlineMediaServicePrivate.h */; };\n\t\t4C3157E520EB6D0600448776 /* TVCLogControllerOperationQueuePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C920EB673E00448776 /* TVCLogControllerOperationQueuePrivate.h */; };\n\t\t4C3157E620EB6D0600448776 /* TVCLogControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521520EB673E00448776 /* TVCLogControllerPrivate.h */; };\n\t\t4C3157E720EB6D0600448776 /* TVCLogLinePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523020EB673E00448776 /* TVCLogLinePrivate.h */; };\n\t\t4C3157E820EB6D0600448776 /* TVCLogPolicyPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DD20EB673E00448776 /* TVCLogPolicyPrivate.h */; };\n\t\t4C3157E920EB6D0600448776 /* TVCLogScriptEventSinkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B020EB673E00448776 /* TVCLogScriptEventSinkPrivate.h */; };\n\t\t4C3157EA20EB6D0600448776 /* TVCLogViewInternalWK1.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521D20EB673E00448776 /* TVCLogViewInternalWK1.h */; };\n\t\t4C3157EB20EB6D0600448776 /* TVCLogViewInternalWK2.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F020EB673E00448776 /* TVCLogViewInternalWK2.h */; };\n\t\t4C3157EC20EB6D0600448776 /* TVCLogViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520D20EB673E00448776 /* TVCLogViewPrivate.h */; };\n\t\t4C3157ED20EB6D0600448776 /* TVCMainWindowAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520020EB673E00448776 /* TVCMainWindowAppearancePrivate.h */; };\n\t\t4C3157EE20EB6D0600448776 /* TVCMainWindowChannelViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C820EB673E00448776 /* TVCMainWindowChannelViewPrivate.h */; };\n\t\t4C3157EF20EB6D0600448776 /* TVCMainWindowLoadingScreenPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F420EB673E00448776 /* TVCMainWindowLoadingScreenPrivate.h */; };\n\t\t4C3157F020EB6D0600448776 /* TVCMainWindowPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523820EB673E00448776 /* TVCMainWindowPrivate.h */; };\n\t\t4C3157F120EB6D0600448776 /* TVCMainWindowSegmentedControlPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522D20EB673E00448776 /* TVCMainWindowSegmentedControlPrivate.h */; };\n\t\t4C3157F320EB6D0600448776 /* TVCMainWindowSplitViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CE20EB673E00448776 /* TVCMainWindowSplitViewPrivate.h */; };\n\t\t4C3157F420EB6D0600448776 /* TVCMainWindowTextViewAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F320EB673E00448776 /* TVCMainWindowTextViewAppearancePrivate.h */; };\n\t\t4C3157F520EB6D0600448776 /* TVCMainWindowTextViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BB20EB673E00448776 /* TVCMainWindowTextViewPrivate.h */; };\n\t\t4C3157F620EB6D0600448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DF20EB673E00448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h */; };\n\t\t4C3157F720EB6D0600448776 /* TVCMemberListAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521A20EB673E00448776 /* TVCMemberListAppearancePrivate.h */; };\n\t\t4C3157F820EB6D0600448776 /* TVCMemberListCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C520EB673E00448776 /* TVCMemberListCellPrivate.h */; };\n\t\t4C3157F920EB6D0600448776 /* TVCMemberListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151BF20EB673E00448776 /* TVCMemberListPrivate.h */; };\n\t\t4C3157FA20EB6D0600448776 /* TVCMemberListUserInfoPopoverPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151B620EB673E00448776 /* TVCMemberListUserInfoPopoverPrivate.h */; };\n\t\t4C3157FB20EB6D0600448776 /* TVCNotificationConfigurationViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522320EB673E00448776 /* TVCNotificationConfigurationViewControllerPrivate.h */; };\n\t\t4C3157FC20EB6D0600448776 /* TVCServerListAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31521720EB673E00448776 /* TVCServerListAppearancePrivate.h */; };\n\t\t4C3157FD20EB6D0600448776 /* TVCServerListCellPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151F720EB673E00448776 /* TVCServerListCellPrivate.h */; };\n\t\t4C3157FE20EB6D0600448776 /* TVCServerListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CA20EB673E00448776 /* TVCServerListPrivate.h */; };\n\t\t4C3157FF20EB6D0600448776 /* TVCTextFormatterMenuPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522620EB673E00448776 /* TVCTextFormatterMenuPrivate.h */; };\n\t\t4C31580020EB6D0600448776 /* TVCTextViewWithIRCFormatterPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520820EB673E00448776 /* TVCTextViewWithIRCFormatterPrivate.h */; };\n\t\t4C31580120EB6D0600448776 /* TVCWK1AutoScrollerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151CD20EB673E00448776 /* TVCWK1AutoScrollerPrivate.h */; };\n\t\t4C31580220EB6D0600448776 /* TXAppearancePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523A20EB673E00448776 /* TXAppearancePrivate.h */; };\n\t\t4C31580320EB6D0600448776 /* TXApplicationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520620EB673E00448776 /* TXApplicationPrivate.h */; };\n\t\t4C31580420EB6D0600448776 /* TXGlobalModelsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523220EB673E00448776 /* TXGlobalModelsPrivate.h */; };\n\t\t4C31580520EB6D0600448776 /* TXMasterControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31520420EB673E00448776 /* TXMasterControllerPrivate.h */; };\n\t\t4C31580620EB6D0600448776 /* TXMenuControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151DE20EB673E00448776 /* TXMenuControllerPrivate.h */; };\n\t\t4C31580720EB6D0600448776 /* TXSharedApplicationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3151C620EB673E00448776 /* TXSharedApplicationPrivate.h */; };\n\t\t4C31580820EB6D0600448776 /* TXWindowControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31522A20EB673E00448776 /* TXWindowControllerPrivate.h */; };\n\t\t4C31580920EB6D0600448776 /* WKWebViewPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31523120EB673E00448776 /* WKWebViewPrivate.h */; };\n\t\t4C3158AE20EB6D0F00448776 /* IRCServerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518520EB673E00448776 /* IRCServerInternal.h */; };\n\t\t4C3158AF20EB6D0F00448776 /* IRCUserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518620EB673E00448776 /* IRCUserInternal.h */; };\n\t\t4C3158B020EB6D0F00448776 /* IRCAddressBookInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518720EB673E00448776 /* IRCAddressBookInternal.h */; };\n\t\t4C3158B120EB6D0F00448776 /* TDCChannelPropertiesSheetInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518820EB673E00448776 /* TDCChannelPropertiesSheetInternal.h */; };\n\t\t4C3158B220EB6D0F00448776 /* TDCChannelSpotlightAppearanceInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518920EB673E00448776 /* TDCChannelSpotlightAppearanceInternal.h */; };\n\t\t4C3158B420EB6D0F00448776 /* IRCPrefixInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518B20EB673E00448776 /* IRCPrefixInternal.h */; };\n\t\t4C3158B520EB6D0F00448776 /* IRCChannelConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518C20EB673E00448776 /* IRCChannelConfigInternal.h */; };\n\t\t4C3158B620EB6D0F00448776 /* IRCClientConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518D20EB673E00448776 /* IRCClientConfigInternal.h */; };\n\t\t4C3158B720EB6D0F00448776 /* TVCLogLineInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518E20EB673E00448776 /* TVCLogLineInternal.h */; };\n\t\t4C3158B820EB6D0F00448776 /* IRCChannelUserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518F20EB673E00448776 /* IRCChannelUserInternal.h */; };\n\t\t4C3158B920EB6D0F00448776 /* IRCModeInfoInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519020EB673E00448776 /* IRCModeInfoInternal.h */; };\n\t\t4C3158BA20EB6D0F00448776 /* IRCMessageInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519120EB673E00448776 /* IRCMessageInternal.h */; };\n\t\t4C3158BB20EB6D0F00448776 /* TDCFileTransferDialogInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519220EB673E00448776 /* TDCFileTransferDialogInternal.h */; };\n\t\t4C3158BC20EB6D0F00448776 /* TDCChannelSpotlightControllerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519320EB673E00448776 /* TDCChannelSpotlightControllerInternal.h */; };\n\t\t4C3158BD20EB6D0F00448776 /* IRCHighlightLogEntryInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519420EB673E00448776 /* IRCHighlightLogEntryInternal.h */; };\n\t\t4C3158BE20EB6D0F00448776 /* IRCHighlightMatchConditionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519520EB673E00448776 /* IRCHighlightMatchConditionInternal.h */; };\n\t\t4C3158BF20EB6D1000448776 /* IRCServerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518520EB673E00448776 /* IRCServerInternal.h */; };\n\t\t4C3158C020EB6D1000448776 /* IRCUserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518620EB673E00448776 /* IRCUserInternal.h */; };\n\t\t4C3158C120EB6D1000448776 /* IRCAddressBookInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518720EB673E00448776 /* IRCAddressBookInternal.h */; };\n\t\t4C3158C220EB6D1000448776 /* TDCChannelPropertiesSheetInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518820EB673E00448776 /* TDCChannelPropertiesSheetInternal.h */; };\n\t\t4C3158C320EB6D1000448776 /* TDCChannelSpotlightAppearanceInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518920EB673E00448776 /* TDCChannelSpotlightAppearanceInternal.h */; };\n\t\t4C3158C520EB6D1000448776 /* IRCPrefixInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518B20EB673E00448776 /* IRCPrefixInternal.h */; };\n\t\t4C3158C620EB6D1000448776 /* IRCChannelConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518C20EB673E00448776 /* IRCChannelConfigInternal.h */; };\n\t\t4C3158C720EB6D1000448776 /* IRCClientConfigInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518D20EB673E00448776 /* IRCClientConfigInternal.h */; };\n\t\t4C3158C820EB6D1000448776 /* TVCLogLineInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518E20EB673E00448776 /* TVCLogLineInternal.h */; };\n\t\t4C3158C920EB6D1000448776 /* IRCChannelUserInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31518F20EB673E00448776 /* IRCChannelUserInternal.h */; };\n\t\t4C3158CA20EB6D1000448776 /* IRCModeInfoInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519020EB673E00448776 /* IRCModeInfoInternal.h */; };\n\t\t4C3158CB20EB6D1000448776 /* IRCMessageInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519120EB673E00448776 /* IRCMessageInternal.h */; };\n\t\t4C3158CC20EB6D1000448776 /* TDCFileTransferDialogInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519220EB673E00448776 /* TDCFileTransferDialogInternal.h */; };\n\t\t4C3158CD20EB6D1000448776 /* TDCChannelSpotlightControllerInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519320EB673E00448776 /* TDCChannelSpotlightControllerInternal.h */; };\n\t\t4C3158CE20EB6D1000448776 /* IRCHighlightLogEntryInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519420EB673E00448776 /* IRCHighlightLogEntryInternal.h */; };\n\t\t4C3158CF20EB6D1000448776 /* IRCHighlightMatchConditionInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31519520EB673E00448776 /* IRCHighlightMatchConditionInternal.h */; };\n\t\t4C3158E320EB6D1600448776 /* GTMEncodeHTML.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516220EB673E00448776 /* GTMEncodeHTML.h */; };\n\t\t4C3158E420EB6D1600448776 /* OELReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516320EB673E00448776 /* OELReachability.h */; };\n\t\t4C3158E520EB6D1600448776 /* GTMEncodeHTML.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516220EB673E00448776 /* GTMEncodeHTML.h */; };\n\t\t4C3158E620EB6D1600448776 /* OELReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C31516320EB673E00448776 /* OELReachability.h */; };\n\t\t4C33341D20CC471A00ACB9AD /* Bundled Scripts in Resources */ = {isa = PBXBuildFile; fileRef = 4C33341B20CC471A00ACB9AD /* Bundled Scripts */; };\n\t\t4C33341E20CC471A00ACB9AD /* Bundled Scripts in Resources */ = {isa = PBXBuildFile; fileRef = 4C33341B20CC471A00ACB9AD /* Bundled Scripts */; };\n\t\t4C33342220CC475300ACB9AD /* Bundled Styles in Resources */ = {isa = PBXBuildFile; fileRef = 4C33342020CC475300ACB9AD /* Bundled Styles */; };\n\t\t4C33342320CC475300ACB9AD /* Bundled Styles in Resources */ = {isa = PBXBuildFile; fileRef = 4C33342020CC475300ACB9AD /* Bundled Styles */; };\n\t\t4C469E3B20EC5BDB00094EA4 /* TLOLinkParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515520EB673E00448776 /* TLOLinkParser.swift */; };\n\t\t4C469E3C20EC5BDB00094EA4 /* TLOpenLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515920EB673E00448776 /* TLOpenLink.swift */; };\n\t\t4C469E3D20EC5BDB00094EA4 /* TLOLinkParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515520EB673E00448776 /* TLOLinkParser.swift */; };\n\t\t4C469E3E20EC5BDB00094EA4 /* TLOpenLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C31515920EB673E00448776 /* TLOpenLink.swift */; };\n\t\t4C51327920F76E980033B703 /* TLOLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C51327720F76E980033B703 /* TLOLocalization.swift */; };\n\t\t4C51327A20F76E980033B703 /* TLOLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C51327720F76E980033B703 /* TLOLocalization.swift */; };\n\t\t4C52379415C18F6700414852 /* Style Default Templates in Resources */ = {isa = PBXBuildFile; fileRef = 4C52379215C18F6700414852 /* Style Default Templates */; };\n\t\t4C5274E220F8D78800B18F9D /* IRCConnectionErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C5274E020F8D78700B18F9D /* IRCConnectionErrors.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C5274E320F8D78800B18F9D /* IRCConnectionErrors.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C5274E020F8D78700B18F9D /* IRCConnectionErrors.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C5274E720F8D7CD00B18F9D /* IRCConnectionErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5274E520F8D7CD00B18F9D /* IRCConnectionErrors.m */; };\n\t\t4C5274E820F8D7CD00B18F9D /* IRCConnectionErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5274E520F8D7CD00B18F9D /* IRCConnectionErrors.m */; };\n\t\t4C58B572186011B900834882 /* Acknowledgements.pdf in Copy Acknowledgements */ = {isa = PBXBuildFile; fileRef = 4C58B570186011AC00834882 /* Acknowledgements.pdf */; };\n\t\t4C58B573186011BE00834882 /* Acknowledgements.pdf in Copy Acknowledgements */ = {isa = PBXBuildFile; fileRef = 4C58B570186011AC00834882 /* Acknowledgements.pdf */; };\n\t\t4C5BA3CB16F1302F00A96CA2 /* Style Default Templates in Resources */ = {isa = PBXBuildFile; fileRef = 4C52379215C18F6700414852 /* Style Default Templates */; };\n\t\t4C7B05001D1210F300295E82 /* BuildConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CC70202171E1CB400BDFAE0 /* BuildConfig.h */; };\n\t\t4C7B05011D12110500295E82 /* BuildConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CC70202171E1CB400BDFAE0 /* BuildConfig.h */; };\n\t\t4C83B9121BA9BED500BD7718 /* Chat Filters.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C83B9101BA9BEB800BD7718 /* Chat Filters.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C8878042C33706E0016DB98 /* TPCSandboxMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8878032C33706E0016DB98 /* TPCSandboxMigration.m */; };\n\t\t4C8878052C33706E0016DB98 /* TPCSandboxMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8878032C33706E0016DB98 /* TPCSandboxMigration.m */; };\n\t\t4C8878072C3371470016DB98 /* TPCSandboxMigrationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C8878062C3371470016DB98 /* TPCSandboxMigrationPrivate.h */; };\n\t\t4C8878082C3371470016DB98 /* TPCSandboxMigrationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C8878062C3371470016DB98 /* TPCSandboxMigrationPrivate.h */; };\n\t\t4C8F3FD82C31AF7700118AAF /* THOPluginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C8F3FD62C31AF6E00118AAF /* THOPluginManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C8F3FD92C31AF7700118AAF /* THOPluginManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C8F3FD62C31AF6E00118AAF /* THOPluginManager.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C8F3FDC2C31B15B00118AAF /* THOPluginItemLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F3FDB2C31B15200118AAF /* THOPluginItemLogging.m */; };\n\t\t4C8F3FDD2C31B15B00118AAF /* THOPluginItemLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C8F3FDB2C31B15200118AAF /* THOPluginItemLogging.m */; };\n\t\t4C95689F194A894D003D97FD /* Smiley Converter.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C956893194A8862003D97FD /* Smiley Converter.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C9A1D9C1836E6D300C14835 /* User Insights.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D921836E6A100C14835 /* User Insights.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C9A1D9D1836E6D500C14835 /* System Info.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D931836E6A100C14835 /* System Info.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4C9A1D9E1836E6D700C14835 /* ZNC Additions.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D941836E6A100C14835 /* ZNC Additions.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n\t\t4CAB27522537EE44009B1F07 /* IRCChannelMemberList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB27502537EE43009B1F07 /* IRCChannelMemberList.m */; };\n\t\t4CAB27532537EE44009B1F07 /* IRCChannelMemberList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB27502537EE43009B1F07 /* IRCChannelMemberList.m */; };\n\t\t4CAB27582537EE66009B1F07 /* IRCChannelMemberListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB27562537EE66009B1F07 /* IRCChannelMemberListPrivate.h */; };\n\t\t4CAB27592537EE66009B1F07 /* IRCChannelMemberListPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB27562537EE66009B1F07 /* IRCChannelMemberListPrivate.h */; };\n\t\t4CAB275F2537F71B009B1F07 /* IRCChannelMemberList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB275D2537F71B009B1F07 /* IRCChannelMemberList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4CAB27602537F71B009B1F07 /* IRCChannelMemberList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB275D2537F71B009B1F07 /* IRCChannelMemberList.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4CAB2766253863BF009B1F07 /* IRCChannelMemberListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB2764253863BF009B1F07 /* IRCChannelMemberListController.m */; };\n\t\t4CAB2767253863BF009B1F07 /* IRCChannelMemberListController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAB2764253863BF009B1F07 /* IRCChannelMemberListController.m */; };\n\t\t4CAB276C253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB276A253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h */; };\n\t\t4CAB276D253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CAB276A253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h */; };\n\t\t4CAC9D7B1F2B076100AD5F12 /* Textual-Extras.pkg in Resources */ = {isa = PBXBuildFile; fileRef = 4C2F0C701F2AF3860017D3B7 /* Textual-Extras.pkg */; };\n\t\t4CAC9D831F2B076400AD5F12 /* Textual-Extras.pkg in Resources */ = {isa = PBXBuildFile; fileRef = 4C2F0C701F2AF3860017D3B7 /* Textual-Extras.pkg */; };\n\t\t4CB638CC2D45A06C002B2CC3 /* FeatureFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB638CB2D45A06C002B2CC3 /* FeatureFlags.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4CB638CD2D45A06C002B2CC3 /* FeatureFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB638CB2D45A06C002B2CC3 /* FeatureFlags.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4CB873DD22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB873DB22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m */; };\n\t\t4CB873DE22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CB873DB22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m */; };\n\t\t4CCD93FE1CA7291300335381 /* JavaScript in Resources */ = {isa = PBXBuildFile; fileRef = 4CCD93FC1CA7291300335381 /* JavaScript */; };\n\t\t4CCD93FF1CA7291300335381 /* JavaScript in Resources */ = {isa = PBXBuildFile; fileRef = 4CCD93FC1CA7291300335381 /* JavaScript */; };\n\t\t4CEA6AA52C36F90000A36551 /* KeysExcludedFromExport.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C315EE72C36581A001A16B4 /* KeysExcludedFromExport.plist */; };\n\t\t4CEA6AA62C36F90000A36551 /* PreferenceKeyMasterList.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C315EE82C36581A001A16B4 /* PreferenceKeyMasterList.plist */; };\n\t\t4CEA6AA72C36F90000A36551 /* RegisteredUserDefaults.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A520EB676400448776 /* RegisteredUserDefaults.plist */; };\n\t\t4CEA6AA82C36F90000A36551 /* RegisteredUserDefaultsInContainer.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A620EB676400448776 /* RegisteredUserDefaultsInContainer.plist */; };\n\t\t4CEA6AAA2C36F91E00A36551 /* KeysExcludedFromExport.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C315EE72C36581A001A16B4 /* KeysExcludedFromExport.plist */; };\n\t\t4CEA6AAB2C36F91E00A36551 /* PreferenceKeyMasterList.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C315EE82C36581A001A16B4 /* PreferenceKeyMasterList.plist */; };\n\t\t4CEA6AAC2C36F91E00A36551 /* RegisteredUserDefaults.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A520EB676400448776 /* RegisteredUserDefaults.plist */; };\n\t\t4CEA6AAD2C36F91E00A36551 /* RegisteredUserDefaultsInContainer.plist in Copy Preference Resources */ = {isa = PBXBuildFile; fileRef = 4C3153A620EB676400448776 /* RegisteredUserDefaultsInContainer.plist */; };\n\t\t4CEE0BDE268F3C9B004CB3C3 /* Chat Filters.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C83B9101BA9BEB800BD7718 /* Chat Filters.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4CEE0BDF268F3C9B004CB3C3 /* Smiley Converter.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C956893194A8862003D97FD /* Smiley Converter.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4CEE0BE0268F3C9B004CB3C3 /* User Insights.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D921836E6A100C14835 /* User Insights.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4CEE0BE1268F3C9B004CB3C3 /* System Info.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D931836E6A100C14835 /* System Info.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4CEE0BE2268F3C9B004CB3C3 /* ZNC Additions.bundle in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A1D941836E6A100C14835 /* ZNC Additions.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };\n\t\t4CEFEDAB22B4AF42002CEE19 /* TDCPreferencesUserStyleSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB873D622B4A497005AB046 /* TDCPreferencesUserStyleSheetPrivate.h */; };\n\t\t4CEFEDAC22B4AF42002CEE19 /* TDCPreferencesUserStyleSheetPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB873D622B4A497005AB046 /* TDCPreferencesUserStyleSheetPrivate.h */; };\n\t\t4CEFEDB122B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4CEFEDAE22B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings */; };\n\t\t4CEFEDB222B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4CEFEDAE22B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t4CBB842C16F0DA1D004E3ED6 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4C1DC5491580420500A47BC9 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 4CCF301015804DCE006FFE21;\n\t\t\tremoteInfo = \"Build Frameworks\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t4C06E44320EC539E0055D09A /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t4C06E43620EC539E0055D09A /* AutoHyperlinks.framework in Embed Frameworks */,\n\t\t\t\t4C06E43820EC539E0055D09A /* CocoaExtensions.framework in Embed Frameworks */,\n\t\t\t\t4C06E43A20EC539E0055D09A /* EncryptionKit.framework in Embed Frameworks */,\n\t\t\t\t4C06E43C20EC539E0055D09A /* GRMustache.framework in Embed Frameworks */,\n\t\t\t\t4C06E44220EC539E0055D09A /* Sparkle.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C06E48020EC541C0055D09A /* Embed Frameworks */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"\";\n\t\t\tdstSubfolderSpec = 10;\n\t\t\tfiles = (\n\t\t\t\t4C06E47320EC541C0055D09A /* AutoHyperlinks.framework in Embed Frameworks */,\n\t\t\t\t4C06E47520EC541C0055D09A /* CocoaExtensions.framework in Embed Frameworks */,\n\t\t\t\t4C06E47720EC541C0055D09A /* EncryptionKit.framework in Embed Frameworks */,\n\t\t\t\t4C06E47920EC541C0055D09A /* GRMustache.framework in Embed Frameworks */,\n\t\t\t\t4C06E47F20EC541C0055D09A /* Sparkle.framework in Embed Frameworks */,\n\t\t\t);\n\t\t\tname = \"Embed Frameworks\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C52AED515811C2000940619 /* Copy Extensions */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 12;\n\t\t\tdstPath = \"Bundled Extensions\";\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C2E92212C1E446E003BB92D /* Caffeine.bundle in Copy Extensions */,\n\t\t\t\t4C83B9121BA9BED500BD7718 /* Chat Filters.bundle in Copy Extensions */,\n\t\t\t\t4C9A1D9C1836E6D300C14835 /* User Insights.bundle in Copy Extensions */,\n\t\t\t\t4C9A1D9D1836E6D500C14835 /* System Info.bundle in Copy Extensions */,\n\t\t\t\t4C95689F194A894D003D97FD /* Smiley Converter.bundle in Copy Extensions */,\n\t\t\t\t4C9A1D9E1836E6D700C14835 /* ZNC Additions.bundle in Copy Extensions */,\n\t\t\t);\n\t\t\tname = \"Copy Extensions\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C5BA4DC16F1302F00A96CA2 /* Copy Acknowledgements */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Documentation;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C58B573186011BE00834882 /* Acknowledgements.pdf in Copy Acknowledgements */,\n\t\t\t);\n\t\t\tname = \"Copy Acknowledgements\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C761BA41E155C4300A505B7 /* Copy XPC Services */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"$(CONTENTS_FOLDER_PATH)/XPCServices\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t\t4C17167D254A58BD004BE8AE /* Inline Content Loader.xpc in Copy XPC Services */,\n\t\t\t\t4C17167E254A58BD004BE8AE /* IRC Connection Host.xpc in Copy XPC Services */,\n\t\t\t\t4C17167F254A58BD004BE8AE /* Scrollback History Manager.xpc in Copy XPC Services */,\n\t\t\t);\n\t\t\tname = \"Copy XPC Services\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C761BA61E155C6E00A505B7 /* Copy XPC Services */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"$(CONTENTS_FOLDER_PATH)/XPCServices\";\n\t\t\tdstSubfolderSpec = 16;\n\t\t\tfiles = (\n\t\t\t\t4C171681254A58C2004BE8AE /* Inline Content Loader.xpc in Copy XPC Services */,\n\t\t\t\t4C171682254A58C2004BE8AE /* IRC Connection Host.xpc in Copy XPC Services */,\n\t\t\t\t4C171683254A58C2004BE8AE /* Scrollback History Manager.xpc in Copy XPC Services */,\n\t\t\t);\n\t\t\tname = \"Copy XPC Services\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C9E534415B4C171000E84A9 /* Copy Acknowledgements */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Documentation;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C58B572186011B900834882 /* Acknowledgements.pdf in Copy Acknowledgements */,\n\t\t\t);\n\t\t\tname = \"Copy Acknowledgements\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4CEA6AA42C36F8E700A36551 /* Copy Preference Resources */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Preferences;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C2BEB642C3866DF008F8F0D /* KeysExcludedFromContainer.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AA52C36F90000A36551 /* KeysExcludedFromExport.plist in Copy Preference Resources */,\n\t\t\t\t4C0A31152C374A5B0081EF1F /* KeysExcludedFromMigrate.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AA62C36F90000A36551 /* PreferenceKeyMasterList.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AA72C36F90000A36551 /* RegisteredUserDefaults.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AA82C36F90000A36551 /* RegisteredUserDefaultsInContainer.plist in Copy Preference Resources */,\n\t\t\t);\n\t\t\tname = \"Copy Preference Resources\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4CEA6AA92C36F91400A36551 /* Copy Preference Resources */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Preferences;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C2BEB652C3866E2008F8F0D /* KeysExcludedFromContainer.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AAA2C36F91E00A36551 /* KeysExcludedFromExport.plist in Copy Preference Resources */,\n\t\t\t\t4C0A31162C374A610081EF1F /* KeysExcludedFromMigrate.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AAB2C36F91E00A36551 /* PreferenceKeyMasterList.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AAC2C36F91E00A36551 /* RegisteredUserDefaults.plist in Copy Preference Resources */,\n\t\t\t\t4CEA6AAD2C36F91E00A36551 /* RegisteredUserDefaultsInContainer.plist in Copy Preference Resources */,\n\t\t\t);\n\t\t\tname = \"Copy Preference Resources\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4CEE0BDC268F3C8D004CB3C3 /* Copy Extensions */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = \"Bundled Extensions\";\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C2E92232C1E447E003BB92D /* Caffeine.bundle in Copy Extensions */,\n\t\t\t\t4CEE0BDE268F3C9B004CB3C3 /* Chat Filters.bundle in Copy Extensions */,\n\t\t\t\t4CEE0BDF268F3C9B004CB3C3 /* Smiley Converter.bundle in Copy Extensions */,\n\t\t\t\t4CEE0BE0268F3C9B004CB3C3 /* User Insights.bundle in Copy Extensions */,\n\t\t\t\t4CEE0BE1268F3C9B004CB3C3 /* System Info.bundle in Copy Extensions */,\n\t\t\t\t4CEE0BE2268F3C9B004CB3C3 /* ZNC Additions.bundle in Copy Extensions */,\n\t\t\t);\n\t\t\tname = \"Copy Extensions\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t4C06E13A20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCServerPropertiesSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E13E20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCServerHighlightListSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14020EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCServerEndpointListSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14220EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelModifyModesSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14420EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelSpotlightController.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14620EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCFileTransferDialog.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14820EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCServerChannelListDialog.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14A20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelBanListSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14C20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelPropertiesSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E14E20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseManagerMigrateAppStoreSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15220EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseUpgradeEligibilitySheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15620EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TVCChannelSelectionView.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15820EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TXCMainMenu.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15A20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TVCNotificationConfigurationView.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15C20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseUpgradeActivateSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E15E20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCPreferences.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16020EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelInviteSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16220EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCNicknameColorSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16420EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCWelcomeSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16620EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCProgressIndicatorSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16820EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCAddressBookSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16A20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TVCAlert.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16C20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseUpgradeDialog.xib; sourceTree = \"<group>\"; };\n\t\t4C06E16E20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCServerChangeNicknameSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17020EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCChannelModifyTopicSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17220EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCAboutDialog.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17420EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCHighlightEntrySheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17620EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TVCMainWindow.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17820EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseManagerDialog.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17A20EC4AC40055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCLicenseManagerRecoverLostLicenseSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C06E17C20EC4AC40055D09A /* TVCMemberListAppearance.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMemberListAppearance.plist; sourceTree = \"<group>\"; };\n\t\t4C06E17D20EC4AC40055D09A /* TVCServerListAppearanceTemplate.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCServerListAppearanceTemplate.plist; sourceTree = \"<group>\"; };\n\t\t4C06E17E20EC4AC40055D09A /* TDCChannelSpotlightAppearanceTemplate.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TDCChannelSpotlightAppearanceTemplate.plist; sourceTree = \"<group>\"; };\n\t\t4C06E17F20EC4AC40055D09A /* TVCMemberListAppearanceTemplate.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMemberListAppearanceTemplate.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18020EC4AC40055D09A /* TVCMainWindowTextViewAppearanceTemplate.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMainWindowTextViewAppearanceTemplate.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18120EC4AC40055D09A /* TDCChannelSpotlightAppearance.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TDCChannelSpotlightAppearance.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18220EC4AC40055D09A /* TVCMainWindowAppearance.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMainWindowAppearance.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18320EC4AC40055D09A /* TVCMainWindowTextViewAppearance.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMainWindowTextViewAppearance.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18420EC4AC40055D09A /* TVCServerListAppearance.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCServerListAppearance.plist; sourceTree = \"<group>\"; };\n\t\t4C06E18520EC4AC40055D09A /* TVCMainWindowAppearanceTemplate.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TVCMainWindowAppearanceTemplate.plist; sourceTree = \"<group>\"; };\n\t\t4C06E24720EC4B970055D09A /* IRCConnectionConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCConnectionConfig.h; path = ../Shared/Headers/IRCConnectionConfig.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E25B20EC4BBD0055D09A /* IRCConnectionConfigInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCConnectionConfigInternal.h; path = ../Shared/Headers/Internal/IRCConnectionConfigInternal.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E26020EC4C560055D09A /* TPCPreferencesPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCPreferencesPrivate.h; path = ../Shared/Headers/Private/TPCPreferencesPrivate.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E26120EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCPreferencesUserDefaultsPrivate.h; path = ../Shared/Headers/Private/TPCPreferencesUserDefaultsPrivate.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E26220EC4C560055D09A /* NSObjectHelperPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSObjectHelperPrivate.h; path = ../Shared/Headers/Private/NSObjectHelperPrivate.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E26F20EC4E350055D09A /* StaticDefinitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StaticDefinitions.h; path = ../Shared/Headers/StaticDefinitions.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E27420EC4E850055D09A /* TLOTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TLOTimer.h; path = ../Shared/Headers/TLOTimer.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E27520EC4E850055D09A /* TPCPreferencesUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCPreferencesUserDefaults.h; path = ../Shared/Headers/TPCPreferencesUserDefaults.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E27620EC4E860055D09A /* TPCPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TPCPreferences.h; path = ../Shared/Headers/TPCPreferences.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E27720EC4E860055D09A /* TLOLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TLOLocalization.h; path = ../Shared/Headers/TLOLocalization.h; sourceTree = SOURCE_ROOT; };\n\t\t4C06E28820EC4F000055D09A /* TPCPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPCPreferences.m; path = ../Shared/Preferences/TPCPreferences.m; sourceTree = SOURCE_ROOT; };\n\t\t4C06E28920EC4F000055D09A /* TPCPreferencesUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TPCPreferencesUserDefaults.m; path = ../Shared/Preferences/TPCPreferencesUserDefaults.m; sourceTree = SOURCE_ROOT; };\n\t\t4C06E29220EC4F570055D09A /* TLOLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TLOLocalization.m; path = ../Shared/Library/TLOLocalization.m; sourceTree = SOURCE_ROOT; };\n\t\t4C06E29320EC4F570055D09A /* TLOTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TLOTimer.m; path = ../Shared/Library/TLOTimer.m; sourceTree = SOURCE_ROOT; };\n\t\t4C06E29C20EC4F880055D09A /* IRCConnectionConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IRCConnectionConfig.m; path = ../Shared/IRC/IRCConnectionConfig.m; sourceTree = SOURCE_ROOT; };\n\t\t4C06E2A120EC4FA50055D09A /* NSObjectHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSObjectHelper.m; path = \"../Shared/Helpers/Cocoa (Objective-C)/NSObjectHelper.m\"; sourceTree = SOURCE_ROOT; };\n\t\t4C06E2A820EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Prompts.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2AA20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/OffTheRecord.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2AC20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/CommonErrors.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2B020EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2B220EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Accessibility.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2B420EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelPropertiesSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2B620EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelBanListSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2B820EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCPreferencesController.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2BA20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCFileTransferDialog.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2BC20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelInviteSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2BE20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCAboutDialog.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2C020EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCServerPropertiesSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2C220EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/IRC.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2C420EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TLOLicenseManager.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2C620EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelModifyModesSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2C820EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TVCMainWindow.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2CA20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Notifications.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2CE20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TVCNotificationConfigurationView.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2D020EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCServerEndpointListSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2D220EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCServerChannelListDialog.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2D420EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelSpotlightController.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2D620EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCAddressBookSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2D820EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCLicenseUpgradeEligibilitySheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E2DA20EC4FF00055D09A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCChannelModifyTopicSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C06E34E20EC50D40055D09A /* ICLPayloadLocal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLPayloadLocal.m; sourceTree = \"<group>\"; };\n\t\t4C06E36320EC51370055D09A /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = \"<group>\"; };\n\t\t4C06E36520EC51370055D09A /* GCDAsyncSocketExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocketExtensions.m; sourceTree = \"<group>\"; };\n\t\t4C06E36B20EC51370055D09A /* GCDAsyncSocketExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocketExtensions.h; sourceTree = \"<group>\"; };\n\t\t4C06E36C20EC51370055D09A /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = \"<group>\"; };\n\t\t4C06E37220EC51370055D09A /* ICLPayloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayloadInternal.h; sourceTree = \"<group>\"; };\n\t\t4C06E37520EC51370055D09A /* ICLPayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayload.h; sourceTree = \"<group>\"; };\n\t\t4C06E37F20EC51370055D09A /* RCMConnectionManagerProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCMConnectionManagerProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C06E38020EC51370055D09A /* ICLInlineContentProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLInlineContentProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C06E38120EC51370055D09A /* HLSHistoricLogProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLSHistoricLogProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C06E38620EC51370055D09A /* TVCLogLineXPC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TVCLogLineXPC.m; sourceTree = \"<group>\"; };\n\t\t4C06E38B20EC51370055D09A /* ICLPayload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLPayload.m; sourceTree = \"<group>\"; };\n\t\t4C06E41020EC52240055D09A /* TVCLogLineXPCPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TVCLogLineXPCPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C06E41520EC52D50055D09A /* ICLPayloadLocalPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayloadLocalPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C0A31122C37419D0081EF1F /* KeysExcludedFromMigrate.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = KeysExcludedFromMigrate.plist; sourceTree = \"<group>\"; };\n\t\t4C10C00D1F37E59B0004C624 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };\n\t\t4C171668254A589D004BE8AE /* IRC Connection Host.xpc */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.xpc-service\"; name = \"IRC Connection Host.xpc\"; path = \"../../../.tmp/SharedBuildProducts-XPCServices/IRC Connection Host.xpc\"; sourceTree = \"<group>\"; };\n\t\t4C171669254A589D004BE8AE /* Inline Content Loader.xpc */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.xpc-service\"; name = \"Inline Content Loader.xpc\"; path = \"../../../.tmp/SharedBuildProducts-XPCServices/Inline Content Loader.xpc\"; sourceTree = \"<group>\"; };\n\t\t4C17166A254A589E004BE8AE /* Scrollback History Manager.xpc */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.xpc-service\"; name = \"Scrollback History Manager.xpc\"; path = \"../../../.tmp/SharedBuildProducts-XPCServices/Scrollback History Manager.xpc\"; sourceTree = \"<group>\"; };\n\t\t4C17305322B4A94000DC5836 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TDCPreferencesUserStyleSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C1DC5521580420500A47BC9 /* Textual.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Textual.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C24DC751A93C9CE0098D1BE /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = \"../../Frameworks/Static Libraries/Libraries/Sparkle.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4C2BEB622C385189008F8F0D /* PostprocessSparkle.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = PostprocessSparkle.sh; path = \"Build Scripts/PostprocessSparkle.sh\"; sourceTree = \"<group>\"; };\n\t\t4C2BEB632C3864C1008F8F0D /* KeysExcludedFromContainer.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = KeysExcludedFromContainer.plist; sourceTree = \"<group>\"; };\n\t\t4C2E92202C1E4463003BB92D /* Caffeine.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = Caffeine.bundle; path = \"../../../.tmp/SharedBuildProducts-Extensions/Caffeine.bundle\"; sourceTree = \"<group>\"; };\n\t\t4C2F0C701F2AF3860017D3B7 /* Textual-Extras.pkg */ = {isa = PBXFileReference; lastKnownFileType = file; name = \"Textual-Extras.pkg\"; path = \"Scripting/Script Files/Textual Extras Installer/Packages/Textual-Extras.pkg\"; sourceTree = \"<group>\"; };\n\t\t4C2F42042C3F4218000D962D /* UserNotifications.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserNotifications.framework; path = System/Library/Frameworks/UserNotifications.framework; sourceTree = SDKROOT; };\n\t\t4C31511420EB673E00448776 /* TPCApplicationInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCApplicationInfo.m; sourceTree = \"<group>\"; };\n\t\t4C31511520EB673E00448776 /* TPCPreferencesLocal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesLocal.m; sourceTree = \"<group>\"; };\n\t\t4C31511620EB673E00448776 /* TPCPreferencesImportExport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesImportExport.m; sourceTree = \"<group>\"; };\n\t\t4C31511820EB673E00448776 /* TPCResourceManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCResourceManager.m; sourceTree = \"<group>\"; };\n\t\t4C31511920EB673E00448776 /* TPCPreferencesUserDefaultsLocal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesUserDefaultsLocal.m; sourceTree = \"<group>\"; };\n\t\t4C31511A20EB673E00448776 /* TPCPathInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPathInfo.m; sourceTree = \"<group>\"; };\n\t\t4C31511F20EB673E00448776 /* TPCThemeController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCThemeController.m; sourceTree = \"<group>\"; };\n\t\t4C31512020EB673E00448776 /* TPCTheme.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCTheme.m; sourceTree = \"<group>\"; };\n\t\t4C31512120EB673E00448776 /* TPCPreferencesReload.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesReload.m; sourceTree = \"<group>\"; };\n\t\t4C31512320EB673E00448776 /* IRCAddressBook.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCAddressBook.m; sourceTree = \"<group>\"; };\n\t\t4C31512420EB673E00448776 /* IRCChannelConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCChannelConfig.m; sourceTree = \"<group>\"; };\n\t\t4C31512520EB673E00448776 /* IRCPrefix.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCPrefix.m; sourceTree = \"<group>\"; };\n\t\t4C31512620EB673E00448776 /* IRCHighlightLogEntry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCHighlightLogEntry.m; sourceTree = \"<group>\"; };\n\t\t4C31512820EB673E00448776 /* IRCChannel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCChannel.m; sourceTree = \"<group>\"; };\n\t\t4C31512920EB673E00448776 /* IRCServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCServer.m; sourceTree = \"<group>\"; };\n\t\t4C31512A20EB673E00448776 /* IRCHighlightMatchCondition.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCHighlightMatchCondition.m; sourceTree = \"<group>\"; };\n\t\t4C31512B20EB673E00448776 /* IRCAddressBookMatchCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCAddressBookMatchCache.m; sourceTree = \"<group>\"; };\n\t\t4C31512C20EB673E00448776 /* IRCSendingMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCSendingMessage.m; sourceTree = \"<group>\"; };\n\t\t4C31512D20EB673E00448776 /* IRCMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCMessage.m; sourceTree = \"<group>\"; };\n\t\t4C31512E20EB673E00448776 /* IRCConnection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCConnection.m; sourceTree = \"<group>\"; };\n\t\t4C31512F20EB673E00448776 /* IRCTimerCommand.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCTimerCommand.m; sourceTree = \"<group>\"; };\n\t\t4C31513020EB673E00448776 /* IRCModeInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCModeInfo.m; sourceTree = \"<group>\"; };\n\t\t4C31513120EB673E00448776 /* IRCExtras.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCExtras.m; sourceTree = \"<group>\"; };\n\t\t4C31513320EB673E00448776 /* IRCUserRelations.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCUserRelations.m; sourceTree = \"<group>\"; };\n\t\t4C31513420EB673E00448776 /* IRCUser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCUser.m; sourceTree = \"<group>\"; };\n\t\t4C31513520EB673E00448776 /* IRCUserNicknameColorStyleGenerator.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCUserNicknameColorStyleGenerator.m; sourceTree = \"<group>\"; };\n\t\t4C31513620EB673E00448776 /* IRCUserPersistentStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCUserPersistentStore.m; sourceTree = \"<group>\"; };\n\t\t4C31513720EB673E00448776 /* IRCCommandIndex.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCCommandIndex.m; sourceTree = \"<group>\"; };\n\t\t4C31513820EB673E00448776 /* IRCClientRequestedCommands.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCClientRequestedCommands.m; sourceTree = \"<group>\"; };\n\t\t4C31513920EB673E00448776 /* IRCNetworkList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCNetworkList.m; sourceTree = \"<group>\"; };\n\t\t4C31513A20EB673E00448776 /* IRCWorld.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCWorld.m; sourceTree = \"<group>\"; };\n\t\t4C31513B20EB673E00448776 /* IRCClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCClient.m; sourceTree = \"<group>\"; };\n\t\t4C31513C20EB673E00448776 /* IRCClientConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCClientConfig.m; sourceTree = \"<group>\"; };\n\t\t4C31513D20EB673E00448776 /* IRCChannelUser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCChannelUser.m; sourceTree = \"<group>\"; };\n\t\t4C31513E20EB673E00448776 /* IRCAddressBookUserTracking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCAddressBookUserTracking.m; sourceTree = \"<group>\"; };\n\t\t4C31513F20EB673E00448776 /* IRCMessageBatch.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCMessageBatch.m; sourceTree = \"<group>\"; };\n\t\t4C31514020EB673E00448776 /* IRCChannelMode.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCChannelMode.m; sourceTree = \"<group>\"; };\n\t\t4C31514120EB673E00448776 /* IRCISupportInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCISupportInfo.m; sourceTree = \"<group>\"; };\n\t\t4C31514220EB673E00448776 /* IRCTreeItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCTreeItem.m; sourceTree = \"<group>\"; };\n\t\t4C31514420EB673E00448776 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t4C31514820EB673E00448776 /* OELReachability.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OELReachability.m; sourceTree = \"<group>\"; };\n\t\t4C31514920EB673E00448776 /* TLONotificationController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLONotificationController.m; sourceTree = \"<group>\"; };\n\t\t4C31514B20EB673E00448776 /* TLOKeyEventHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOKeyEventHandler.m; sourceTree = \"<group>\"; };\n\t\t4C31514E20EB673E00448776 /* TLOLicenseManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOLicenseManager.m; sourceTree = \"<group>\"; };\n\t\t4C31514F20EB673E00448776 /* TLOLicenseManagerLastGen.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOLicenseManagerLastGen.m; sourceTree = \"<group>\"; };\n\t\t4C31515020EB673E00448776 /* TLOLicenseManagerDownloader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOLicenseManagerDownloader.m; sourceTree = \"<group>\"; };\n\t\t4C31515320EB673E00448776 /* TLOEncryptionManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOEncryptionManager.m; sourceTree = \"<group>\"; };\n\t\t4C31515420EB673E00448776 /* TLOInputHistory.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOInputHistory.m; sourceTree = \"<group>\"; };\n\t\t4C31515520EB673E00448776 /* TLOLinkParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLOLinkParser.swift; sourceTree = \"<group>\"; };\n\t\t4C31515620EB673E00448776 /* TLOInternetAddressLookup.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOInternetAddressLookup.m; sourceTree = \"<group>\"; };\n\t\t4C31515720EB673E00448776 /* TLOSpeechSynthesizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOSpeechSynthesizer.m; sourceTree = \"<group>\"; };\n\t\t4C31515820EB673E00448776 /* TLOSoundPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOSoundPlayer.m; sourceTree = \"<group>\"; };\n\t\t4C31515920EB673E00448776 /* TLOpenLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLOpenLink.swift; sourceTree = \"<group>\"; };\n\t\t4C31515A20EB673E00448776 /* TLOSpokenNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOSpokenNotification.m; sourceTree = \"<group>\"; };\n\t\t4C31515B20EB673E00448776 /* TLOFileLogger.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLOFileLogger.m; sourceTree = \"<group>\"; };\n\t\t4C31515C20EB673E00448776 /* TLONicknameCompletionStatus.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLONicknameCompletionStatus.m; sourceTree = \"<group>\"; };\n\t\t4C31515D20EB673E00448776 /* TLONotificationConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TLONotificationConfiguration.m; sourceTree = \"<group>\"; };\n\t\t4C31515F20EB673E00448776 /* IRCColorFormat.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = IRCColorFormat.m; sourceTree = \"<group>\"; };\n\t\t4C31516220EB673E00448776 /* GTMEncodeHTML.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GTMEncodeHTML.h; sourceTree = \"<group>\"; };\n\t\t4C31516320EB673E00448776 /* OELReachability.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OELReachability.h; sourceTree = \"<group>\"; };\n\t\t4C31516420EB673E00448776 /* TLOSoundPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOSoundPlayer.h; sourceTree = \"<group>\"; };\n\t\t4C31516520EB673E00448776 /* TPCResourceManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCResourceManager.h; sourceTree = \"<group>\"; };\n\t\t4C31516620EB673E00448776 /* IRCNumerics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCNumerics.h; sourceTree = \"<group>\"; };\n\t\t4C31516720EB673E00448776 /* TVCServerList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCServerList.h; sourceTree = \"<group>\"; };\n\t\t4C31516820EB673E00448776 /* TPCPreferencesLocal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesLocal.h; sourceTree = \"<group>\"; };\n\t\t4C31516920EB673E00448776 /* TVCMemberList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberList.h; sourceTree = \"<group>\"; };\n\t\t4C31516A20EB673E00448776 /* TDCInputPrompt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCInputPrompt.h; sourceTree = \"<group>\"; };\n\t\t4C31516B20EB673E00448776 /* TXSharedApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXSharedApplication.h; sourceTree = \"<group>\"; };\n\t\t4C31516C20EB673E00448776 /* IRCModeInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCModeInfo.h; sourceTree = \"<group>\"; };\n\t\t4C31516D20EB673E00448776 /* TVCServerListAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCServerListAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31516E20EB673E00448776 /* TVCAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31516F20EB673E00448776 /* TVCAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCAlert.h; sourceTree = \"<group>\"; };\n\t\t4C31517020EB673E00448776 /* TPCTheme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCTheme.h; sourceTree = \"<group>\"; };\n\t\t4C31517120EB673E00448776 /* IRCCommandIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCCommandIndex.h; sourceTree = \"<group>\"; };\n\t\t4C31517220EB673E00448776 /* TPCThemeController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCThemeController.h; sourceTree = \"<group>\"; };\n\t\t4C31517320EB673E00448776 /* TXAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31517420EB673E00448776 /* TXAppearanceHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXAppearanceHelper.h; sourceTree = \"<group>\"; };\n\t\t4C31517520EB673E00448776 /* TVCErrorMessagePopoverControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCErrorMessagePopoverControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31517620EB673E00448776 /* IRCAddressBookUserTracking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCAddressBookUserTracking.h; sourceTree = \"<group>\"; };\n\t\t4C31517720EB673E00448776 /* TextualApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextualApplication.h; sourceTree = \"<group>\"; };\n\t\t4C31517820EB673E00448776 /* THOPluginProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C31517920EB673E00448776 /* IRCChannelUser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelUser.h; sourceTree = \"<group>\"; };\n\t\t4C31517A20EB673E00448776 /* TXMasterController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXMasterController.h; sourceTree = \"<group>\"; };\n\t\t4C31517B20EB673E00448776 /* TLOpenLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOpenLink.h; sourceTree = \"<group>\"; };\n\t\t4C31517C20EB673E00448776 /* IRCClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClient.h; sourceTree = \"<group>\"; };\n\t\t4C31517D20EB673E00448776 /* TPCPathInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPathInfo.h; sourceTree = \"<group>\"; };\n\t\t4C31517E20EB673E00448776 /* TVCAutoExpandingTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCAutoExpandingTextField.h; sourceTree = \"<group>\"; };\n\t\t4C31517F20EB673E00448776 /* IRCClientConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClientConfig.h; sourceTree = \"<group>\"; };\n\t\t4C31518020EB673E00448776 /* IRCWorld.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCWorld.h; sourceTree = \"<group>\"; };\n\t\t4C31518120EB673E00448776 /* IRCNetworkList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCNetworkList.h; sourceTree = \"<group>\"; };\n\t\t4C31518220EB673E00448776 /* TDCSheetBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCSheetBase.h; sourceTree = \"<group>\"; };\n\t\t4C31518520EB673E00448776 /* IRCServerInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCServerInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518620EB673E00448776 /* IRCUserInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518720EB673E00448776 /* IRCAddressBookInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCAddressBookInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518820EB673E00448776 /* TDCChannelPropertiesSheetInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelPropertiesSheetInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518920EB673E00448776 /* TDCChannelSpotlightAppearanceInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightAppearanceInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518B20EB673E00448776 /* IRCPrefixInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCPrefixInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518C20EB673E00448776 /* IRCChannelConfigInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelConfigInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518D20EB673E00448776 /* IRCClientConfigInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClientConfigInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518E20EB673E00448776 /* TVCLogLineInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogLineInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31518F20EB673E00448776 /* IRCChannelUserInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelUserInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519020EB673E00448776 /* IRCModeInfoInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCModeInfoInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519120EB673E00448776 /* IRCMessageInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCMessageInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519220EB673E00448776 /* TDCFileTransferDialogInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCFileTransferDialogInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519320EB673E00448776 /* TDCChannelSpotlightControllerInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightControllerInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519420EB673E00448776 /* IRCHighlightLogEntryInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCHighlightLogEntryInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519520EB673E00448776 /* IRCHighlightMatchConditionInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCHighlightMatchConditionInternal.h; sourceTree = \"<group>\"; };\n\t\t4C31519620EB673E00448776 /* TVCChannelSelectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCChannelSelectionViewController.h; sourceTree = \"<group>\"; };\n\t\t4C31519720EB673E00448776 /* IRCTreeItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCTreeItem.h; sourceTree = \"<group>\"; };\n\t\t4C31519820EB673E00448776 /* IRCISupportInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCISupportInfo.h; sourceTree = \"<group>\"; };\n\t\t4C31519920EB673E00448776 /* TVCLogLine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogLine.h; sourceTree = \"<group>\"; };\n\t\t4C31519A20EB673E00448776 /* IRCChannelMode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelMode.h; sourceTree = \"<group>\"; };\n\t\t4C31519B20EB673E00448776 /* TXMenuController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXMenuController.h; sourceTree = \"<group>\"; };\n\t\t4C31519C20EB673E00448776 /* TPCPreferencesReload.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesReload.h; sourceTree = \"<group>\"; };\n\t\t4C31519D20EB673E00448776 /* TLOLinkParser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOLinkParser.h; sourceTree = \"<group>\"; };\n\t\t4C31519E20EB673E00448776 /* NSColorHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSColorHelper.h; sourceTree = \"<group>\"; };\n\t\t4C31519F20EB673E00448776 /* TPCPreferencesUserDefaultsLocal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesUserDefaultsLocal.h; sourceTree = \"<group>\"; };\n\t\t4C3151A020EB673E00448776 /* TVCErrorMessagePopoverPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCErrorMessagePopoverPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151A120EB673E00448776 /* IRCHighlightLogEntry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCHighlightLogEntry.h; sourceTree = \"<group>\"; };\n\t\t4C3151A220EB673E00448776 /* TVCBasicTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCBasicTableView.h; sourceTree = \"<group>\"; };\n\t\t4C3151A320EB673E00448776 /* TVCAutoExpandingTokenField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCAutoExpandingTokenField.h; sourceTree = \"<group>\"; };\n\t\t4C3151A420EB673E00448776 /* IRCChannelConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelConfig.h; sourceTree = \"<group>\"; };\n\t\t4C3151A520EB673E00448776 /* IRCPrefix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCPrefix.h; sourceTree = \"<group>\"; };\n\t\t4C3151A620EB673E00448776 /* THOUnicodeHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOUnicodeHelper.h; sourceTree = \"<group>\"; };\n\t\t4C3151A720EB673E00448776 /* IRCAddressBook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCAddressBook.h; sourceTree = \"<group>\"; };\n\t\t4C3151A820EB673E00448776 /* TLOKeyEventHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOKeyEventHandler.h; sourceTree = \"<group>\"; };\n\t\t4C3151AA20EB673E00448776 /* TLONotificationController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLONotificationController.h; sourceTree = \"<group>\"; };\n\t\t4C3151AD20EB673E00448776 /* WebScriptObjectHelperPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebScriptObjectHelperPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151AE20EB673E00448776 /* IRCCommandIndexPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCCommandIndexPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151AF20EB673E00448776 /* TLONotificationControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLONotificationControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B020EB673E00448776 /* TVCLogScriptEventSinkPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogScriptEventSinkPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B120EB673E00448776 /* IRCColorFormatPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCColorFormatPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B220EB673E00448776 /* IRCHighlightLogEntryPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCHighlightLogEntryPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B320EB673E00448776 /* THOPluginProtocolPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginProtocolPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B420EB673E00448776 /* IRCUserRelationsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserRelationsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B520EB673E00448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelPropertiesNotificationConfigurationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B620EB673E00448776 /* TVCMemberListUserInfoPopoverPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberListUserInfoPopoverPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B820EB673E00448776 /* IRCTimerCommandPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCTimerCommandPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151B920EB673E00448776 /* TDCChannelBanListSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelBanListSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BA20EB673E00448776 /* TDCAddressBookSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCAddressBookSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BB20EB673E00448776 /* TVCMainWindowTextViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowTextViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BC20EB673E00448776 /* IRCUserPersistentStorePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserPersistentStorePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BD20EB673E00448776 /* TDCFileTransferDialogTableCellPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCFileTransferDialogTableCellPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BE20EB673E00448776 /* IRCMessagePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCMessagePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151BF20EB673E00448776 /* TVCMemberListPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberListPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C120EB673E00448776 /* IRCServerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCServerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C220EB673E00448776 /* TVCLogControllerInlineMediaServicePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogControllerInlineMediaServicePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C320EB673E00448776 /* TDCServerChannelListDialogPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerChannelListDialogPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C420EB673E00448776 /* TDCWelcomeSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCWelcomeSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C520EB673E00448776 /* TVCMemberListCellPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberListCellPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C620EB673E00448776 /* TXSharedApplicationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXSharedApplicationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C720EB673E00448776 /* IRCClientConfigPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClientConfigPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C820EB673E00448776 /* TVCMainWindowChannelViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowChannelViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151C920EB673E00448776 /* TVCLogControllerOperationQueuePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogControllerOperationQueuePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151CA20EB673E00448776 /* TVCServerListPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCServerListPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151CC20EB673E00448776 /* TDCLicenseUpgradeDialogPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseUpgradeDialogPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151CD20EB673E00448776 /* TVCWK1AutoScrollerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCWK1AutoScrollerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151CE20EB673E00448776 /* TVCMainWindowSplitViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowSplitViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151CF20EB673E00448776 /* THOPluginManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginManagerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D120EB673E00448776 /* TDCChannelSpotlightControlsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightControlsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D220EB673E00448776 /* TPCPathInfoPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPathInfoPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D320EB673E00448776 /* TDCLicenseUpgradeCommonActionsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseUpgradeCommonActionsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D520EB673E00448776 /* TVCAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D620EB673E00448776 /* TPCThemePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCThemePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D720EB673E00448776 /* TDCHighlightEntrySheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCHighlightEntrySheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D820EB673E00448776 /* TextualPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextualPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151D920EB673E00448776 /* TDCChannelSpotlightSearchResultPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightSearchResultPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DA20EB673E00448776 /* TLOInputHistoryPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOInputHistoryPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DB20EB673E00448776 /* IRCWorldPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCWorldPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DC20EB673E00448776 /* TDCProgressIndicatorSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCProgressIndicatorSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DD20EB673E00448776 /* TVCLogPolicyPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogPolicyPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DE20EB673E00448776 /* TXMenuControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXMenuControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151DF20EB673E00448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowTitlebarAccessoryViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E020EB673E00448776 /* IRCAddressBookMatchCachePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCAddressBookMatchCachePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E120EB673E00448776 /* IRCMessageBatchPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCMessageBatchPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E220EB673E00448776 /* NSTableVIewHelperPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSTableVIewHelperPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E320EB673E00448776 /* IRCTreeItemPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCTreeItemPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E420EB673E00448776 /* TPCPreferencesImportExportPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesImportExportPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E620EB673E00448776 /* TDCNicknameColorSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCNicknameColorSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E720EB673E00448776 /* IRCUserPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E820EB673E00448776 /* TDCChannelModifyTopicSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelModifyTopicSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151E920EB673E00448776 /* TDCServerPropertiesSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerPropertiesSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151EA20EB673E00448776 /* IRCAddressBookUserTrackingPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCAddressBookUserTrackingPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151EB20EB673E00448776 /* TDCServerEndpointListSheetTablePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerEndpointListSheetTablePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151ED20EB673E00448776 /* IRCISupportInfoPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCISupportInfoPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151EE20EB673E00448776 /* TPCApplicationInfoPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCApplicationInfoPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151EF20EB673E00448776 /* TDCServerChangeNicknameSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerChangeNicknameSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F020EB673E00448776 /* TVCLogViewInternalWK2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogViewInternalWK2.h; sourceTree = \"<group>\"; };\n\t\t4C3151F120EB673E00448776 /* TDCPreferencesControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCPreferencesControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F220EB673E00448776 /* TLOFileLoggerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOFileLoggerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F320EB673E00448776 /* TVCMainWindowTextViewAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowTextViewAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F420EB673E00448776 /* TVCMainWindowLoadingScreenPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowLoadingScreenPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F620EB673E00448776 /* IRCExtrasPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCExtrasPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F720EB673E00448776 /* TVCServerListCellPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCServerListCellPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151F820EB673E00448776 /* TVCChannelSelectionOutlineViewCellPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCChannelSelectionOutlineViewCellPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151FB20EB673E00448776 /* TDCSharedProtocolDefinitionsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCSharedProtocolDefinitionsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151FC20EB673E00448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseUpgradeEligibilitySheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151FD20EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseManagerMigrateAppStoreSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C3151FF20EB673E00448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserNicknameColorStyleGeneratorPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520020EB673E00448776 /* TVCMainWindowAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520120EB673E00448776 /* TLOEncryptionManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOEncryptionManagerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520220EB673E00448776 /* IRCChannelPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520320EB673E00448776 /* TLOSpokenNotificationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOSpokenNotificationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520420EB673E00448776 /* TXMasterControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXMasterControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520520EB673E00448776 /* TVCChannelSelectionViewControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCChannelSelectionViewControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520620EB673E00448776 /* TXApplicationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXApplicationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520720EB673E00448776 /* TDCFileTransferDialogTransferControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCFileTransferDialogTransferControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520820EB673E00448776 /* TVCTextViewWithIRCFormatterPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCTextViewWithIRCFormatterPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520920EB673E00448776 /* TLOLicenseManagerDownloaderPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOLicenseManagerDownloaderPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520A20EB673E00448776 /* SwiftBridgingHeaderPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftBridgingHeaderPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520B20EB673E00448776 /* IRCClientPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClientPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520D20EB673E00448776 /* TVCLogViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520E20EB673E00448776 /* TDCLicenseUpgradeActivateSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseUpgradeActivateSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31520F20EB673E00448776 /* TDCServerHighlightListSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerHighlightListSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521020EB673E00448776 /* TPCThemeControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCThemeControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521120EB673E00448776 /* IRCChannelUserPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelUserPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521220EB673E00448776 /* TDCFileTransferDialogPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCFileTransferDialogPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521420EB673E00448776 /* NSViewHelperPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSViewHelperPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521520EB673E00448776 /* TVCLogControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521620EB673E00448776 /* THOPluginDispatcherPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginDispatcherPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521720EB673E00448776 /* TVCServerListAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCServerListAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521820EB673E00448776 /* TPCPreferencesLocalPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesLocalPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521920EB673E00448776 /* THOPluginItemPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginItemPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521A20EB673E00448776 /* TVCMemberListAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberListAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521B20EB673E00448776 /* TDCChannelSpotlightAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31521D20EB673E00448776 /* TVCLogViewInternalWK1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogViewInternalWK1.h; sourceTree = \"<group>\"; };\n\t\t4C31521F20EB673E00448776 /* TVCContentNavigationOutlineViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCContentNavigationOutlineViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522020EB673E00448776 /* IRCConnectionPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCConnectionPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522120EB673E00448776 /* IRCChannelConfigPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelConfigPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522220EB673E00448776 /* TLOLicenseManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOLicenseManagerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522320EB673E00448776 /* TVCNotificationConfigurationViewControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCNotificationConfigurationViewControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522420EB673E00448776 /* TVCLogControllerHistoricLogFilePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogControllerHistoricLogFilePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522520EB673E00448776 /* TPCResourceManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCResourceManagerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522620EB673E00448776 /* TVCTextFormatterMenuPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCTextFormatterMenuPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522720EB673E00448776 /* TVCDockIconPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCDockIconPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522820EB673E00448776 /* TDCAboutDialogPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCAboutDialogPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522920EB673E00448776 /* IRCChannelModePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannelModePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522A20EB673E00448776 /* TXWindowControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXWindowControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522B20EB673E00448776 /* TDCChannelSpotlightControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522C20EB673E00448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelSpotlightSearchResultsTablePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522D20EB673E00448776 /* TVCMainWindowSegmentedControlPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowSegmentedControlPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31522F20EB673E00448776 /* TDCServerEndpointListSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCServerEndpointListSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523020EB673E00448776 /* TVCLogLinePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogLinePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523120EB673E00448776 /* WKWebViewPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKWebViewPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523220EB673E00448776 /* TXGlobalModelsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXGlobalModelsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523320EB673E00448776 /* TLOLicenseManagerLastGenPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOLicenseManagerLastGenPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523420EB673E00448776 /* TLONotificationConfigurationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLONotificationConfigurationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523520EB673E00448776 /* TLONicknameCompletionStatusPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLONicknameCompletionStatusPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523620EB673E00448776 /* TLOSpeechSynthesizerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOSpeechSynthesizerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523720EB673E00448776 /* TDCLicenseManagerDialogPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseManagerDialogPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523820EB673E00448776 /* TVCMainWindowPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523920EB673E00448776 /* TDCPreferencesNotificationConfigurationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCPreferencesNotificationConfigurationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523A20EB673E00448776 /* TXAppearancePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXAppearancePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523B20EB673E00448776 /* TDCChannelPropertiesSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelPropertiesSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523C20EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCLicenseManagerRecoverLostLicenseSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523D20EB673E00448776 /* TDCChannelModifyModesSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelModifyModesSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523E20EB673E00448776 /* TDCChannelInviteSheetPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCChannelInviteSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31523F20EB673E00448776 /* IRCClientRequestedCommandsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCClientRequestedCommandsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C31524020EB673E00448776 /* TPCApplicationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCApplicationInfo.h; sourceTree = \"<group>\"; };\n\t\t4C31524120EB673E00448776 /* IRC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRC.h; sourceTree = \"<group>\"; };\n\t\t4C31524220EB673E00448776 /* TVCMainWindowTextViewAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowTextViewAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31524320EB673E00448776 /* NSViewHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSViewHelper.h; sourceTree = \"<group>\"; };\n\t\t4C31524420EB673E00448776 /* TVCTextViewWithIRCFormatter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCTextViewWithIRCFormatter.h; sourceTree = \"<group>\"; };\n\t\t4C31524520EB673E00448776 /* TLOEncryptionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOEncryptionManager.h; sourceTree = \"<group>\"; };\n\t\t4C31524620EB673E00448776 /* IRCServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCServer.h; sourceTree = \"<group>\"; };\n\t\t4C31524720EB673E00448776 /* IRCHighlightMatchCondition.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCHighlightMatchCondition.h; sourceTree = \"<group>\"; };\n\t\t4C31524820EB673E00448776 /* TXGlobalModels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TXGlobalModels.h; sourceTree = \"<group>\"; };\n\t\t4C31524920EB673E00448776 /* TDCAlert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCAlert.h; sourceTree = \"<group>\"; };\n\t\t4C31524A20EB673E00448776 /* TPCPreferencesImportExport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesImportExport.h; sourceTree = \"<group>\"; };\n\t\t4C31524B20EB673E00448776 /* IRCChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCChannel.h; sourceTree = \"<group>\"; };\n\t\t4C31524C20EB673E00448776 /* TVCMainWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindow.h; sourceTree = \"<group>\"; };\n\t\t4C31524D20EB673E00448776 /* TVCLogView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogView.h; sourceTree = \"<group>\"; };\n\t\t4C31524E20EB673E00448776 /* IRCUser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUser.h; sourceTree = \"<group>\"; };\n\t\t4C31524F20EB673E00448776 /* IRCUserRelations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCUserRelations.h; sourceTree = \"<group>\"; };\n\t\t4C31525020EB673E00448776 /* TVCValidatedComboBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCValidatedComboBox.h; sourceTree = \"<group>\"; };\n\t\t4C31525120EB673E00448776 /* TVCMemberListAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMemberListAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31525220EB673E00448776 /* TVCMainWindowSplitView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowSplitView.h; sourceTree = \"<group>\"; };\n\t\t4C31525320EB673E00448776 /* IRCMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCMessage.h; sourceTree = \"<group>\"; };\n\t\t4C31525420EB673E00448776 /* TVCLogRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogRenderer.h; sourceTree = \"<group>\"; };\n\t\t4C31525520EB673E00448776 /* IRCSendingMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCSendingMessage.h; sourceTree = \"<group>\"; };\n\t\t4C31525620EB673E00448776 /* TVCLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCLogController.h; sourceTree = \"<group>\"; };\n\t\t4C31525720EB673E00448776 /* TVCMainWindowLoadingScreen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowLoadingScreen.h; sourceTree = \"<group>\"; };\n\t\t4C31525820EB673E00448776 /* NSStringHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSStringHelper.h; sourceTree = \"<group>\"; };\n\t\t4C31525920EB673E00448776 /* TVCMainWindowTextView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowTextView.h; sourceTree = \"<group>\"; };\n\t\t4C31525A20EB673E00448776 /* TVCMainWindowAppearance.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCMainWindowAppearance.h; sourceTree = \"<group>\"; };\n\t\t4C31525B20EB673E00448776 /* TLOInternetAddressLookup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOInternetAddressLookup.h; sourceTree = \"<group>\"; };\n\t\t4C31525C20EB673E00448776 /* TDCWindowBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDCWindowBase.h; sourceTree = \"<group>\"; };\n\t\t4C31525E20EB673E00448776 /* TVCValidatedTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TVCValidatedTextField.h; sourceTree = \"<group>\"; };\n\t\t4C31525F20EB673E00448776 /* Textual.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Textual.h; sourceTree = \"<group>\"; };\n\t\t4C31526020EB673E00448776 /* IRCConnection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCConnection.h; sourceTree = \"<group>\"; };\n\t\t4C31526120EB673E00448776 /* IRCColorFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCColorFormat.h; sourceTree = \"<group>\"; };\n\t\t4C31526320EB673E00448776 /* TDCChannelInviteSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelInviteSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31526420EB673E00448776 /* TDCChannelPropertiesSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelPropertiesSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31526520EB673E00448776 /* TDCServerPropertiesSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerPropertiesSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31526620EB673E00448776 /* TDCChannelModifyModesSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelModifyModesSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31526820EB673E00448776 /* TDCPreferencesNotificationConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCPreferencesNotificationConfiguration.m; sourceTree = \"<group>\"; };\n\t\t4C31526920EB673E00448776 /* TDCPreferencesController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCPreferencesController.m; sourceTree = \"<group>\"; };\n\t\t4C31526B20EB673E00448776 /* TDCChannelSpotlightControls.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelSpotlightControls.m; sourceTree = \"<group>\"; };\n\t\t4C31526C20EB673E00448776 /* TDCChannelSpotlightSearchResult.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelSpotlightSearchResult.m; sourceTree = \"<group>\"; };\n\t\t4C31526D20EB673E00448776 /* TDCChannelSpotlightController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelSpotlightController.m; sourceTree = \"<group>\"; };\n\t\t4C31526E20EB673E00448776 /* TDCChannelSpotlightAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelSpotlightAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C31526F20EB673E00448776 /* TDCChannelSpotlightSearchResultsTable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelSpotlightSearchResultsTable.m; sourceTree = \"<group>\"; };\n\t\t4C31527020EB673E00448776 /* TDCAddressBookSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCAddressBookSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31527120EB673E00448776 /* TDCChannelPropertiesNotificationConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelPropertiesNotificationConfiguration.m; sourceTree = \"<group>\"; };\n\t\t4C31527420EB673E00448776 /* TDCLicenseUpgradeDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseUpgradeDialog.m; sourceTree = \"<group>\"; };\n\t\t4C31527520EB673E00448776 /* TDCLicenseUpgradeEligibilitySheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseUpgradeEligibilitySheet.m; sourceTree = \"<group>\"; };\n\t\t4C31527620EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseManagerMigrateAppStoreSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31527720EB673E00448776 /* TDCLicenseUpgradeCommonActions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseUpgradeCommonActions.m; sourceTree = \"<group>\"; };\n\t\t4C31527820EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseManagerRecoverLostLicenseSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31527920EB673E00448776 /* TDCLicenseUpgradeActivateSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseUpgradeActivateSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31527A20EB673E00448776 /* TDCLicenseManagerDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCLicenseManagerDialog.m; sourceTree = \"<group>\"; };\n\t\t4C31528020EB673E00448776 /* TDCAlert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCAlert.m; sourceTree = \"<group>\"; };\n\t\t4C31528120EB673E00448776 /* TDCAboutDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCAboutDialog.m; sourceTree = \"<group>\"; };\n\t\t4C31528220EB673E00448776 /* TDCChannelBanListSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelBanListSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528320EB673E00448776 /* TDCHighlightEntrySheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCHighlightEntrySheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528420EB673E00448776 /* TDCWindowBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCWindowBase.m; sourceTree = \"<group>\"; };\n\t\t4C31528520EB673E00448776 /* TDCInputPrompt.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCInputPrompt.m; sourceTree = \"<group>\"; };\n\t\t4C31528620EB673E00448776 /* TDCServerChannelListDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerChannelListDialog.m; sourceTree = \"<group>\"; };\n\t\t4C31528720EB673E00448776 /* TDCServerHighlightListSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerHighlightListSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528820EB673E00448776 /* TDCProgressIndicatorSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCProgressIndicatorSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528920EB673E00448776 /* TDCChannelModifyTopicSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCChannelModifyTopicSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528A20EB673E00448776 /* TDCSheetBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCSheetBase.m; sourceTree = \"<group>\"; };\n\t\t4C31528B20EB673E00448776 /* TDCWelcomeSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCWelcomeSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528C20EB673E00448776 /* TDCServerChangeNicknameSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerChangeNicknameSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31528E20EB673E00448776 /* TDCServerEndpointListSheetTable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerEndpointListSheetTable.m; sourceTree = \"<group>\"; };\n\t\t4C31528F20EB673E00448776 /* TDCServerEndpointListSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCServerEndpointListSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31529120EB673E00448776 /* TDCFileTransferDialog.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCFileTransferDialog.m; sourceTree = \"<group>\"; };\n\t\t4C31529220EB673E00448776 /* TDCFileTransferDialogTransferController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCFileTransferDialogTransferController.m; sourceTree = \"<group>\"; };\n\t\t4C31529320EB673E00448776 /* TDCFileTransferDialogTableCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCFileTransferDialogTableCell.m; sourceTree = \"<group>\"; };\n\t\t4C31529420EB673E00448776 /* TDCNicknameColorSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDCNicknameColorSheet.m; sourceTree = \"<group>\"; };\n\t\t4C31529B20EB673E00448776 /* TXGlobalModels.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXGlobalModels.m; sourceTree = \"<group>\"; };\n\t\t4C31529C20EB673E00448776 /* TXApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXApplication.m; sourceTree = \"<group>\"; };\n\t\t4C31529D20EB673E00448776 /* TXSharedApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXSharedApplication.m; sourceTree = \"<group>\"; };\n\t\t4C31529E20EB673E00448776 /* TXAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C31529F20EB673E00448776 /* TXMasterController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXMasterController.m; sourceTree = \"<group>\"; };\n\t\t4C3152A020EB673E00448776 /* TXWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXWindowController.m; sourceTree = \"<group>\"; };\n\t\t4C3152A120EB673E00448776 /* TXMenuController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXMenuController.m; sourceTree = \"<group>\"; };\n\t\t4C3152A320EB673E00448776 /* TVCBasicTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCBasicTableView.m; sourceTree = \"<group>\"; };\n\t\t4C3152A520EB673E00448776 /* TVCAutoExpandingTokenField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCAutoExpandingTokenField.m; sourceTree = \"<group>\"; };\n\t\t4C3152A620EB673E00448776 /* TVCTextFormatterMenu.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCTextFormatterMenu.m; sourceTree = \"<group>\"; };\n\t\t4C3152A720EB673E00448776 /* TVCTextViewWithIRCFormatter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCTextViewWithIRCFormatter.m; sourceTree = \"<group>\"; };\n\t\t4C3152A820EB673E00448776 /* TVCValidatedComboBox.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCValidatedComboBox.m; sourceTree = \"<group>\"; };\n\t\t4C3152A920EB673E00448776 /* TVCValidatedTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCValidatedTextField.m; sourceTree = \"<group>\"; };\n\t\t4C3152AA20EB673E00448776 /* TVCAutoExpandingTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCAutoExpandingTextField.m; sourceTree = \"<group>\"; };\n\t\t4C3152AC20EB673E00448776 /* TVCNotificationConfigurationViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCNotificationConfigurationViewController.m; sourceTree = \"<group>\"; };\n\t\t4C3152AE20EB673E00448776 /* TVCChannelSelectionOutlineCellView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCChannelSelectionOutlineCellView.m; sourceTree = \"<group>\"; };\n\t\t4C3152AF20EB673E00448776 /* TVCChannelSelectionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCChannelSelectionViewController.m; sourceTree = \"<group>\"; };\n\t\t4C3152B120EB673E00448776 /* TVCMemberListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMemberListCell.m; sourceTree = \"<group>\"; };\n\t\t4C3152B220EB673E00448776 /* TVCMemberListAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMemberListAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C3152B320EB673E00448776 /* TVCMemberList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMemberList.m; sourceTree = \"<group>\"; };\n\t\t4C3152B420EB673E00448776 /* TVCMemberListUserInfoPopover.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMemberListUserInfoPopover.m; sourceTree = \"<group>\"; };\n\t\t4C3152B520EB673E00448776 /* TVCContentNavigationOutlineView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCContentNavigationOutlineView.m; sourceTree = \"<group>\"; };\n\t\t4C3152B720EB673E00448776 /* TVCLogScriptEventSink.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogScriptEventSink.m; sourceTree = \"<group>\"; };\n\t\t4C3152B820EB673E00448776 /* TVCLogPolicy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogPolicy.m; sourceTree = \"<group>\"; };\n\t\t4C3152B920EB673E00448776 /* TVCLogViewInternalWK2.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogViewInternalWK2.m; sourceTree = \"<group>\"; };\n\t\t4C3152BA20EB673E00448776 /* TVCLogController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogController.m; sourceTree = \"<group>\"; };\n\t\t4C3152BB20EB673E00448776 /* TVCLogRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogRenderer.m; sourceTree = \"<group>\"; };\n\t\t4C3152BC20EB673E00448776 /* TVCLogViewInternalWK1.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogViewInternalWK1.m; sourceTree = \"<group>\"; };\n\t\t4C3152BD20EB673E00448776 /* TVCLogView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogView.m; sourceTree = \"<group>\"; };\n\t\t4C3152BE20EB673E00448776 /* TVCLogLine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogLine.m; sourceTree = \"<group>\"; };\n\t\t4C3152BF20EB673E00448776 /* TVCWK1AutoScroller.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCWK1AutoScroller.m; sourceTree = \"<group>\"; };\n\t\t4C3152C120EB673E00448776 /* TVCLogControllerInlineMediaService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogControllerInlineMediaService.m; sourceTree = \"<group>\"; };\n\t\t4C3152C220EB673E00448776 /* TVCLogControllerHistoricLogFile.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogControllerHistoricLogFile.m; sourceTree = \"<group>\"; };\n\t\t4C3152C320EB673E00448776 /* TVCLogControllerOperationQueue.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCLogControllerOperationQueue.m; sourceTree = \"<group>\"; };\n\t\t4C3152C420EB673E00448776 /* TVCAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C3152C520EB673E00448776 /* TVCDockIcon.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCDockIcon.m; sourceTree = \"<group>\"; };\n\t\t4C3152C720EB673E00448776 /* TVCErrorMessagePopover.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCErrorMessagePopover.m; sourceTree = \"<group>\"; };\n\t\t4C3152C820EB673E00448776 /* TVCErrorMessagePopoverController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCErrorMessagePopoverController.m; sourceTree = \"<group>\"; };\n\t\t4C3152C920EB673E00448776 /* TVCAlert.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCAlert.m; sourceTree = \"<group>\"; };\n\t\t4C3152CB20EB673E00448776 /* TVCServerListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCServerListCell.m; sourceTree = \"<group>\"; };\n\t\t4C3152CC20EB673E00448776 /* TVCServerList.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCServerList.m; sourceTree = \"<group>\"; };\n\t\t4C3152CD20EB673E00448776 /* TVCServerListAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCServerListAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C3152CF20EB673E00448776 /* TVCMainWindowTextViewAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowTextViewAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C3152D120EB673E00448776 /* TVCMainWindow.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindow.m; sourceTree = \"<group>\"; };\n\t\t4C3152D220EB673E00448776 /* TVCMainWindowLoadingScreen.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowLoadingScreen.m; sourceTree = \"<group>\"; };\n\t\t4C3152D320EB673E00448776 /* TVCMainWindowSplitView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowSplitView.m; sourceTree = \"<group>\"; };\n\t\t4C3152D420EB673E00448776 /* TVCMainWindowSegmentedControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowSegmentedControl.m; sourceTree = \"<group>\"; };\n\t\t4C3152D520EB673E00448776 /* TVCMainWindowAppearance.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowAppearance.m; sourceTree = \"<group>\"; };\n\t\t4C3152D620EB673E00448776 /* TVCMainWindowTextView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowTextView.m; sourceTree = \"<group>\"; };\n\t\t4C3152D720EB673E00448776 /* TVCMainWindowTitlebarAccessoryView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowTitlebarAccessoryView.m; sourceTree = \"<group>\"; };\n\t\t4C3152D820EB673E00448776 /* TVCMainWindowChannelView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TVCMainWindowChannelView.m; sourceTree = \"<group>\"; };\n\t\t4C3152DC20EB673E00448776 /* WebScriptObjectHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebScriptObjectHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152DE20EB673E00448776 /* GTMEncodeHTML.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GTMEncodeHTML.m; sourceTree = \"<group>\"; };\n\t\t4C3152DF20EB673E00448776 /* THOUnicodeHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THOUnicodeHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152E120EB673E00448776 /* THOPluginDispatcher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THOPluginDispatcher.m; sourceTree = \"<group>\"; };\n\t\t4C3152E220EB673E00448776 /* THOPluginManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THOPluginManager.m; sourceTree = \"<group>\"; };\n\t\t4C3152E320EB673E00448776 /* THOPluginItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THOPluginItem.m; sourceTree = \"<group>\"; };\n\t\t4C3152E520EB673E00448776 /* NSColorHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSColorHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152E620EB673E00448776 /* NSViewHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSViewHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152E720EB673E00448776 /* NSStringHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSStringHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152E820EB673E00448776 /* NSTableViewHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSTableViewHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152E920EB673E00448776 /* TXAppearanceHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TXAppearanceHelper.m; sourceTree = \"<group>\"; };\n\t\t4C3152EE20EB676400448776 /* RemoteLicenseSystemPublicKey.pub */ = {isa = PBXFileReference; lastKnownFileType = text; path = RemoteLicenseSystemPublicKey.pub; sourceTree = \"<group>\"; };\n\t\t4C31531920EB676400448776 /* TPWTB_Advanced@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Advanced@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31531A20EB676400448776 /* TPWTB_Highlights.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Highlights.png; sourceTree = \"<group>\"; };\n\t\t4C31531B20EB676400448776 /* TPWTB_Highlights@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Highlights@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31531C20EB676400448776 /* TPWTB_Addons.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Addons.png; sourceTree = \"<group>\"; };\n\t\t4C31531D20EB676400448776 /* TPWTB_Advanced.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Advanced.png; sourceTree = \"<group>\"; };\n\t\t4C31531E20EB676400448776 /* TPWTB_Controls.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Controls.png; sourceTree = \"<group>\"; };\n\t\t4C31531F20EB676400448776 /* TPWTB_Style@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Style@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532020EB676400448776 /* TPWTB_General@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_General@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532120EB676400448776 /* TPWTB_Addons@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Addons@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532220EB676400448776 /* TPWTB_Notifications@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Notifications@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532320EB676400448776 /* TPWTB_Controls@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Controls@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532420EB676400448776 /* TPWTB_Interface.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Interface.png; sourceTree = \"<group>\"; };\n\t\t4C31532520EB676400448776 /* TPWTB_Interface@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = \"TPWTB_Interface@2x.png\"; sourceTree = \"<group>\"; };\n\t\t4C31532620EB676400448776 /* TPWTB_Notifications.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Notifications.png; sourceTree = \"<group>\"; };\n\t\t4C31532720EB676400448776 /* TPWTB_Style.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_Style.png; sourceTree = \"<group>\"; };\n\t\t4C31532820EB676400448776 /* TPWTB_General.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TPWTB_General.png; sourceTree = \"<group>\"; };\n\t\t4C31533120EB676400448776 /* channelRoomStatusIconLightActive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"channelRoomStatusIconLightActive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31533220EB676400448776 /* channelRoomStatusIconDarkActive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"channelRoomStatusIconDarkActive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31533320EB676400448776 /* channelRoomStatusIconLightInactive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = channelRoomStatusIconLightInactive.tif; sourceTree = \"<group>\"; };\n\t\t4C31533420EB676400448776 /* channelRoomStatusIconDarkInactive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"channelRoomStatusIconDarkInactive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31533620EB676400448776 /* channelRoomStatusIconDarkActive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = channelRoomStatusIconDarkActive.tif; sourceTree = \"<group>\"; };\n\t\t4C31533720EB676400448776 /* channelRoomStatusIconLightActive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = channelRoomStatusIconLightActive.tif; sourceTree = \"<group>\"; };\n\t\t4C31533920EB676400448776 /* channelRoomStatusIconDarkInactive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = channelRoomStatusIconDarkInactive.tif; sourceTree = \"<group>\"; };\n\t\t4C31533B20EB676400448776 /* channelRoomStatusIconLightInactive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"channelRoomStatusIconLightInactive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31533D20EB676400448776 /* FormattingColor_8.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_8.png; sourceTree = \"<group>\"; };\n\t\t4C31533E20EB676400448776 /* FormattingColor_9.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_9.png; sourceTree = \"<group>\"; };\n\t\t4C31533F20EB676400448776 /* FormattingColor_11.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_11.png; sourceTree = \"<group>\"; };\n\t\t4C31534020EB676400448776 /* FormattingColor_10.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_10.png; sourceTree = \"<group>\"; };\n\t\t4C31534120EB676400448776 /* FormattingColor_12.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_12.png; sourceTree = \"<group>\"; };\n\t\t4C31534220EB676400448776 /* FormattingColor_Rainbow.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = FormattingColor_Rainbow.tif; sourceTree = \"<group>\"; };\n\t\t4C31534320EB676400448776 /* FormattingColor_13.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_13.png; sourceTree = \"<group>\"; };\n\t\t4C31534420EB676400448776 /* FormattingColor_14.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_14.png; sourceTree = \"<group>\"; };\n\t\t4C31534520EB676400448776 /* FormattingColor_15.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_15.png; sourceTree = \"<group>\"; };\n\t\t4C31534620EB676400448776 /* FormattingColor_7.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_7.png; sourceTree = \"<group>\"; };\n\t\t4C31534720EB676400448776 /* FormattingColor_6.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_6.png; sourceTree = \"<group>\"; };\n\t\t4C31534820EB676400448776 /* FormattingColor_4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_4.png; sourceTree = \"<group>\"; };\n\t\t4C31534920EB676400448776 /* FormattingColor_5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_5.png; sourceTree = \"<group>\"; };\n\t\t4C31534A20EB676400448776 /* FormattingColor_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_1.png; sourceTree = \"<group>\"; };\n\t\t4C31534B20EB676400448776 /* FormattingColor_Rainbow@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"FormattingColor_Rainbow@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31534C20EB676400448776 /* FormattingColor_0.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_0.png; sourceTree = \"<group>\"; };\n\t\t4C31534D20EB676400448776 /* FormattingColor_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_2.png; sourceTree = \"<group>\"; };\n\t\t4C31534E20EB676400448776 /* FormattingColor_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = FormattingColor_3.png; sourceTree = \"<group>\"; };\n\t\t4C31535020EB676400448776 /* encryptionLockIconLight@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"encryptionLockIconLight@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31535120EB676400448776 /* encryptionLockIconDark.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = encryptionLockIconDark.tif; sourceTree = \"<group>\"; };\n\t\t4C31535220EB676400448776 /* encryptionLockIconDark@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"encryptionLockIconDark@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31535320EB676400448776 /* encryptionLockIconLight.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = encryptionLockIconLight.tif; sourceTree = \"<group>\"; };\n\t\t4C31535620EB676400448776 /* Copyright Information for Images.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = \"Copyright Information for Images.txt\"; sourceTree = \"<group>\"; };\n\t\t4C31535820EB676400448776 /* applicationIcon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = applicationIcon.icns; sourceTree = \"<group>\"; };\n\t\t4C31535920EB676400448776 /* applicationIcon.iconset */ = {isa = PBXFileReference; lastKnownFileType = folder.iconset; path = applicationIcon.iconset; sourceTree = \"<group>\"; };\n\t\t4C31535A20EB676400448776 /* applicationIconBirthday.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = applicationIconBirthday.icns; sourceTree = \"<group>\"; };\n\t\t4C31535F20EB676400448776 /* DIGreenBadgeLeft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIGreenBadgeLeft.png; sourceTree = \"<group>\"; };\n\t\t4C31536020EB676400448776 /* DIGreenBadgeRight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIGreenBadgeRight.png; sourceTree = \"<group>\"; };\n\t\t4C31536120EB676400448776 /* DIGreenBadgeCenter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIGreenBadgeCenter.png; sourceTree = \"<group>\"; };\n\t\t4C31537020EB676400448776 /* DIRedBadgeRight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIRedBadgeRight.png; sourceTree = \"<group>\"; };\n\t\t4C31537120EB676400448776 /* DIRedBadgeLeft.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIRedBadgeLeft.png; sourceTree = \"<group>\"; };\n\t\t4C31537220EB676400448776 /* DIRedBadgeCenter.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DIRedBadgeCenter.png; sourceTree = \"<group>\"; };\n\t\t4C31537820EB676400448776 /* MainWindowSegmentedControlUserTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = MainWindowSegmentedControlUserTemplate.pdf; sourceTree = \"<group>\"; };\n\t\t4C31537920EB676400448776 /* MainWindowSpotlightIconTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = MainWindowSpotlightIconTemplate.pdf; sourceTree = \"<group>\"; };\n\t\t4C31537B20EB676400448776 /* ErroneousTextFieldValueIndicator.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = ErroneousTextFieldValueIndicator.tif; sourceTree = \"<group>\"; };\n\t\t4C31537E20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31537F20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31538220EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = VibrantDarkServerListViewPrivateMessageUserIconActive.tif; sourceTree = \"<group>\"; };\n\t\t4C31538320EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = VibrantLightServerListViewPrivateMessageUserIconActive.tif; sourceTree = \"<group>\"; };\n\t\t4C31538420EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = VibrantLightServerListViewPrivateMessageUserIconInactive.tif; sourceTree = \"<group>\"; };\n\t\t4C31538520EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31538620EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = VibrantDarkServerListViewPrivateMessageUserIconInactive.tif; sourceTree = \"<group>\"; };\n\t\t4C31538720EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = \"VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif\"; sourceTree = \"<group>\"; };\n\t\t4C31539F20EB676400448776 /* IRCCommandIndexRemoteData.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = IRCCommandIndexRemoteData.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A020EB676400448776 /* IRCCommandIndexLocalData.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = IRCCommandIndexLocalData.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A120EB676400448776 /* TemplateLineTypes.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = TemplateLineTypes.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A220EB676400448776 /* IRCNetworks.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = IRCNetworks.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A420EB676400448776 /* StaticStore.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = StaticStore.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A520EB676400448776 /* RegisteredUserDefaults.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = RegisteredUserDefaults.plist; sourceTree = \"<group>\"; };\n\t\t4C3153A620EB676400448776 /* RegisteredUserDefaultsInContainer.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = RegisteredUserDefaultsInContainer.plist; sourceTree = \"<group>\"; };\n\t\t4C3154B720EB685700448776 /* Textual App.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual App.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154B820EB685700448776 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C3154B920EB685700448776 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154BA20EB685700448776 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154BB20EB685700448776 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154BC20EB685700448776 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154BD20EB685700448776 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154CA20EB685700448776 /* Textual App.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual App.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154CB20EB685700448776 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C3154CC20EB685700448776 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154CD20EB685700448776 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154CE20EB685700448776 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154CF20EB685700448776 /* Foundation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C3154D020EB685700448776 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154D120EB685700448776 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154D220EB685700448776 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154D320EB685700448776 /* Code Signing Identity.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Code Signing Identity.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154DF20EB685700448776 /* Textual App.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual App.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E020EB685700448776 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C3154E120EB685700448776 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E220EB685700448776 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E320EB685700448776 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E420EB685700448776 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E520EB685700448776 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C3154E720EB68A900448776 /* Standard Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = \"Standard Release.entitlements\"; sourceTree = \"<group>\"; };\n\t\t4C3154E820EB68A900448776 /* Debug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Debug.entitlements; sourceTree = \"<group>\"; };\n\t\t4C315EE72C36581A001A16B4 /* KeysExcludedFromExport.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = KeysExcludedFromExport.plist; sourceTree = \"<group>\"; };\n\t\t4C315EE82C36581A001A16B4 /* PreferenceKeyMasterList.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = PreferenceKeyMasterList.plist; sourceTree = \"<group>\"; };\n\t\t4C33341B20CC471A00ACB9AD /* Bundled Scripts */ = {isa = PBXFileReference; lastKnownFileType = folder; path = \"Bundled Scripts\"; sourceTree = \"<group>\"; };\n\t\t4C33342020CC475300ACB9AD /* Bundled Styles */ = {isa = PBXFileReference; lastKnownFileType = folder; path = \"Bundled Styles\"; sourceTree = \"<group>\"; };\n\t\t4C46CCBC1580469E00846B64 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };\n\t\t4C46CCC01580469E00846B64 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };\n\t\t4C46CCC11580469E00846B64 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };\n\t\t4C46CCC21580469E00846B64 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };\n\t\t4C48B46320E4D06900CF5F84 /* MergeSwift.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = MergeSwift.sh; path = \"Build Scripts/MergeSwift.sh\"; sourceTree = \"<group>\"; };\n\t\t4C4A0D6C1C973E9000064A23 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = \"Application Properties/Info.plist\"; sourceTree = \"<group>\"; };\n\t\t4C51327720F76E980033B703 /* TLOLocalization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TLOLocalization.swift; path = ../../../Shared/Library/TLOLocalization.swift; sourceTree = \"<group>\"; };\n\t\t4C52379215C18F6700414852 /* Style Default Templates */ = {isa = PBXFileReference; lastKnownFileType = folder; path = \"Style Default Templates\"; sourceTree = \"<group>\"; };\n\t\t4C5274E020F8D78700B18F9D /* IRCConnectionErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRCConnectionErrors.h; path = ../../../Shared/Headers/IRCConnectionErrors.h; sourceTree = \"<group>\"; };\n\t\t4C5274E520F8D7CD00B18F9D /* IRCConnectionErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IRCConnectionErrors.m; path = ../../../Shared/IRC/IRCConnectionErrors.m; sourceTree = \"<group>\"; };\n\t\t4C58B570186011AC00834882 /* Acknowledgements.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; name = Acknowledgements.pdf; path = ../../Acknowledgements.pdf; sourceTree = SOURCE_ROOT; };\n\t\t4C5BA4E616F1302F00A96CA2 /* Textual.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Textual.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C761BAE1E155CB100A505B7 /* BuildServices.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = BuildServices.sh; path = \"Build Scripts/BuildServices.sh\"; sourceTree = \"<group>\"; };\n\t\t4C7961C6267D25B400D37F07 /* UpdateFeatureFlags.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = UpdateFeatureFlags.sh; path = \"Build Scripts/UpdateFeatureFlags.sh\"; sourceTree = \"<group>\"; };\n\t\t4C83B9101BA9BEB800BD7718 /* Chat Filters.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = \"Chat Filters.bundle\"; path = \"../../.tmp/SharedBuildProducts-Extensions/Chat Filters.bundle\"; sourceTree = SOURCE_ROOT; };\n\t\t4C8878032C33706E0016DB98 /* TPCSandboxMigration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCSandboxMigration.m; sourceTree = \"<group>\"; };\n\t\t4C8878062C3371470016DB98 /* TPCSandboxMigrationPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCSandboxMigrationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EncryptionKit.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/EncryptionKit.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4C8F3FD62C31AF6E00118AAF /* THOPluginManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THOPluginManager.h; sourceTree = \"<group>\"; };\n\t\t4C8F3FDB2C31B15200118AAF /* THOPluginItemLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = THOPluginItemLogging.m; sourceTree = \"<group>\"; };\n\t\t4C956893194A8862003D97FD /* Smiley Converter.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = \"Smiley Converter.bundle\"; path = \"../../.tmp/SharedBuildProducts-Extensions/Smiley Converter.bundle\"; sourceTree = SOURCE_ROOT; };\n\t\t4C9A1D921836E6A100C14835 /* User Insights.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = \"User Insights.bundle\"; path = \"../../.tmp/SharedBuildProducts-Extensions/User Insights.bundle\"; sourceTree = SOURCE_ROOT; };\n\t\t4C9A1D931836E6A100C14835 /* System Info.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = \"System Info.bundle\"; path = \"../../.tmp/SharedBuildProducts-Extensions/System Info.bundle\"; sourceTree = SOURCE_ROOT; };\n\t\t4C9A1D941836E6A100C14835 /* ZNC Additions.bundle */ = {isa = PBXFileReference; lastKnownFileType = \"wrapper.plug-in\"; name = \"ZNC Additions.bundle\"; path = \"../../.tmp/SharedBuildProducts-Extensions/ZNC Additions.bundle\"; sourceTree = SOURCE_ROOT; };\n\t\t4CA8EC621B63C2970087BF72 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };\n\t\t4CAB27502537EE43009B1F07 /* IRCChannelMemberList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRCChannelMemberList.m; sourceTree = \"<group>\"; };\n\t\t4CAB27562537EE66009B1F07 /* IRCChannelMemberListPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCChannelMemberListPrivate.h; sourceTree = \"<group>\"; };\n\t\t4CAB275D2537F71B009B1F07 /* IRCChannelMemberList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCChannelMemberList.h; sourceTree = \"<group>\"; };\n\t\t4CAB2764253863BF009B1F07 /* IRCChannelMemberListController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRCChannelMemberListController.m; sourceTree = \"<group>\"; };\n\t\t4CAB276A253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCChannelMemberListControllerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4CB638CB2D45A06C002B2CC3 /* FeatureFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FeatureFlags.h; path = \"../../.tmp/Build Headers/FeatureFlags.h\"; sourceTree = SOURCE_ROOT; };\n\t\t4CB873D622B4A497005AB046 /* TDCPreferencesUserStyleSheetPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDCPreferencesUserStyleSheetPrivate.h; sourceTree = \"<group>\"; };\n\t\t4CB873DB22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDCPreferencesUserStyleSheet.m; sourceTree = \"<group>\"; };\n\t\t4CC4A7371F8A1404008FF15F /* GRMustache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GRMustache.framework; path = \"../../Frameworks/Static Libraries/Libraries/GRMustache.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CC70202171E1CB400BDFAE0 /* BuildConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BuildConfig.h; path = \"../../.tmp/Build Headers/BuildConfig.h\"; sourceTree = SOURCE_ROOT; };\n\t\t4CCD93FC1CA7291300335381 /* JavaScript */ = {isa = PBXFileReference; lastKnownFileType = folder; path = JavaScript; sourceTree = \"<group>\"; };\n\t\t4CCE521A18C7BE0600D49601 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };\n\t\t4CD6F7BB1CA7747600842597 /* ExportArchive.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = ExportArchive.sh; path = \"Build Scripts/ExportArchive.sh\"; sourceTree = \"<group>\"; };\n\t\t4CEFEDAF22B4B6E8002CEE19 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TDCPreferencesUserStyleSheet.strings; sourceTree = \"<group>\"; };\n\t\t4CF4D6B619837C1700FB5AF0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };\n\t\t4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AutoHyperlinks.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/AutoHyperlinks.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t5D9B8EB6170A0EB400919CB0 /* BuildFrameworks.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = BuildFrameworks.sh; path = \"Build Scripts/BuildFrameworks.sh\"; sourceTree = \"<group>\"; };\n\t\t5D9B8EB8170A0EB400919CB0 /* UpdateVersionInfo.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = UpdateVersionInfo.sh; path = \"Build Scripts/UpdateVersionInfo.sh\"; sourceTree = \"<group>\"; };\n\t\t5D9B8EB9170A10F200919CB0 /* BuildExtensions.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; name = BuildExtensions.sh; path = \"Build Scripts/BuildExtensions.sh\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4C1DC54F1580420500A47BC9 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E48820EC542C0055D09A /* AudioToolbox.framework in Frameworks */,\n\t\t\t\t4C06E48920EC542C0055D09A /* Cocoa.framework in Frameworks */,\n\t\t\t\t4C06E48A20EC542C0055D09A /* CoreServices.framework in Frameworks */,\n\t\t\t\t4C06E48C20EC542C0055D09A /* IOKit.framework in Frameworks */,\n\t\t\t\t4C06E48E20EC542C0055D09A /* QuartzCore.framework in Frameworks */,\n\t\t\t\t4C2F42062C3F4218000D962D /* UserNotifications.framework in Frameworks */,\n\t\t\t\t4C06E48F20EC542C0055D09A /* Security.framework in Frameworks */,\n\t\t\t\t4C06E49220EC542C0055D09A /* SystemConfiguration.framework in Frameworks */,\n\t\t\t\t4C06E49320EC542C0055D09A /* WebKit.framework in Frameworks */,\n\t\t\t\t4C06E48120EC54260055D09A /* AutoHyperlinks.framework in Frameworks */,\n\t\t\t\t4C06E48220EC54260055D09A /* CocoaExtensions.framework in Frameworks */,\n\t\t\t\t4C06E48320EC54260055D09A /* EncryptionKit.framework in Frameworks */,\n\t\t\t\t4C06E48420EC54260055D09A /* GRMustache.framework in Frameworks */,\n\t\t\t\t4C06E48720EC54260055D09A /* Sparkle.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C5BA45716F1302F00A96CA2 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E42920EC53620055D09A /* AudioToolbox.framework in Frameworks */,\n\t\t\t\t4C06E43B20EC539E0055D09A /* GRMustache.framework in Frameworks */,\n\t\t\t\t4C06E42A20EC53620055D09A /* Cocoa.framework in Frameworks */,\n\t\t\t\t4C06E42B20EC53620055D09A /* CoreServices.framework in Frameworks */,\n\t\t\t\t4C06E43520EC539E0055D09A /* AutoHyperlinks.framework in Frameworks */,\n\t\t\t\t4C2F42052C3F4218000D962D /* UserNotifications.framework in Frameworks */,\n\t\t\t\t4C06E42D20EC53620055D09A /* IOKit.framework in Frameworks */,\n\t\t\t\t4C06E44120EC539E0055D09A /* Sparkle.framework in Frameworks */,\n\t\t\t\t4C06E43920EC539E0055D09A /* EncryptionKit.framework in Frameworks */,\n\t\t\t\t4C06E42F20EC53620055D09A /* QuartzCore.framework in Frameworks */,\n\t\t\t\t4C06E43020EC53620055D09A /* Security.framework in Frameworks */,\n\t\t\t\t4C06E43320EC53620055D09A /* SystemConfiguration.framework in Frameworks */,\n\t\t\t\t4C06E43720EC539E0055D09A /* CocoaExtensions.framework in Frameworks */,\n\t\t\t\t4C06E43420EC53620055D09A /* WebKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4C06E13620EC4AC40055D09A /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17B20EC4AC40055D09A /* Appearance */,\n\t\t\t\t4C06E17120EC4AC40055D09A /* TDCAboutDialog.xib */,\n\t\t\t\t4C06E16720EC4AC40055D09A /* TDCAddressBookSheet.xib */,\n\t\t\t\t4C06E14920EC4AC40055D09A /* TDCChannelBanListSheet.xib */,\n\t\t\t\t4C06E15F20EC4AC40055D09A /* TDCChannelInviteSheet.xib */,\n\t\t\t\t4C06E14120EC4AC40055D09A /* TDCChannelModifyModesSheet.xib */,\n\t\t\t\t4C06E16F20EC4AC40055D09A /* TDCChannelModifyTopicSheet.xib */,\n\t\t\t\t4C06E14B20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib */,\n\t\t\t\t4C06E14320EC4AC40055D09A /* TDCChannelSpotlightController.xib */,\n\t\t\t\t4C06E14520EC4AC40055D09A /* TDCFileTransferDialog.xib */,\n\t\t\t\t4C06E17320EC4AC40055D09A /* TDCHighlightEntrySheet.xib */,\n\t\t\t\t4C06E17720EC4AC40055D09A /* TDCLicenseManagerDialog.xib */,\n\t\t\t\t4C06E14D20EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib */,\n\t\t\t\t4C06E17920EC4AC40055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib */,\n\t\t\t\t4C06E15B20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib */,\n\t\t\t\t4C06E16B20EC4AC40055D09A /* TDCLicenseUpgradeDialog.xib */,\n\t\t\t\t4C06E15120EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib */,\n\t\t\t\t4C06E16120EC4AC40055D09A /* TDCNicknameColorSheet.xib */,\n\t\t\t\t4C06E15D20EC4AC40055D09A /* TDCPreferences.xib */,\n\t\t\t\t4C17305222B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib */,\n\t\t\t\t4C06E16520EC4AC40055D09A /* TDCProgressIndicatorSheet.xib */,\n\t\t\t\t4C06E16D20EC4AC40055D09A /* TDCServerChangeNicknameSheet.xib */,\n\t\t\t\t4C06E14720EC4AC40055D09A /* TDCServerChannelListDialog.xib */,\n\t\t\t\t4C06E13F20EC4AC40055D09A /* TDCServerEndpointListSheet.xib */,\n\t\t\t\t4C06E13D20EC4AC40055D09A /* TDCServerHighlightListSheet.xib */,\n\t\t\t\t4C06E13920EC4AC40055D09A /* TDCServerPropertiesSheet.xib */,\n\t\t\t\t4C06E16320EC4AC40055D09A /* TDCWelcomeSheet.xib */,\n\t\t\t\t4C06E16920EC4AC40055D09A /* TVCAlert.xib */,\n\t\t\t\t4C06E15520EC4AC40055D09A /* TVCChannelSelectionView.xib */,\n\t\t\t\t4C06E17520EC4AC40055D09A /* TVCMainWindow.xib */,\n\t\t\t\t4C06E15920EC4AC40055D09A /* TVCNotificationConfigurationView.xib */,\n\t\t\t\t4C06E15720EC4AC40055D09A /* TXCMainMenu.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17B20EC4AC40055D09A /* Appearance */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E18120EC4AC40055D09A /* TDCChannelSpotlightAppearance.plist */,\n\t\t\t\t4C06E17E20EC4AC40055D09A /* TDCChannelSpotlightAppearanceTemplate.plist */,\n\t\t\t\t4C06E18220EC4AC40055D09A /* TVCMainWindowAppearance.plist */,\n\t\t\t\t4C06E18520EC4AC40055D09A /* TVCMainWindowAppearanceTemplate.plist */,\n\t\t\t\t4C06E18320EC4AC40055D09A /* TVCMainWindowTextViewAppearance.plist */,\n\t\t\t\t4C06E18020EC4AC40055D09A /* TVCMainWindowTextViewAppearanceTemplate.plist */,\n\t\t\t\t4C06E17C20EC4AC40055D09A /* TVCMemberListAppearance.plist */,\n\t\t\t\t4C06E17F20EC4AC40055D09A /* TVCMemberListAppearanceTemplate.plist */,\n\t\t\t\t4C06E18420EC4AC40055D09A /* TVCServerListAppearance.plist */,\n\t\t\t\t4C06E17D20EC4AC40055D09A /* TVCServerListAppearanceTemplate.plist */,\n\t\t\t);\n\t\t\tpath = Appearance;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2A620EC4FF00055D09A /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B120EC4FF00055D09A /* Accessibility.strings */,\n\t\t\t\t4C06E2AF20EC4FF00055D09A /* BasicLanguage.strings */,\n\t\t\t\t4C06E2AB20EC4FF00055D09A /* CommonErrors.strings */,\n\t\t\t\t4C06E2C120EC4FF00055D09A /* IRC.strings */,\n\t\t\t\t4C06E2C920EC4FF00055D09A /* Notifications.strings */,\n\t\t\t\t4C06E2A920EC4FF00055D09A /* OffTheRecord.strings */,\n\t\t\t\t4C06E2A720EC4FF00055D09A /* Prompts.strings */,\n\t\t\t\t4C06E2BD20EC4FF00055D09A /* TDCAboutDialog.strings */,\n\t\t\t\t4C06E2D520EC4FF00055D09A /* TDCAddressBookSheet.strings */,\n\t\t\t\t4C06E2B520EC4FF00055D09A /* TDCChannelBanListSheet.strings */,\n\t\t\t\t4C06E2BB20EC4FF00055D09A /* TDCChannelInviteSheet.strings */,\n\t\t\t\t4C06E2C520EC4FF00055D09A /* TDCChannelModifyModesSheet.strings */,\n\t\t\t\t4C06E2D920EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings */,\n\t\t\t\t4C06E2B320EC4FF00055D09A /* TDCChannelPropertiesSheet.strings */,\n\t\t\t\t4C06E2D320EC4FF00055D09A /* TDCChannelSpotlightController.strings */,\n\t\t\t\t4C06E2B920EC4FF00055D09A /* TDCFileTransferDialog.strings */,\n\t\t\t\t4C06E2D720EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings */,\n\t\t\t\t4C06E2B720EC4FF00055D09A /* TDCPreferencesController.strings */,\n\t\t\t\t4CEFEDAE22B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings */,\n\t\t\t\t4C06E2D120EC4FF00055D09A /* TDCServerChannelListDialog.strings */,\n\t\t\t\t4C06E2CF20EC4FF00055D09A /* TDCServerEndpointListSheet.strings */,\n\t\t\t\t4C06E2BF20EC4FF00055D09A /* TDCServerPropertiesSheet.strings */,\n\t\t\t\t4C06E2C320EC4FF00055D09A /* TLOLicenseManager.strings */,\n\t\t\t\t4C06E2C720EC4FF00055D09A /* TVCMainWindow.strings */,\n\t\t\t\t4C06E2CD20EC4FF00055D09A /* TVCNotificationConfigurationView.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E34D20EC50D40055D09A /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E34E20EC50D40055D09A /* ICLPayloadLocal.m */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E35A20EC51370055D09A /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E36920EC51370055D09A /* Headers */,\n\t\t\t\t4C06E36020EC51370055D09A /* Library */,\n\t\t\t\t4C06E38A20EC51370055D09A /* Services */,\n\t\t\t\t4C06E38420EC51370055D09A /* Views */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tpath = ../Shared;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C06E36020EC51370055D09A /* Library */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E36120EC51370055D09A /* External Libraries */,\n\t\t\t);\n\t\t\tpath = Library;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E36120EC51370055D09A /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E36220EC51370055D09A /* Sockets */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E36220EC51370055D09A /* Sockets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E36320EC51370055D09A /* GCDAsyncSocket.m */,\n\t\t\t\t4C06E36520EC51370055D09A /* GCDAsyncSocketExtensions.m */,\n\t\t\t);\n\t\t\tpath = Sockets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E36920EC51370055D09A /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E37520EC51370055D09A /* ICLPayload.h */,\n\t\t\t\t4C06E36A20EC51370055D09A /* External Libraries */,\n\t\t\t\t4C06E37120EC51370055D09A /* Internal */,\n\t\t\t\t4C06E37720EC51370055D09A /* Private */,\n\t\t\t\t4C06E37E20EC51370055D09A /* Services */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E36A20EC51370055D09A /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E36C20EC51370055D09A /* GCDAsyncSocket.h */,\n\t\t\t\t4C06E36B20EC51370055D09A /* GCDAsyncSocketExtensions.h */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E37120EC51370055D09A /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E37220EC51370055D09A /* ICLPayloadInternal.h */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E37720EC51370055D09A /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E41020EC52240055D09A /* TVCLogLineXPCPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E37E20EC51370055D09A /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E37F20EC51370055D09A /* RCMConnectionManagerProtocol.h */,\n\t\t\t\t4C06E38020EC51370055D09A /* ICLInlineContentProtocol.h */,\n\t\t\t\t4C06E38120EC51370055D09A /* HLSHistoricLogProtocol.h */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E38420EC51370055D09A /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E38520EC51370055D09A /* Channel View */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E38520EC51370055D09A /* Channel View */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E38620EC51370055D09A /* TVCLogLineXPC.m */,\n\t\t\t);\n\t\t\tpath = \"Channel View\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E38A20EC51370055D09A /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E38B20EC51370055D09A /* ICLPayload.m */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1DC5471580420500A47BC9 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31511220EB673E00448776 /* Classes */,\n\t\t\t\t4C3152EC20EB676400448776 /* Resources */,\n\t\t\t\t4C1DC5551580420500A47BC9 /* Frameworks */,\n\t\t\t\t4C1DC5531580420500A47BC9 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1DC5531580420500A47BC9 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1DC5521580420500A47BC9 /* Textual.app */,\n\t\t\t\t4C5BA4E616F1302F00A96CA2 /* Textual.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1DC5551580420500A47BC9 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46CCCC158046BE00846B64 /* External Frameworks */,\n\t\t\t\t4C211D3F15BF1F5E00E218DA /* External Libraries */,\n\t\t\t\t4C46CCB91580469200846B64 /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C211D3F15BF1F5E00E218DA /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31511220EB673E00448776 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31529A20EB673E00448776 /* Controllers */,\n\t\t\t\t4C31526220EB673E00448776 /* Dialogs */,\n\t\t\t\t4C31516020EB673E00448776 /* Headers */,\n\t\t\t\t4C3152D920EB673E00448776 /* Helpers */,\n\t\t\t\t4C31512220EB673E00448776 /* IRC */,\n\t\t\t\t4C31514520EB673E00448776 /* Library */,\n\t\t\t\t4C31514320EB673E00448776 /* Others */,\n\t\t\t\t4C31511320EB673E00448776 /* Preferences */,\n\t\t\t\t4C06E34D20EC50D40055D09A /* Services */,\n\t\t\t\t4C06E35A20EC51370055D09A /* Shared */,\n\t\t\t\t4C3152A220EB673E00448776 /* Views */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31511320EB673E00448776 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31511E20EB673E00448776 /* Themes */,\n\t\t\t\t4C31511420EB673E00448776 /* TPCApplicationInfo.m */,\n\t\t\t\t4C31511A20EB673E00448776 /* TPCPathInfo.m */,\n\t\t\t\t4C06E28820EC4F000055D09A /* TPCPreferences.m */,\n\t\t\t\t4C31511520EB673E00448776 /* TPCPreferencesLocal.m */,\n\t\t\t\t4C31511620EB673E00448776 /* TPCPreferencesImportExport.m */,\n\t\t\t\t4C31512120EB673E00448776 /* TPCPreferencesReload.m */,\n\t\t\t\t4C06E28920EC4F000055D09A /* TPCPreferencesUserDefaults.m */,\n\t\t\t\t4C31511920EB673E00448776 /* TPCPreferencesUserDefaultsLocal.m */,\n\t\t\t\t4C31511820EB673E00448776 /* TPCResourceManager.m */,\n\t\t\t\t4C8878032C33706E0016DB98 /* TPCSandboxMigration.m */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31511E20EB673E00448776 /* Themes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31512020EB673E00448776 /* TPCTheme.m */,\n\t\t\t\t4C31511F20EB673E00448776 /* TPCThemeController.m */,\n\t\t\t);\n\t\t\tpath = Themes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31512220EB673E00448776 /* IRC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31512320EB673E00448776 /* IRCAddressBook.m */,\n\t\t\t\t4C31512B20EB673E00448776 /* IRCAddressBookMatchCache.m */,\n\t\t\t\t4C31513E20EB673E00448776 /* IRCAddressBookUserTracking.m */,\n\t\t\t\t4C31512820EB673E00448776 /* IRCChannel.m */,\n\t\t\t\t4C31512420EB673E00448776 /* IRCChannelConfig.m */,\n\t\t\t\t4CAB27502537EE43009B1F07 /* IRCChannelMemberList.m */,\n\t\t\t\t4CAB2764253863BF009B1F07 /* IRCChannelMemberListController.m */,\n\t\t\t\t4C31514020EB673E00448776 /* IRCChannelMode.m */,\n\t\t\t\t4C31513B20EB673E00448776 /* IRCClient.m */,\n\t\t\t\t4C31513C20EB673E00448776 /* IRCClientConfig.m */,\n\t\t\t\t4C31513820EB673E00448776 /* IRCClientRequestedCommands.m */,\n\t\t\t\t4C31513720EB673E00448776 /* IRCCommandIndex.m */,\n\t\t\t\t4C31512E20EB673E00448776 /* IRCConnection.m */,\n\t\t\t\t4C06E29C20EC4F880055D09A /* IRCConnectionConfig.m */,\n\t\t\t\t4C5274E520F8D7CD00B18F9D /* IRCConnectionErrors.m */,\n\t\t\t\t4C31513120EB673E00448776 /* IRCExtras.m */,\n\t\t\t\t4C31512620EB673E00448776 /* IRCHighlightLogEntry.m */,\n\t\t\t\t4C31512A20EB673E00448776 /* IRCHighlightMatchCondition.m */,\n\t\t\t\t4C31514120EB673E00448776 /* IRCISupportInfo.m */,\n\t\t\t\t4C31512D20EB673E00448776 /* IRCMessage.m */,\n\t\t\t\t4C31513F20EB673E00448776 /* IRCMessageBatch.m */,\n\t\t\t\t4C31513020EB673E00448776 /* IRCModeInfo.m */,\n\t\t\t\t4C31513920EB673E00448776 /* IRCNetworkList.m */,\n\t\t\t\t4C31512520EB673E00448776 /* IRCPrefix.m */,\n\t\t\t\t4C31512C20EB673E00448776 /* IRCSendingMessage.m */,\n\t\t\t\t4C31512920EB673E00448776 /* IRCServer.m */,\n\t\t\t\t4C31512F20EB673E00448776 /* IRCTimerCommand.m */,\n\t\t\t\t4C31514220EB673E00448776 /* IRCTreeItem.m */,\n\t\t\t\t4C31513A20EB673E00448776 /* IRCWorld.m */,\n\t\t\t\t4C31513220EB673E00448776 /* Users */,\n\t\t\t);\n\t\t\tpath = IRC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31513220EB673E00448776 /* Users */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31513D20EB673E00448776 /* IRCChannelUser.m */,\n\t\t\t\t4C31513320EB673E00448776 /* IRCUserRelations.m */,\n\t\t\t\t4C31513420EB673E00448776 /* IRCUser.m */,\n\t\t\t\t4C31513520EB673E00448776 /* IRCUserNicknameColorStyleGenerator.m */,\n\t\t\t\t4C31513620EB673E00448776 /* IRCUserPersistentStore.m */,\n\t\t\t);\n\t\t\tpath = Users;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514320EB673E00448776 /* Others */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31514420EB673E00448776 /* main.m */,\n\t\t\t);\n\t\t\tpath = Others;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514520EB673E00448776 /* Library */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31515E20EB673E00448776 /* Color Formatting */,\n\t\t\t\t4C31514620EB673E00448776 /* External Libraries */,\n\t\t\t\t4C31514C20EB673E00448776 /* License Manager */,\n\t\t\t\t4C31515320EB673E00448776 /* TLOEncryptionManager.m */,\n\t\t\t\t4C31515B20EB673E00448776 /* TLOFileLogger.m */,\n\t\t\t\t4C31515420EB673E00448776 /* TLOInputHistory.m */,\n\t\t\t\t4C31515620EB673E00448776 /* TLOInternetAddressLookup.m */,\n\t\t\t\t4C31514B20EB673E00448776 /* TLOKeyEventHandler.m */,\n\t\t\t\t4C31515520EB673E00448776 /* TLOLinkParser.swift */,\n\t\t\t\t4C06E29220EC4F570055D09A /* TLOLocalization.m */,\n\t\t\t\t4C51327720F76E980033B703 /* TLOLocalization.swift */,\n\t\t\t\t4C31515C20EB673E00448776 /* TLONicknameCompletionStatus.m */,\n\t\t\t\t4C31515D20EB673E00448776 /* TLONotificationConfiguration.m */,\n\t\t\t\t4C31514920EB673E00448776 /* TLONotificationController.m */,\n\t\t\t\t4C31515920EB673E00448776 /* TLOpenLink.swift */,\n\t\t\t\t4C31515820EB673E00448776 /* TLOSoundPlayer.m */,\n\t\t\t\t4C31515720EB673E00448776 /* TLOSpeechSynthesizer.m */,\n\t\t\t\t4C31515A20EB673E00448776 /* TLOSpokenNotification.m */,\n\t\t\t\t4C06E29320EC4F570055D09A /* TLOTimer.m */,\n\t\t\t);\n\t\t\tpath = Library;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514620EB673E00448776 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31514720EB673E00448776 /* Sockets */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514720EB673E00448776 /* Sockets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31514820EB673E00448776 /* OELReachability.m */,\n\t\t\t);\n\t\t\tpath = Sockets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514C20EB673E00448776 /* License Manager */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31514D20EB673E00448776 /* Standalone */,\n\t\t\t);\n\t\t\tpath = \"License Manager\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31514D20EB673E00448776 /* Standalone */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31514E20EB673E00448776 /* TLOLicenseManager.m */,\n\t\t\t\t4C31515020EB673E00448776 /* TLOLicenseManagerDownloader.m */,\n\t\t\t\t4C31514F20EB673E00448776 /* TLOLicenseManagerLastGen.m */,\n\t\t\t);\n\t\t\tpath = Standalone;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31515E20EB673E00448776 /* Color Formatting */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31515F20EB673E00448776 /* IRCColorFormat.m */,\n\t\t\t);\n\t\t\tpath = \"Color Formatting\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31516020EB673E00448776 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31516120EB673E00448776 /* External Libraries */,\n\t\t\t\t4C31518420EB673E00448776 /* Internal */,\n\t\t\t\t4C3151AB20EB673E00448776 /* Private */,\n\t\t\t\t4C31524120EB673E00448776 /* IRC.h */,\n\t\t\t\t4C3151A720EB673E00448776 /* IRCAddressBook.h */,\n\t\t\t\t4C31517620EB673E00448776 /* IRCAddressBookUserTracking.h */,\n\t\t\t\t4C31524B20EB673E00448776 /* IRCChannel.h */,\n\t\t\t\t4C3151A420EB673E00448776 /* IRCChannelConfig.h */,\n\t\t\t\t4CAB275D2537F71B009B1F07 /* IRCChannelMemberList.h */,\n\t\t\t\t4C31519A20EB673E00448776 /* IRCChannelMode.h */,\n\t\t\t\t4C31517920EB673E00448776 /* IRCChannelUser.h */,\n\t\t\t\t4C31517C20EB673E00448776 /* IRCClient.h */,\n\t\t\t\t4C31517F20EB673E00448776 /* IRCClientConfig.h */,\n\t\t\t\t4C31526120EB673E00448776 /* IRCColorFormat.h */,\n\t\t\t\t4C31517120EB673E00448776 /* IRCCommandIndex.h */,\n\t\t\t\t4C31526020EB673E00448776 /* IRCConnection.h */,\n\t\t\t\t4C06E24720EC4B970055D09A /* IRCConnectionConfig.h */,\n\t\t\t\t4C5274E020F8D78700B18F9D /* IRCConnectionErrors.h */,\n\t\t\t\t4C3151A120EB673E00448776 /* IRCHighlightLogEntry.h */,\n\t\t\t\t4C31524720EB673E00448776 /* IRCHighlightMatchCondition.h */,\n\t\t\t\t4C31519820EB673E00448776 /* IRCISupportInfo.h */,\n\t\t\t\t4C31525320EB673E00448776 /* IRCMessage.h */,\n\t\t\t\t4C31516C20EB673E00448776 /* IRCModeInfo.h */,\n\t\t\t\t4C31518120EB673E00448776 /* IRCNetworkList.h */,\n\t\t\t\t4C31516620EB673E00448776 /* IRCNumerics.h */,\n\t\t\t\t4C3151A520EB673E00448776 /* IRCPrefix.h */,\n\t\t\t\t4C31525520EB673E00448776 /* IRCSendingMessage.h */,\n\t\t\t\t4C31524620EB673E00448776 /* IRCServer.h */,\n\t\t\t\t4C31519720EB673E00448776 /* IRCTreeItem.h */,\n\t\t\t\t4C31524E20EB673E00448776 /* IRCUser.h */,\n\t\t\t\t4C31524F20EB673E00448776 /* IRCUserRelations.h */,\n\t\t\t\t4C31518020EB673E00448776 /* IRCWorld.h */,\n\t\t\t\t4C31519E20EB673E00448776 /* NSColorHelper.h */,\n\t\t\t\t4C31525820EB673E00448776 /* NSStringHelper.h */,\n\t\t\t\t4C31524320EB673E00448776 /* NSViewHelper.h */,\n\t\t\t\t4C06E26F20EC4E350055D09A /* StaticDefinitions.h */,\n\t\t\t\t4C31524920EB673E00448776 /* TDCAlert.h */,\n\t\t\t\t4C31516A20EB673E00448776 /* TDCInputPrompt.h */,\n\t\t\t\t4C31518220EB673E00448776 /* TDCSheetBase.h */,\n\t\t\t\t4C31525C20EB673E00448776 /* TDCWindowBase.h */,\n\t\t\t\t4C31525F20EB673E00448776 /* Textual.h */,\n\t\t\t\t4C31517720EB673E00448776 /* TextualApplication.h */,\n\t\t\t\t4C8F3FD62C31AF6E00118AAF /* THOPluginManager.h */,\n\t\t\t\t4C31517820EB673E00448776 /* THOPluginProtocol.h */,\n\t\t\t\t4C3151A620EB673E00448776 /* THOUnicodeHelper.h */,\n\t\t\t\t4C31524520EB673E00448776 /* TLOEncryptionManager.h */,\n\t\t\t\t4C31525B20EB673E00448776 /* TLOInternetAddressLookup.h */,\n\t\t\t\t4C3151A820EB673E00448776 /* TLOKeyEventHandler.h */,\n\t\t\t\t4C31519D20EB673E00448776 /* TLOLinkParser.h */,\n\t\t\t\t4C06E27720EC4E860055D09A /* TLOLocalization.h */,\n\t\t\t\t4C3151AA20EB673E00448776 /* TLONotificationController.h */,\n\t\t\t\t4C31517B20EB673E00448776 /* TLOpenLink.h */,\n\t\t\t\t4C31516420EB673E00448776 /* TLOSoundPlayer.h */,\n\t\t\t\t4C06E27420EC4E850055D09A /* TLOTimer.h */,\n\t\t\t\t4C31524020EB673E00448776 /* TPCApplicationInfo.h */,\n\t\t\t\t4C31517D20EB673E00448776 /* TPCPathInfo.h */,\n\t\t\t\t4C06E27620EC4E860055D09A /* TPCPreferences.h */,\n\t\t\t\t4C31524A20EB673E00448776 /* TPCPreferencesImportExport.h */,\n\t\t\t\t4C31516820EB673E00448776 /* TPCPreferencesLocal.h */,\n\t\t\t\t4C31519C20EB673E00448776 /* TPCPreferencesReload.h */,\n\t\t\t\t4C06E27520EC4E850055D09A /* TPCPreferencesUserDefaults.h */,\n\t\t\t\t4C31519F20EB673E00448776 /* TPCPreferencesUserDefaultsLocal.h */,\n\t\t\t\t4C31516520EB673E00448776 /* TPCResourceManager.h */,\n\t\t\t\t4C31517020EB673E00448776 /* TPCTheme.h */,\n\t\t\t\t4C31517220EB673E00448776 /* TPCThemeController.h */,\n\t\t\t\t4C31516F20EB673E00448776 /* TVCAlert.h */,\n\t\t\t\t4C31516E20EB673E00448776 /* TVCAppearance.h */,\n\t\t\t\t4C31517E20EB673E00448776 /* TVCAutoExpandingTextField.h */,\n\t\t\t\t4C3151A320EB673E00448776 /* TVCAutoExpandingTokenField.h */,\n\t\t\t\t4C3151A220EB673E00448776 /* TVCBasicTableView.h */,\n\t\t\t\t4C31519620EB673E00448776 /* TVCChannelSelectionViewController.h */,\n\t\t\t\t4C31525620EB673E00448776 /* TVCLogController.h */,\n\t\t\t\t4C31519920EB673E00448776 /* TVCLogLine.h */,\n\t\t\t\t4C31525420EB673E00448776 /* TVCLogRenderer.h */,\n\t\t\t\t4C31524D20EB673E00448776 /* TVCLogView.h */,\n\t\t\t\t4C31524C20EB673E00448776 /* TVCMainWindow.h */,\n\t\t\t\t4C31525A20EB673E00448776 /* TVCMainWindowAppearance.h */,\n\t\t\t\t4C31525720EB673E00448776 /* TVCMainWindowLoadingScreen.h */,\n\t\t\t\t4C31525220EB673E00448776 /* TVCMainWindowSplitView.h */,\n\t\t\t\t4C31525920EB673E00448776 /* TVCMainWindowTextView.h */,\n\t\t\t\t4C31524220EB673E00448776 /* TVCMainWindowTextViewAppearance.h */,\n\t\t\t\t4C31516920EB673E00448776 /* TVCMemberList.h */,\n\t\t\t\t4C31525120EB673E00448776 /* TVCMemberListAppearance.h */,\n\t\t\t\t4C31516720EB673E00448776 /* TVCServerList.h */,\n\t\t\t\t4C31516D20EB673E00448776 /* TVCServerListAppearance.h */,\n\t\t\t\t4C31524420EB673E00448776 /* TVCTextViewWithIRCFormatter.h */,\n\t\t\t\t4C31525020EB673E00448776 /* TVCValidatedComboBox.h */,\n\t\t\t\t4C31525E20EB673E00448776 /* TVCValidatedTextField.h */,\n\t\t\t\t4C31517320EB673E00448776 /* TXAppearance.h */,\n\t\t\t\t4C31517420EB673E00448776 /* TXAppearanceHelper.h */,\n\t\t\t\t4C31524820EB673E00448776 /* TXGlobalModels.h */,\n\t\t\t\t4C31517A20EB673E00448776 /* TXMasterController.h */,\n\t\t\t\t4C31519B20EB673E00448776 /* TXMenuController.h */,\n\t\t\t\t4C31516B20EB673E00448776 /* TXSharedApplication.h */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31516120EB673E00448776 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31516220EB673E00448776 /* GTMEncodeHTML.h */,\n\t\t\t\t4C31516320EB673E00448776 /* OELReachability.h */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31518420EB673E00448776 /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31518720EB673E00448776 /* IRCAddressBookInternal.h */,\n\t\t\t\t4C31518C20EB673E00448776 /* IRCChannelConfigInternal.h */,\n\t\t\t\t4C31518F20EB673E00448776 /* IRCChannelUserInternal.h */,\n\t\t\t\t4C31518D20EB673E00448776 /* IRCClientConfigInternal.h */,\n\t\t\t\t4C06E25B20EC4BBD0055D09A /* IRCConnectionConfigInternal.h */,\n\t\t\t\t4C31519420EB673E00448776 /* IRCHighlightLogEntryInternal.h */,\n\t\t\t\t4C31519520EB673E00448776 /* IRCHighlightMatchConditionInternal.h */,\n\t\t\t\t4C31519120EB673E00448776 /* IRCMessageInternal.h */,\n\t\t\t\t4C31519020EB673E00448776 /* IRCModeInfoInternal.h */,\n\t\t\t\t4C31518B20EB673E00448776 /* IRCPrefixInternal.h */,\n\t\t\t\t4C31518520EB673E00448776 /* IRCServerInternal.h */,\n\t\t\t\t4C31518620EB673E00448776 /* IRCUserInternal.h */,\n\t\t\t\t4C31518820EB673E00448776 /* TDCChannelPropertiesSheetInternal.h */,\n\t\t\t\t4C31518920EB673E00448776 /* TDCChannelSpotlightAppearanceInternal.h */,\n\t\t\t\t4C31519320EB673E00448776 /* TDCChannelSpotlightControllerInternal.h */,\n\t\t\t\t4C31519220EB673E00448776 /* TDCFileTransferDialogInternal.h */,\n\t\t\t\t4C31518E20EB673E00448776 /* TVCLogLineInternal.h */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3151AB20EB673E00448776 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E41520EC52D50055D09A /* ICLPayloadLocalPrivate.h */,\n\t\t\t\t4C3151E020EB673E00448776 /* IRCAddressBookMatchCachePrivate.h */,\n\t\t\t\t4C3151EA20EB673E00448776 /* IRCAddressBookUserTrackingPrivate.h */,\n\t\t\t\t4C31522120EB673E00448776 /* IRCChannelConfigPrivate.h */,\n\t\t\t\t4CAB276A253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h */,\n\t\t\t\t4CAB27562537EE66009B1F07 /* IRCChannelMemberListPrivate.h */,\n\t\t\t\t4C31522920EB673E00448776 /* IRCChannelModePrivate.h */,\n\t\t\t\t4C31520220EB673E00448776 /* IRCChannelPrivate.h */,\n\t\t\t\t4C31521120EB673E00448776 /* IRCChannelUserPrivate.h */,\n\t\t\t\t4C3151C720EB673E00448776 /* IRCClientConfigPrivate.h */,\n\t\t\t\t4C31520B20EB673E00448776 /* IRCClientPrivate.h */,\n\t\t\t\t4C31523F20EB673E00448776 /* IRCClientRequestedCommandsPrivate.h */,\n\t\t\t\t4C3151B120EB673E00448776 /* IRCColorFormatPrivate.h */,\n\t\t\t\t4C3151AE20EB673E00448776 /* IRCCommandIndexPrivate.h */,\n\t\t\t\t4C31522020EB673E00448776 /* IRCConnectionPrivate.h */,\n\t\t\t\t4C3151F620EB673E00448776 /* IRCExtrasPrivate.h */,\n\t\t\t\t4C3151B220EB673E00448776 /* IRCHighlightLogEntryPrivate.h */,\n\t\t\t\t4C3151ED20EB673E00448776 /* IRCISupportInfoPrivate.h */,\n\t\t\t\t4C3151E120EB673E00448776 /* IRCMessageBatchPrivate.h */,\n\t\t\t\t4C3151BE20EB673E00448776 /* IRCMessagePrivate.h */,\n\t\t\t\t4C3151C120EB673E00448776 /* IRCServerPrivate.h */,\n\t\t\t\t4C3151B820EB673E00448776 /* IRCTimerCommandPrivate.h */,\n\t\t\t\t4C3151E320EB673E00448776 /* IRCTreeItemPrivate.h */,\n\t\t\t\t4C3151FF20EB673E00448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h */,\n\t\t\t\t4C3151BC20EB673E00448776 /* IRCUserPersistentStorePrivate.h */,\n\t\t\t\t4C3151E720EB673E00448776 /* IRCUserPrivate.h */,\n\t\t\t\t4C3151B420EB673E00448776 /* IRCUserRelationsPrivate.h */,\n\t\t\t\t4C3151DB20EB673E00448776 /* IRCWorldPrivate.h */,\n\t\t\t\t4C06E26220EC4C560055D09A /* NSObjectHelperPrivate.h */,\n\t\t\t\t4C3151E220EB673E00448776 /* NSTableVIewHelperPrivate.h */,\n\t\t\t\t4C31521420EB673E00448776 /* NSViewHelperPrivate.h */,\n\t\t\t\t4C31520A20EB673E00448776 /* SwiftBridgingHeaderPrivate.h */,\n\t\t\t\t4C31522820EB673E00448776 /* TDCAboutDialogPrivate.h */,\n\t\t\t\t4C3151BA20EB673E00448776 /* TDCAddressBookSheetPrivate.h */,\n\t\t\t\t4C3151B920EB673E00448776 /* TDCChannelBanListSheetPrivate.h */,\n\t\t\t\t4C31523E20EB673E00448776 /* TDCChannelInviteSheetPrivate.h */,\n\t\t\t\t4C31523D20EB673E00448776 /* TDCChannelModifyModesSheetPrivate.h */,\n\t\t\t\t4C3151E820EB673E00448776 /* TDCChannelModifyTopicSheetPrivate.h */,\n\t\t\t\t4C3151B520EB673E00448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h */,\n\t\t\t\t4C31523B20EB673E00448776 /* TDCChannelPropertiesSheetPrivate.h */,\n\t\t\t\t4C31521B20EB673E00448776 /* TDCChannelSpotlightAppearancePrivate.h */,\n\t\t\t\t4C31522B20EB673E00448776 /* TDCChannelSpotlightControllerPrivate.h */,\n\t\t\t\t4C3151D120EB673E00448776 /* TDCChannelSpotlightControlsPrivate.h */,\n\t\t\t\t4C3151D920EB673E00448776 /* TDCChannelSpotlightSearchResultPrivate.h */,\n\t\t\t\t4C31522C20EB673E00448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h */,\n\t\t\t\t4C31521220EB673E00448776 /* TDCFileTransferDialogPrivate.h */,\n\t\t\t\t4C3151BD20EB673E00448776 /* TDCFileTransferDialogTableCellPrivate.h */,\n\t\t\t\t4C31520720EB673E00448776 /* TDCFileTransferDialogTransferControllerPrivate.h */,\n\t\t\t\t4C3151D720EB673E00448776 /* TDCHighlightEntrySheetPrivate.h */,\n\t\t\t\t4C31523720EB673E00448776 /* TDCLicenseManagerDialogPrivate.h */,\n\t\t\t\t4C3151FD20EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h */,\n\t\t\t\t4C31523C20EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h */,\n\t\t\t\t4C31520E20EB673E00448776 /* TDCLicenseUpgradeActivateSheetPrivate.h */,\n\t\t\t\t4C3151D320EB673E00448776 /* TDCLicenseUpgradeCommonActionsPrivate.h */,\n\t\t\t\t4C3151CC20EB673E00448776 /* TDCLicenseUpgradeDialogPrivate.h */,\n\t\t\t\t4C3151FC20EB673E00448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h */,\n\t\t\t\t4C3151E620EB673E00448776 /* TDCNicknameColorSheetPrivate.h */,\n\t\t\t\t4C3151F120EB673E00448776 /* TDCPreferencesControllerPrivate.h */,\n\t\t\t\t4C31523920EB673E00448776 /* TDCPreferencesNotificationConfigurationPrivate.h */,\n\t\t\t\t4CB873D622B4A497005AB046 /* TDCPreferencesUserStyleSheetPrivate.h */,\n\t\t\t\t4C3151DC20EB673E00448776 /* TDCProgressIndicatorSheetPrivate.h */,\n\t\t\t\t4C3151EF20EB673E00448776 /* TDCServerChangeNicknameSheetPrivate.h */,\n\t\t\t\t4C3151C320EB673E00448776 /* TDCServerChannelListDialogPrivate.h */,\n\t\t\t\t4C31522F20EB673E00448776 /* TDCServerEndpointListSheetPrivate.h */,\n\t\t\t\t4C3151EB20EB673E00448776 /* TDCServerEndpointListSheetTablePrivate.h */,\n\t\t\t\t4C31520F20EB673E00448776 /* TDCServerHighlightListSheetPrivate.h */,\n\t\t\t\t4C3151E920EB673E00448776 /* TDCServerPropertiesSheetPrivate.h */,\n\t\t\t\t4C3151FB20EB673E00448776 /* TDCSharedProtocolDefinitionsPrivate.h */,\n\t\t\t\t4C3151C420EB673E00448776 /* TDCWelcomeSheetPrivate.h */,\n\t\t\t\t4C3151D820EB673E00448776 /* TextualPrivate.h */,\n\t\t\t\t4C31521620EB673E00448776 /* THOPluginDispatcherPrivate.h */,\n\t\t\t\t4C31521920EB673E00448776 /* THOPluginItemPrivate.h */,\n\t\t\t\t4C3151CF20EB673E00448776 /* THOPluginManagerPrivate.h */,\n\t\t\t\t4C3151B320EB673E00448776 /* THOPluginProtocolPrivate.h */,\n\t\t\t\t4C31520120EB673E00448776 /* TLOEncryptionManagerPrivate.h */,\n\t\t\t\t4C3151F220EB673E00448776 /* TLOFileLoggerPrivate.h */,\n\t\t\t\t4C3151DA20EB673E00448776 /* TLOInputHistoryPrivate.h */,\n\t\t\t\t4C31520920EB673E00448776 /* TLOLicenseManagerDownloaderPrivate.h */,\n\t\t\t\t4C31523320EB673E00448776 /* TLOLicenseManagerLastGenPrivate.h */,\n\t\t\t\t4C31522220EB673E00448776 /* TLOLicenseManagerPrivate.h */,\n\t\t\t\t4C31523520EB673E00448776 /* TLONicknameCompletionStatusPrivate.h */,\n\t\t\t\t4C31523420EB673E00448776 /* TLONotificationConfigurationPrivate.h */,\n\t\t\t\t4C3151AF20EB673E00448776 /* TLONotificationControllerPrivate.h */,\n\t\t\t\t4C31523620EB673E00448776 /* TLOSpeechSynthesizerPrivate.h */,\n\t\t\t\t4C31520320EB673E00448776 /* TLOSpokenNotificationPrivate.h */,\n\t\t\t\t4C3151EE20EB673E00448776 /* TPCApplicationInfoPrivate.h */,\n\t\t\t\t4C3151D220EB673E00448776 /* TPCPathInfoPrivate.h */,\n\t\t\t\t4C3151E420EB673E00448776 /* TPCPreferencesImportExportPrivate.h */,\n\t\t\t\t4C31521820EB673E00448776 /* TPCPreferencesLocalPrivate.h */,\n\t\t\t\t4C06E26020EC4C560055D09A /* TPCPreferencesPrivate.h */,\n\t\t\t\t4C06E26120EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h */,\n\t\t\t\t4C8878062C3371470016DB98 /* TPCSandboxMigrationPrivate.h */,\n\t\t\t\t4C31522520EB673E00448776 /* TPCResourceManagerPrivate.h */,\n\t\t\t\t4C31521020EB673E00448776 /* TPCThemeControllerPrivate.h */,\n\t\t\t\t4C3151D620EB673E00448776 /* TPCThemePrivate.h */,\n\t\t\t\t4C3151D520EB673E00448776 /* TVCAppearancePrivate.h */,\n\t\t\t\t4C3151F820EB673E00448776 /* TVCChannelSelectionOutlineViewCellPrivate.h */,\n\t\t\t\t4C31520520EB673E00448776 /* TVCChannelSelectionViewControllerPrivate.h */,\n\t\t\t\t4C31521F20EB673E00448776 /* TVCContentNavigationOutlineViewPrivate.h */,\n\t\t\t\t4C31522720EB673E00448776 /* TVCDockIconPrivate.h */,\n\t\t\t\t4C31517520EB673E00448776 /* TVCErrorMessagePopoverControllerPrivate.h */,\n\t\t\t\t4C3151A020EB673E00448776 /* TVCErrorMessagePopoverPrivate.h */,\n\t\t\t\t4C31522420EB673E00448776 /* TVCLogControllerHistoricLogFilePrivate.h */,\n\t\t\t\t4C3151C220EB673E00448776 /* TVCLogControllerInlineMediaServicePrivate.h */,\n\t\t\t\t4C3151C920EB673E00448776 /* TVCLogControllerOperationQueuePrivate.h */,\n\t\t\t\t4C31521520EB673E00448776 /* TVCLogControllerPrivate.h */,\n\t\t\t\t4C31523020EB673E00448776 /* TVCLogLinePrivate.h */,\n\t\t\t\t4C3151DD20EB673E00448776 /* TVCLogPolicyPrivate.h */,\n\t\t\t\t4C3151B020EB673E00448776 /* TVCLogScriptEventSinkPrivate.h */,\n\t\t\t\t4C31521D20EB673E00448776 /* TVCLogViewInternalWK1.h */,\n\t\t\t\t4C3151F020EB673E00448776 /* TVCLogViewInternalWK2.h */,\n\t\t\t\t4C31520D20EB673E00448776 /* TVCLogViewPrivate.h */,\n\t\t\t\t4C31520020EB673E00448776 /* TVCMainWindowAppearancePrivate.h */,\n\t\t\t\t4C3151C820EB673E00448776 /* TVCMainWindowChannelViewPrivate.h */,\n\t\t\t\t4C3151F420EB673E00448776 /* TVCMainWindowLoadingScreenPrivate.h */,\n\t\t\t\t4C31523820EB673E00448776 /* TVCMainWindowPrivate.h */,\n\t\t\t\t4C31522D20EB673E00448776 /* TVCMainWindowSegmentedControlPrivate.h */,\n\t\t\t\t4C3151CE20EB673E00448776 /* TVCMainWindowSplitViewPrivate.h */,\n\t\t\t\t4C3151F320EB673E00448776 /* TVCMainWindowTextViewAppearancePrivate.h */,\n\t\t\t\t4C3151BB20EB673E00448776 /* TVCMainWindowTextViewPrivate.h */,\n\t\t\t\t4C3151DF20EB673E00448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h */,\n\t\t\t\t4C31521A20EB673E00448776 /* TVCMemberListAppearancePrivate.h */,\n\t\t\t\t4C3151C520EB673E00448776 /* TVCMemberListCellPrivate.h */,\n\t\t\t\t4C3151BF20EB673E00448776 /* TVCMemberListPrivate.h */,\n\t\t\t\t4C3151B620EB673E00448776 /* TVCMemberListUserInfoPopoverPrivate.h */,\n\t\t\t\t4C31522320EB673E00448776 /* TVCNotificationConfigurationViewControllerPrivate.h */,\n\t\t\t\t4C31521720EB673E00448776 /* TVCServerListAppearancePrivate.h */,\n\t\t\t\t4C3151F720EB673E00448776 /* TVCServerListCellPrivate.h */,\n\t\t\t\t4C3151CA20EB673E00448776 /* TVCServerListPrivate.h */,\n\t\t\t\t4C31522620EB673E00448776 /* TVCTextFormatterMenuPrivate.h */,\n\t\t\t\t4C31520820EB673E00448776 /* TVCTextViewWithIRCFormatterPrivate.h */,\n\t\t\t\t4C3151CD20EB673E00448776 /* TVCWK1AutoScrollerPrivate.h */,\n\t\t\t\t4C31523A20EB673E00448776 /* TXAppearancePrivate.h */,\n\t\t\t\t4C31520620EB673E00448776 /* TXApplicationPrivate.h */,\n\t\t\t\t4C31523220EB673E00448776 /* TXGlobalModelsPrivate.h */,\n\t\t\t\t4C31520420EB673E00448776 /* TXMasterControllerPrivate.h */,\n\t\t\t\t4C3151DE20EB673E00448776 /* TXMenuControllerPrivate.h */,\n\t\t\t\t4C3151C620EB673E00448776 /* TXSharedApplicationPrivate.h */,\n\t\t\t\t4C31522A20EB673E00448776 /* TXWindowControllerPrivate.h */,\n\t\t\t\t4C3151AD20EB673E00448776 /* WebScriptObjectHelperPrivate.h */,\n\t\t\t\t4C31523120EB673E00448776 /* WKWebViewPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31526220EB673E00448776 /* Dialogs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31526A20EB673E00448776 /* Channel Spotlight */,\n\t\t\t\t4C31529020EB673E00448776 /* File Transfers */,\n\t\t\t\t4C31527220EB673E00448776 /* License Manager */,\n\t\t\t\t4C31526720EB673E00448776 /* Preferences */,\n\t\t\t\t4C31528D20EB673E00448776 /* Server Endpoint */,\n\t\t\t\t4C31528120EB673E00448776 /* TDCAboutDialog.m */,\n\t\t\t\t4C31527020EB673E00448776 /* TDCAddressBookSheet.m */,\n\t\t\t\t4C31528020EB673E00448776 /* TDCAlert.m */,\n\t\t\t\t4C31528220EB673E00448776 /* TDCChannelBanListSheet.m */,\n\t\t\t\t4C31526320EB673E00448776 /* TDCChannelInviteSheet.m */,\n\t\t\t\t4C31526620EB673E00448776 /* TDCChannelModifyModesSheet.m */,\n\t\t\t\t4C31528920EB673E00448776 /* TDCChannelModifyTopicSheet.m */,\n\t\t\t\t4C31527120EB673E00448776 /* TDCChannelPropertiesNotificationConfiguration.m */,\n\t\t\t\t4C31526420EB673E00448776 /* TDCChannelPropertiesSheet.m */,\n\t\t\t\t4C31528320EB673E00448776 /* TDCHighlightEntrySheet.m */,\n\t\t\t\t4C31528520EB673E00448776 /* TDCInputPrompt.m */,\n\t\t\t\t4C31529420EB673E00448776 /* TDCNicknameColorSheet.m */,\n\t\t\t\t4C31528820EB673E00448776 /* TDCProgressIndicatorSheet.m */,\n\t\t\t\t4C31528C20EB673E00448776 /* TDCServerChangeNicknameSheet.m */,\n\t\t\t\t4C31528620EB673E00448776 /* TDCServerChannelListDialog.m */,\n\t\t\t\t4C31528720EB673E00448776 /* TDCServerHighlightListSheet.m */,\n\t\t\t\t4C31526520EB673E00448776 /* TDCServerPropertiesSheet.m */,\n\t\t\t\t4C31528A20EB673E00448776 /* TDCSheetBase.m */,\n\t\t\t\t4C31528B20EB673E00448776 /* TDCWelcomeSheet.m */,\n\t\t\t\t4C31528420EB673E00448776 /* TDCWindowBase.m */,\n\t\t\t);\n\t\t\tpath = Dialogs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31526720EB673E00448776 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31526920EB673E00448776 /* TDCPreferencesController.m */,\n\t\t\t\t4C31526820EB673E00448776 /* TDCPreferencesNotificationConfiguration.m */,\n\t\t\t\t4CB873DB22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31526A20EB673E00448776 /* Channel Spotlight */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31526E20EB673E00448776 /* TDCChannelSpotlightAppearance.m */,\n\t\t\t\t4C31526D20EB673E00448776 /* TDCChannelSpotlightController.m */,\n\t\t\t\t4C31526B20EB673E00448776 /* TDCChannelSpotlightControls.m */,\n\t\t\t\t4C31526C20EB673E00448776 /* TDCChannelSpotlightSearchResult.m */,\n\t\t\t\t4C31526F20EB673E00448776 /* TDCChannelSpotlightSearchResultsTable.m */,\n\t\t\t);\n\t\t\tpath = \"Channel Spotlight\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31527220EB673E00448776 /* License Manager */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31527320EB673E00448776 /* Standalone */,\n\t\t\t);\n\t\t\tpath = \"License Manager\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31527320EB673E00448776 /* Standalone */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31527A20EB673E00448776 /* TDCLicenseManagerDialog.m */,\n\t\t\t\t4C31527620EB673E00448776 /* TDCLicenseManagerMigrateAppStoreSheet.m */,\n\t\t\t\t4C31527820EB673E00448776 /* TDCLicenseManagerRecoverLostLicenseSheet.m */,\n\t\t\t\t4C31527920EB673E00448776 /* TDCLicenseUpgradeActivateSheet.m */,\n\t\t\t\t4C31527720EB673E00448776 /* TDCLicenseUpgradeCommonActions.m */,\n\t\t\t\t4C31527420EB673E00448776 /* TDCLicenseUpgradeDialog.m */,\n\t\t\t\t4C31527520EB673E00448776 /* TDCLicenseUpgradeEligibilitySheet.m */,\n\t\t\t);\n\t\t\tpath = Standalone;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31528D20EB673E00448776 /* Server Endpoint */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31528F20EB673E00448776 /* TDCServerEndpointListSheet.m */,\n\t\t\t\t4C31528E20EB673E00448776 /* TDCServerEndpointListSheetTable.m */,\n\t\t\t);\n\t\t\tpath = \"Server Endpoint\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31529020EB673E00448776 /* File Transfers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31529120EB673E00448776 /* TDCFileTransferDialog.m */,\n\t\t\t\t4C31529320EB673E00448776 /* TDCFileTransferDialogTableCell.m */,\n\t\t\t\t4C31529220EB673E00448776 /* TDCFileTransferDialogTransferController.m */,\n\t\t\t);\n\t\t\tpath = \"File Transfers\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31529A20EB673E00448776 /* Controllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31529E20EB673E00448776 /* TXAppearance.m */,\n\t\t\t\t4C31529C20EB673E00448776 /* TXApplication.m */,\n\t\t\t\t4C31529B20EB673E00448776 /* TXGlobalModels.m */,\n\t\t\t\t4C31529F20EB673E00448776 /* TXMasterController.m */,\n\t\t\t\t4C3152A120EB673E00448776 /* TXMenuController.m */,\n\t\t\t\t4C31529D20EB673E00448776 /* TXSharedApplication.m */,\n\t\t\t\t4C3152A020EB673E00448776 /* TXWindowController.m */,\n\t\t\t);\n\t\t\tpath = Controllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152A220EB673E00448776 /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152AD20EB673E00448776 /* Channel Selection Table */,\n\t\t\t\t4C3152B620EB673E00448776 /* Channel View */,\n\t\t\t\t4C3152C620EB673E00448776 /* Errors */,\n\t\t\t\t4C3152A420EB673E00448776 /* Input Text Field */,\n\t\t\t\t4C3152CE20EB673E00448776 /* Main Window */,\n\t\t\t\t4C3152AB20EB673E00448776 /* Preferences */,\n\t\t\t\t4C3152CA20EB673E00448776 /* Server List */,\n\t\t\t\t4C3152B020EB673E00448776 /* User List */,\n\t\t\t\t4C3152C420EB673E00448776 /* TVCAppearance.m */,\n\t\t\t\t4C3152A320EB673E00448776 /* TVCBasicTableView.m */,\n\t\t\t\t4C3152B520EB673E00448776 /* TVCContentNavigationOutlineView.m */,\n\t\t\t\t4C3152C520EB673E00448776 /* TVCDockIcon.m */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152A420EB673E00448776 /* Input Text Field */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152AA20EB673E00448776 /* TVCAutoExpandingTextField.m */,\n\t\t\t\t4C3152A520EB673E00448776 /* TVCAutoExpandingTokenField.m */,\n\t\t\t\t4C3152A620EB673E00448776 /* TVCTextFormatterMenu.m */,\n\t\t\t\t4C3152A720EB673E00448776 /* TVCTextViewWithIRCFormatter.m */,\n\t\t\t\t4C3152A820EB673E00448776 /* TVCValidatedComboBox.m */,\n\t\t\t\t4C3152A920EB673E00448776 /* TVCValidatedTextField.m */,\n\t\t\t);\n\t\t\tpath = \"Input Text Field\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152AB20EB673E00448776 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152AC20EB673E00448776 /* TVCNotificationConfigurationViewController.m */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152AD20EB673E00448776 /* Channel Selection Table */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152AE20EB673E00448776 /* TVCChannelSelectionOutlineCellView.m */,\n\t\t\t\t4C3152AF20EB673E00448776 /* TVCChannelSelectionViewController.m */,\n\t\t\t);\n\t\t\tpath = \"Channel Selection Table\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152B020EB673E00448776 /* User List */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152B320EB673E00448776 /* TVCMemberList.m */,\n\t\t\t\t4C3152B220EB673E00448776 /* TVCMemberListAppearance.m */,\n\t\t\t\t4C3152B120EB673E00448776 /* TVCMemberListCell.m */,\n\t\t\t\t4C3152B420EB673E00448776 /* TVCMemberListUserInfoPopover.m */,\n\t\t\t);\n\t\t\tpath = \"User List\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152B620EB673E00448776 /* Channel View */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152C020EB673E00448776 /* Extras */,\n\t\t\t\t4C3152BA20EB673E00448776 /* TVCLogController.m */,\n\t\t\t\t4C3152BE20EB673E00448776 /* TVCLogLine.m */,\n\t\t\t\t4C3152B820EB673E00448776 /* TVCLogPolicy.m */,\n\t\t\t\t4C3152BB20EB673E00448776 /* TVCLogRenderer.m */,\n\t\t\t\t4C3152B720EB673E00448776 /* TVCLogScriptEventSink.m */,\n\t\t\t\t4C3152BD20EB673E00448776 /* TVCLogView.m */,\n\t\t\t\t4C3152BC20EB673E00448776 /* TVCLogViewInternalWK1.m */,\n\t\t\t\t4C3152B920EB673E00448776 /* TVCLogViewInternalWK2.m */,\n\t\t\t\t4C3152BF20EB673E00448776 /* TVCWK1AutoScroller.m */,\n\t\t\t);\n\t\t\tpath = \"Channel View\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152C020EB673E00448776 /* Extras */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152C220EB673E00448776 /* TVCLogControllerHistoricLogFile.m */,\n\t\t\t\t4C3152C120EB673E00448776 /* TVCLogControllerInlineMediaService.m */,\n\t\t\t\t4C3152C320EB673E00448776 /* TVCLogControllerOperationQueue.m */,\n\t\t\t);\n\t\t\tpath = Extras;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152C620EB673E00448776 /* Errors */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152C920EB673E00448776 /* TVCAlert.m */,\n\t\t\t\t4C3152C720EB673E00448776 /* TVCErrorMessagePopover.m */,\n\t\t\t\t4C3152C820EB673E00448776 /* TVCErrorMessagePopoverController.m */,\n\t\t\t);\n\t\t\tpath = Errors;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152CA20EB673E00448776 /* Server List */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152CC20EB673E00448776 /* TVCServerList.m */,\n\t\t\t\t4C3152CD20EB673E00448776 /* TVCServerListAppearance.m */,\n\t\t\t\t4C3152CB20EB673E00448776 /* TVCServerListCell.m */,\n\t\t\t);\n\t\t\tpath = \"Server List\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152CE20EB673E00448776 /* Main Window */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152D120EB673E00448776 /* TVCMainWindow.m */,\n\t\t\t\t4C3152D520EB673E00448776 /* TVCMainWindowAppearance.m */,\n\t\t\t\t4C3152D820EB673E00448776 /* TVCMainWindowChannelView.m */,\n\t\t\t\t4C3152D220EB673E00448776 /* TVCMainWindowLoadingScreen.m */,\n\t\t\t\t4C3152D420EB673E00448776 /* TVCMainWindowSegmentedControl.m */,\n\t\t\t\t4C3152D320EB673E00448776 /* TVCMainWindowSplitView.m */,\n\t\t\t\t4C3152D620EB673E00448776 /* TVCMainWindowTextView.m */,\n\t\t\t\t4C3152CF20EB673E00448776 /* TVCMainWindowTextViewAppearance.m */,\n\t\t\t\t4C3152D720EB673E00448776 /* TVCMainWindowTitlebarAccessoryView.m */,\n\t\t\t);\n\t\t\tpath = \"Main Window\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152D920EB673E00448776 /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152E420EB673E00448776 /* Cocoa (Objective-C) */,\n\t\t\t\t4C3152DA20EB673E00448776 /* External Libraries */,\n\t\t\t\t4C3152E020EB673E00448776 /* Plugin Architecture */,\n\t\t\t\t4C3152DF20EB673E00448776 /* THOUnicodeHelper.m */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152DA20EB673E00448776 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152DD20EB673E00448776 /* Google */,\n\t\t\t\t4C3152DB20EB673E00448776 /* WebKit */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152DB20EB673E00448776 /* WebKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152DC20EB673E00448776 /* WebScriptObjectHelper.m */,\n\t\t\t);\n\t\t\tpath = WebKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152DD20EB673E00448776 /* Google */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152DE20EB673E00448776 /* GTMEncodeHTML.m */,\n\t\t\t);\n\t\t\tpath = Google;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152E020EB673E00448776 /* Plugin Architecture */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152E120EB673E00448776 /* THOPluginDispatcher.m */,\n\t\t\t\t4C3152E320EB673E00448776 /* THOPluginItem.m */,\n\t\t\t\t4C8F3FDB2C31B15200118AAF /* THOPluginItemLogging.m */,\n\t\t\t\t4C3152E220EB673E00448776 /* THOPluginManager.m */,\n\t\t\t);\n\t\t\tpath = \"Plugin Architecture\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152E420EB673E00448776 /* Cocoa (Objective-C) */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152E520EB673E00448776 /* NSColorHelper.m */,\n\t\t\t\t4C06E2A120EC4FA50055D09A /* NSObjectHelper.m */,\n\t\t\t\t4C3152E720EB673E00448776 /* NSStringHelper.m */,\n\t\t\t\t4C3152E820EB673E00448776 /* NSTableViewHelper.m */,\n\t\t\t\t4C3152E620EB673E00448776 /* NSViewHelper.m */,\n\t\t\t\t4C3152E920EB673E00448776 /* TXAppearanceHelper.m */,\n\t\t\t);\n\t\t\tpath = \"Cocoa (Objective-C)\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152EC20EB676400448776 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154B020EB67A400448776 /* Addons */,\n\t\t\t\t4CCC6B46158E8C1B003A102B /* Build Settings */,\n\t\t\t\t4C46CCA21580437400846B64 /* Documentation */,\n\t\t\t\t4C31531720EB676400448776 /* Images */,\n\t\t\t\t4C06E2A620EC4FF00055D09A /* Language Files */,\n\t\t\t\t4C3152ED20EB676400448776 /* License Manager */,\n\t\t\t\t4C31539B20EB676400448776 /* Property Lists */,\n\t\t\t\t4C3152EF20EB676400448776 /* Scripting */,\n\t\t\t\t4C3153A820EB676400448776 /* Styling */,\n\t\t\t\t4C06E13620EC4AC40055D09A /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152ED20EB676400448776 /* License Manager */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152EE20EB676400448776 /* RemoteLicenseSystemPublicKey.pub */,\n\t\t\t);\n\t\t\tpath = \"License Manager\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152EF20EB676400448776 /* Scripting */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3152F020EB676400448776 /* Script Files */,\n\t\t\t);\n\t\t\tpath = Scripting;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3152F020EB676400448776 /* Script Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C33341B20CC471A00ACB9AD /* Bundled Scripts */,\n\t\t\t);\n\t\t\tpath = \"Script Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31531720EB676400448776 /* Images */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31535720EB676400448776 /* Application */,\n\t\t\t\t4C31535620EB676400448776 /* Copyright Information for Images.txt */,\n\t\t\t\t4C31535C20EB676400448776 /* Dock Icon Badges */,\n\t\t\t\t4C31534F20EB676400448776 /* Encryption Badges */,\n\t\t\t\t4C31533C20EB676400448776 /* IRC Formatting Colors */,\n\t\t\t\t4C31531820EB676400448776 /* Preferences */,\n\t\t\t\t4C31532920EB676400448776 /* Status Badges */,\n\t\t\t\t4C31537720EB676400448776 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Images;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31531820EB676400448776 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31531C20EB676400448776 /* TPWTB_Addons.png */,\n\t\t\t\t4C31532120EB676400448776 /* TPWTB_Addons@2x.png */,\n\t\t\t\t4C31531D20EB676400448776 /* TPWTB_Advanced.png */,\n\t\t\t\t4C31531920EB676400448776 /* TPWTB_Advanced@2x.png */,\n\t\t\t\t4C31531E20EB676400448776 /* TPWTB_Controls.png */,\n\t\t\t\t4C31532320EB676400448776 /* TPWTB_Controls@2x.png */,\n\t\t\t\t4C31532820EB676400448776 /* TPWTB_General.png */,\n\t\t\t\t4C31532020EB676400448776 /* TPWTB_General@2x.png */,\n\t\t\t\t4C31531A20EB676400448776 /* TPWTB_Highlights.png */,\n\t\t\t\t4C31531B20EB676400448776 /* TPWTB_Highlights@2x.png */,\n\t\t\t\t4C31532420EB676400448776 /* TPWTB_Interface.png */,\n\t\t\t\t4C31532520EB676400448776 /* TPWTB_Interface@2x.png */,\n\t\t\t\t4C31532620EB676400448776 /* TPWTB_Notifications.png */,\n\t\t\t\t4C31532220EB676400448776 /* TPWTB_Notifications@2x.png */,\n\t\t\t\t4C31532720EB676400448776 /* TPWTB_Style.png */,\n\t\t\t\t4C31531F20EB676400448776 /* TPWTB_Style@2x.png */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31532920EB676400448776 /* Status Badges */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31533620EB676400448776 /* channelRoomStatusIconDarkActive.tif */,\n\t\t\t\t4C31533220EB676400448776 /* channelRoomStatusIconDarkActive@2x.tif */,\n\t\t\t\t4C31533920EB676400448776 /* channelRoomStatusIconDarkInactive.tif */,\n\t\t\t\t4C31533420EB676400448776 /* channelRoomStatusIconDarkInactive@2x.tif */,\n\t\t\t\t4C31533720EB676400448776 /* channelRoomStatusIconLightActive.tif */,\n\t\t\t\t4C31533120EB676400448776 /* channelRoomStatusIconLightActive@2x.tif */,\n\t\t\t\t4C31533320EB676400448776 /* channelRoomStatusIconLightInactive.tif */,\n\t\t\t\t4C31533B20EB676400448776 /* channelRoomStatusIconLightInactive@2x.tif */,\n\t\t\t);\n\t\t\tpath = \"Status Badges\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31533C20EB676400448776 /* IRC Formatting Colors */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31534C20EB676400448776 /* FormattingColor_0.png */,\n\t\t\t\t4C31534A20EB676400448776 /* FormattingColor_1.png */,\n\t\t\t\t4C31534D20EB676400448776 /* FormattingColor_2.png */,\n\t\t\t\t4C31534E20EB676400448776 /* FormattingColor_3.png */,\n\t\t\t\t4C31534820EB676400448776 /* FormattingColor_4.png */,\n\t\t\t\t4C31534920EB676400448776 /* FormattingColor_5.png */,\n\t\t\t\t4C31534720EB676400448776 /* FormattingColor_6.png */,\n\t\t\t\t4C31534620EB676400448776 /* FormattingColor_7.png */,\n\t\t\t\t4C31533D20EB676400448776 /* FormattingColor_8.png */,\n\t\t\t\t4C31533E20EB676400448776 /* FormattingColor_9.png */,\n\t\t\t\t4C31534020EB676400448776 /* FormattingColor_10.png */,\n\t\t\t\t4C31533F20EB676400448776 /* FormattingColor_11.png */,\n\t\t\t\t4C31534120EB676400448776 /* FormattingColor_12.png */,\n\t\t\t\t4C31534320EB676400448776 /* FormattingColor_13.png */,\n\t\t\t\t4C31534420EB676400448776 /* FormattingColor_14.png */,\n\t\t\t\t4C31534520EB676400448776 /* FormattingColor_15.png */,\n\t\t\t\t4C31534220EB676400448776 /* FormattingColor_Rainbow.tif */,\n\t\t\t\t4C31534B20EB676400448776 /* FormattingColor_Rainbow@2x.tif */,\n\t\t\t);\n\t\t\tpath = \"IRC Formatting Colors\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31534F20EB676400448776 /* Encryption Badges */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31535120EB676400448776 /* encryptionLockIconDark.tif */,\n\t\t\t\t4C31535220EB676400448776 /* encryptionLockIconDark@2x.tif */,\n\t\t\t\t4C31535320EB676400448776 /* encryptionLockIconLight.tif */,\n\t\t\t\t4C31535020EB676400448776 /* encryptionLockIconLight@2x.tif */,\n\t\t\t);\n\t\t\tpath = \"Encryption Badges\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31535720EB676400448776 /* Application */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31535920EB676400448776 /* applicationIcon.iconset */,\n\t\t\t\t4C31535820EB676400448776 /* applicationIcon.icns */,\n\t\t\t\t4C31535A20EB676400448776 /* applicationIconBirthday.icns */,\n\t\t\t);\n\t\t\tpath = Application;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31535C20EB676400448776 /* Dock Icon Badges */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31535D20EB676400448776 /* Green */,\n\t\t\t\t4C31536E20EB676400448776 /* Red */,\n\t\t\t);\n\t\t\tpath = \"Dock Icon Badges\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31535D20EB676400448776 /* Green */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31536120EB676400448776 /* DIGreenBadgeCenter.png */,\n\t\t\t\t4C31535F20EB676400448776 /* DIGreenBadgeLeft.png */,\n\t\t\t\t4C31536020EB676400448776 /* DIGreenBadgeRight.png */,\n\t\t\t);\n\t\t\tpath = Green;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31536E20EB676400448776 /* Red */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31537220EB676400448776 /* DIRedBadgeCenter.png */,\n\t\t\t\t4C31537120EB676400448776 /* DIRedBadgeLeft.png */,\n\t\t\t\t4C31537020EB676400448776 /* DIRedBadgeRight.png */,\n\t\t\t);\n\t\t\tpath = Red;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31537720EB676400448776 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31537820EB676400448776 /* MainWindowSegmentedControlUserTemplate.pdf */,\n\t\t\t\t4C31537920EB676400448776 /* MainWindowSpotlightIconTemplate.pdf */,\n\t\t\t\t4C31537A20EB676400448776 /* Miscellaneous */,\n\t\t\t\t4C31537C20EB676400448776 /* Server List */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31537A20EB676400448776 /* Miscellaneous */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31537B20EB676400448776 /* ErroneousTextFieldValueIndicator.tif */,\n\t\t\t);\n\t\t\tpath = Miscellaneous;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31537C20EB676400448776 /* Server List */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31537D20EB676400448776 /* Glass */,\n\t\t\t);\n\t\t\tpath = \"Server List\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31537D20EB676400448776 /* Glass */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C31538220EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif */,\n\t\t\t\t4C31537F20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif */,\n\t\t\t\t4C31538620EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif */,\n\t\t\t\t4C31537E20EB676400448776 /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif */,\n\t\t\t\t4C31538320EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive.tif */,\n\t\t\t\t4C31538520EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif */,\n\t\t\t\t4C31538420EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif */,\n\t\t\t\t4C31538720EB676400448776 /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif */,\n\t\t\t);\n\t\t\tpath = Glass;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C31539B20EB676400448776 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C315EE62C36494B001A16B4 /* Preferences */,\n\t\t\t\t4C3153A020EB676400448776 /* IRCCommandIndexLocalData.plist */,\n\t\t\t\t4C31539F20EB676400448776 /* IRCCommandIndexRemoteData.plist */,\n\t\t\t\t4C3153A220EB676400448776 /* IRCNetworks.plist */,\n\t\t\t\t4C3153A420EB676400448776 /* StaticStore.plist */,\n\t\t\t\t4C3153A120EB676400448776 /* TemplateLineTypes.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3153A820EB676400448776 /* Styling */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C33342020CC475300ACB9AD /* Bundled Styles */,\n\t\t\t\t4CCD93FC1CA7291300335381 /* JavaScript */,\n\t\t\t\t4C52379215C18F6700414852 /* Style Default Templates */,\n\t\t\t);\n\t\t\tpath = Styling;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154B020EB67A400448776 /* Addons */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46CCA6158043BB00846B64 /* Extensions */,\n\t\t\t\t4C69E3571B65C266002782D4 /* Installers */,\n\t\t\t\t4C9A933B1FA659D1003C3DB5 /* XPC Services */,\n\t\t\t);\n\t\t\tname = Addons;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154B120EB683200448776 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154B420EB685700448776 /* Build */,\n\t\t\t\t4C3154E620EB68A900448776 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../..;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154B420EB685700448776 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154D320EB685700448776 /* Code Signing Identity.xcconfig */,\n\t\t\t\t4C3154C820EB685700448776 /* Common */,\n\t\t\t\t4C3154DD20EB685700448776 /* Debug */,\n\t\t\t\t4C3154B520EB685700448776 /* Standard Release */,\n\t\t\t);\n\t\t\tname = Build;\n\t\t\tpath = Configurations/Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154B520EB685700448776 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154BD20EB685700448776 /* Enabled Features.xcconfig */,\n\t\t\t\t4C3154B720EB685700448776 /* Textual App.xcconfig */,\n\t\t\t\t4C3154B920EB685700448776 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C3154B820EB685700448776 /* Textual.xcconfig */,\n\t\t\t\t4C3154BC20EB685700448776 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t\t4C3154BA20EB685700448776 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4C3154BB20EB685700448776 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154C820EB685700448776 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154D220EB685700448776 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C3154CF20EB685700448776 /* Foundation.xcconfig */,\n\t\t\t\t4C3154CC20EB685700448776 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C3154CA20EB685700448776 /* Textual App.xcconfig */,\n\t\t\t\t4C3154CD20EB685700448776 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C3154CB20EB685700448776 /* Textual.xcconfig */,\n\t\t\t\t4C3154D120EB685700448776 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t\t4C3154CE20EB685700448776 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4C3154D020EB685700448776 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154DD20EB685700448776 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154E520EB685700448776 /* Enabled Features.xcconfig */,\n\t\t\t\t4C3154DF20EB685700448776 /* Textual App.xcconfig */,\n\t\t\t\t4C3154E120EB685700448776 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C3154E020EB685700448776 /* Textual.xcconfig */,\n\t\t\t\t4C3154E420EB685700448776 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t\t4C3154E220EB685700448776 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4C3154E320EB685700448776 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C3154E620EB68A900448776 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C3154E820EB68A900448776 /* Debug.entitlements */,\n\t\t\t\t4C3154E720EB68A900448776 /* Standard Release.entitlements */,\n\t\t\t);\n\t\t\tname = Sandbox;\n\t\t\tpath = Configurations/Sandbox;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C315EE62C36494B001A16B4 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C2BEB632C3864C1008F8F0D /* KeysExcludedFromContainer.plist */,\n\t\t\t\t4C315EE72C36581A001A16B4 /* KeysExcludedFromExport.plist */,\n\t\t\t\t4C0A31122C37419D0081EF1F /* KeysExcludedFromMigrate.plist */,\n\t\t\t\t4C315EE82C36581A001A16B4 /* PreferenceKeyMasterList.plist */,\n\t\t\t\t4C3153A520EB676400448776 /* RegisteredUserDefaults.plist */,\n\t\t\t\t4C3153A620EB676400448776 /* RegisteredUserDefaultsInContainer.plist */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46CCA21580437400846B64 /* Documentation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C58B570186011AC00834882 /* Acknowledgements.pdf */,\n\t\t\t);\n\t\t\tname = Documentation;\n\t\t\tpath = ..;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46CCA6158043BB00846B64 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46CCA7158043C000846B64 /* Binaries */,\n\t\t\t);\n\t\t\tname = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46CCA7158043C000846B64 /* Binaries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C2E92202C1E4463003BB92D /* Caffeine.bundle */,\n\t\t\t\t4C83B9101BA9BEB800BD7718 /* Chat Filters.bundle */,\n\t\t\t\t4C956893194A8862003D97FD /* Smiley Converter.bundle */,\n\t\t\t\t4C9A1D931836E6A100C14835 /* System Info.bundle */,\n\t\t\t\t4C9A1D921836E6A100C14835 /* User Insights.bundle */,\n\t\t\t\t4C9A1D941836E6A100C14835 /* ZNC Additions.bundle */,\n\t\t\t);\n\t\t\tname = Binaries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46CCB91580469200846B64 /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CCE521A18C7BE0600D49601 /* AudioToolbox.framework */,\n\t\t\t\t4C46CCBC1580469E00846B64 /* Cocoa.framework */,\n\t\t\t\t4CA8EC621B63C2970087BF72 /* CoreServices.framework */,\n\t\t\t\t4C10C00D1F37E59B0004C624 /* IOKit.framework */,\n\t\t\t\t4CF4D6B619837C1700FB5AF0 /* QuartzCore.framework */,\n\t\t\t\t4C46CCC01580469E00846B64 /* Security.framework */,\n\t\t\t\t4C46CCC11580469E00846B64 /* SystemConfiguration.framework */,\n\t\t\t\t4C2F42042C3F4218000D962D /* UserNotifications.framework */,\n\t\t\t\t4C46CCC21580469E00846B64 /* WebKit.framework */,\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46CCCC158046BE00846B64 /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CF76A371A91153A0088BF9A /* AutoHyperlinks.framework */,\n\t\t\t\t4CF76A391A91153A0088BF9A /* CocoaExtensions.framework */,\n\t\t\t\t4C8F2F5D1AAE6467007821CC /* EncryptionKit.framework */,\n\t\t\t\t4CC4A7371F8A1404008FF15F /* GRMustache.framework */,\n\t\t\t\t4C24DC751A93C9CE0098D1BE /* Sparkle.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C4A0D6B1C973E8100064A23 /* Application Properties */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C4A0D6C1C973E9000064A23 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Application Properties\";\n\t\t\tpath = \"Resources/Property Lists\";\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C69E3571B65C266002782D4 /* Installers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C2F0C701F2AF3860017D3B7 /* Textual-Extras.pkg */,\n\t\t\t);\n\t\t\tname = Installers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C9A933B1FA659D1003C3DB5 /* XPC Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C9A933C1FA659D9003C3DB5 /* Binaries */,\n\t\t\t);\n\t\t\tname = \"XPC Services\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C9A933C1FA659D9003C3DB5 /* Binaries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C171669254A589D004BE8AE /* Inline Content Loader.xpc */,\n\t\t\t\t4C171668254A589D004BE8AE /* IRC Connection Host.xpc */,\n\t\t\t\t4C17166A254A589E004BE8AE /* Scrollback History Manager.xpc */,\n\t\t\t);\n\t\t\tname = Binaries;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CCC6B46158E8C1B003A102B /* Build Settings */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C4A0D6B1C973E8100064A23 /* Application Properties */,\n\t\t\t\t5D9B8EB1170A0EA700919CB0 /* Build Scripts */,\n\t\t\t\t4C3154B120EB683200448776 /* Configurations */,\n\t\t\t\t4CB638CB2D45A06C002B2CC3 /* FeatureFlags.h */,\n\t\t\t\t4CC70202171E1CB400BDFAE0 /* BuildConfig.h */,\n\t\t\t);\n\t\t\tname = \"Build Settings\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5D9B8EB1170A0EA700919CB0 /* Build Scripts */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5D9B8EB9170A10F200919CB0 /* BuildExtensions.sh */,\n\t\t\t\t5D9B8EB6170A0EB400919CB0 /* BuildFrameworks.sh */,\n\t\t\t\t4C761BAE1E155CB100A505B7 /* BuildServices.sh */,\n\t\t\t\t4CD6F7BB1CA7747600842597 /* ExportArchive.sh */,\n\t\t\t\t4C48B46320E4D06900CF5F84 /* MergeSwift.sh */,\n\t\t\t\t4C7961C6267D25B400D37F07 /* UpdateFeatureFlags.sh */,\n\t\t\t\t5D9B8EB8170A0EB400919CB0 /* UpdateVersionInfo.sh */,\n\t\t\t\t4C2BEB622C385189008F8F0D /* PostprocessSparkle.sh */,\n\t\t\t);\n\t\t\tname = \"Build Scripts\";\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t4C5BA3D916F1302F00A96CA2 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CB638CC2D45A06C002B2CC3 /* FeatureFlags.h in Headers */,\n\t\t\t\t4C3157BF20EB6D0600448776 /* TDCServerPropertiesSheetPrivate.h in Headers */,\n\t\t\t\t4C3157A820EB6D0600448776 /* TDCFileTransferDialogTableCellPrivate.h in Headers */,\n\t\t\t\t4CAB275F2537F71B009B1F07 /* IRCChannelMemberList.h in Headers */,\n\t\t\t\t4C31578A20EB6D0600448776 /* IRCServerPrivate.h in Headers */,\n\t\t\t\t4C3158BD20EB6D0F00448776 /* IRCHighlightLogEntryInternal.h in Headers */,\n\t\t\t\t4C3157F920EB6D0600448776 /* TVCMemberListPrivate.h in Headers */,\n\t\t\t\t4C31556520EB6CB300448776 /* IRCWorld.h in Headers */,\n\t\t\t\t4C31577A20EB6D0600448776 /* IRCAddressBookUserTrackingPrivate.h in Headers */,\n\t\t\t\t4C3158AF20EB6D0F00448776 /* IRCUserInternal.h in Headers */,\n\t\t\t\t4C3157B020EB6D0600448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3F920EC51380055D09A /* ICLInlineContentProtocol.h in Headers */,\n\t\t\t\t4C3157C020EB6D0600448776 /* TDCSharedProtocolDefinitionsPrivate.h in Headers */,\n\t\t\t\t4C31555820EB6CB300448776 /* IRCHighlightLogEntry.h in Headers */,\n\t\t\t\t4C06E26C20EC4C560055D09A /* NSObjectHelperPrivate.h in Headers */,\n\t\t\t\t4C06E28120EC4E870055D09A /* TPCPreferences.h in Headers */,\n\t\t\t\t4C3158BA20EB6D0F00448776 /* IRCMessageInternal.h in Headers */,\n\t\t\t\t4C31559F20EB6CB300448776 /* TXGlobalModels.h in Headers */,\n\t\t\t\t4C3157FB20EB6D0600448776 /* TVCNotificationConfigurationViewControllerPrivate.h in Headers */,\n\t\t\t\t4C31559620EB6CB300448776 /* TVCMemberList.h in Headers */,\n\t\t\t\t4C31558320EB6CB300448776 /* TPCTheme.h in Headers */,\n\t\t\t\t4C3157F120EB6D0600448776 /* TVCMainWindowSegmentedControlPrivate.h in Headers */,\n\t\t\t\t4C31556B20EB6CB300448776 /* TDCSheetBase.h in Headers */,\n\t\t\t\t4C31559120EB6CB300448776 /* TVCMainWindowAppearance.h in Headers */,\n\t\t\t\t4C3157A620EB6D0600448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h in Headers */,\n\t\t\t\t4C31579E20EB6D0600448776 /* TDCChannelModifyModesSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3FD20EC51380055D09A /* HLSHistoricLogProtocol.h in Headers */,\n\t\t\t\t4C3157CC20EB6D0600448776 /* TLOLicenseManagerDownloaderPrivate.h in Headers */,\n\t\t\t\t4C31578F20EB6D0600448776 /* IRCUserPrivate.h in Headers */,\n\t\t\t\t4C31580120EB6D0600448776 /* TVCWK1AutoScrollerPrivate.h in Headers */,\n\t\t\t\t4C3157A420EB6D0600448776 /* TDCChannelSpotlightControlsPrivate.h in Headers */,\n\t\t\t\t4C31559B20EB6CB300448776 /* TVCValidatedComboBox.h in Headers */,\n\t\t\t\t4C31556C20EB6CB300448776 /* TDCWindowBase.h in Headers */,\n\t\t\t\t4C06E3B520EC51380055D09A /* GCDAsyncSocket.h in Headers */,\n\t\t\t\t4C3157C120EB6D0600448776 /* TDCWelcomeSheetPrivate.h in Headers */,\n\t\t\t\t4C3157C220EB6D0600448776 /* TextualPrivate.h in Headers */,\n\t\t\t\t4C3158B920EB6D0F00448776 /* IRCModeInfoInternal.h in Headers */,\n\t\t\t\t4C31578220EB6D0600448776 /* IRCColorFormatPrivate.h in Headers */,\n\t\t\t\t4C3157B120EB6D0600448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3B120EC51380055D09A /* GCDAsyncSocketExtensions.h in Headers */,\n\t\t\t\t4C3157D320EB6D0600448776 /* TPCApplicationInfoPrivate.h in Headers */,\n\t\t\t\t4C31580220EB6D0600448776 /* TXAppearancePrivate.h in Headers */,\n\t\t\t\t4C31555620EB6CB300448776 /* IRCCommandIndex.h in Headers */,\n\t\t\t\t4C31579620EB6D0600448776 /* TDCAboutDialogPrivate.h in Headers */,\n\t\t\t\t4C3157E720EB6D0600448776 /* TVCLogLinePrivate.h in Headers */,\n\t\t\t\t4C3157A220EB6D0600448776 /* TDCChannelSpotlightAppearancePrivate.h in Headers */,\n\t\t\t\t4C3157E620EB6D0600448776 /* TVCLogControllerPrivate.h in Headers */,\n\t\t\t\t4C3157D720EB6D0600448776 /* TPCPreferencesImportExportPrivate.h in Headers */,\n\t\t\t\t4C3157B720EB6D0600448776 /* TDCPreferencesControllerPrivate.h in Headers */,\n\t\t\t\t4C3157AF20EB6D0600448776 /* TDCLicenseManagerDialogPrivate.h in Headers */,\n\t\t\t\t4C31578820EB6D0600448776 /* IRCMessageBatchPrivate.h in Headers */,\n\t\t\t\t4C3157CD20EB6D0600448776 /* TLOLicenseManagerLastGenPrivate.h in Headers */,\n\t\t\t\t4C31556E20EB6CB300448776 /* TextualApplication.h in Headers */,\n\t\t\t\t4C31559020EB6CB300448776 /* TVCMainWindow.h in Headers */,\n\t\t\t\t4C31559420EB6CB300448776 /* TVCMainWindowTextView.h in Headers */,\n\t\t\t\t4C06E26420EC4C560055D09A /* TPCPreferencesPrivate.h in Headers */,\n\t\t\t\t4C3158BC20EB6D0F00448776 /* TDCChannelSpotlightControllerInternal.h in Headers */,\n\t\t\t\t4C06E25D20EC4BBD0055D09A /* IRCConnectionConfigInternal.h in Headers */,\n\t\t\t\t4C31559520EB6CB300448776 /* TVCMainWindowTextViewAppearance.h in Headers */,\n\t\t\t\t4C3157DB20EB6D0600448776 /* TPCResourceManagerPrivate.h in Headers */,\n\t\t\t\t4C06E41220EC52240055D09A /* TVCLogLineXPCPrivate.h in Headers */,\n\t\t\t\t4C3157A020EB6D0600448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C31556320EB6CB300448776 /* IRCUser.h in Headers */,\n\t\t\t\t4C31556F20EB6CB300448776 /* THOPluginProtocol.h in Headers */,\n\t\t\t\t4C3157AA20EB6D0600448776 /* TDCHighlightEntrySheetPrivate.h in Headers */,\n\t\t\t\t4C3157E920EB6D0600448776 /* TVCLogScriptEventSinkPrivate.h in Headers */,\n\t\t\t\t4C3158B420EB6D0F00448776 /* IRCPrefixInternal.h in Headers */,\n\t\t\t\t4C06E3C920EC51380055D09A /* ICLPayloadInternal.h in Headers */,\n\t\t\t\t4C3157EE20EB6D0600448776 /* TVCMainWindowChannelViewPrivate.h in Headers */,\n\t\t\t\t4C3157C520EB6D0600448776 /* THOPluginManagerPrivate.h in Headers */,\n\t\t\t\t4C31558020EB6CB300448776 /* TPCPreferencesUserDefaultsLocal.h in Headers */,\n\t\t\t\t4C3157D820EB6D0600448776 /* TPCPreferencesLocalPrivate.h in Headers */,\n\t\t\t\t4C3157EB20EB6D0600448776 /* TVCLogViewInternalWK2.h in Headers */,\n\t\t\t\t4C31555B20EB6CB300448776 /* IRCMessage.h in Headers */,\n\t\t\t\t4C31578D20EB6D0600448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h in Headers */,\n\t\t\t\t4C3157B820EB6D0600448776 /* TDCPreferencesNotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C31580620EB6D0600448776 /* TXMenuControllerPrivate.h in Headers */,\n\t\t\t\t4C8878082C3371470016DB98 /* TPCSandboxMigrationPrivate.h in Headers */,\n\t\t\t\t4C31558920EB6CB300448776 /* TVCChannelSelectionViewController.h in Headers */,\n\t\t\t\t4C31577C20EB6D0600448776 /* IRCChannelModePrivate.h in Headers */,\n\t\t\t\t4C3157F420EB6D0600448776 /* TVCMainWindowTextViewAppearancePrivate.h in Headers */,\n\t\t\t\t4C31556920EB6CB300448776 /* TDCAlert.h in Headers */,\n\t\t\t\t4C31555320EB6CB300448776 /* IRCClient.h in Headers */,\n\t\t\t\t4C3157FD20EB6D0600448776 /* TVCServerListCellPrivate.h in Headers */,\n\t\t\t\t4C3158B120EB6D0F00448776 /* TDCChannelPropertiesSheetInternal.h in Headers */,\n\t\t\t\t4C31578E20EB6D0600448776 /* IRCUserPersistentStorePrivate.h in Headers */,\n\t\t\t\t4C31559820EB6CB300448776 /* TVCServerList.h in Headers */,\n\t\t\t\t4C3157B320EB6D0600448776 /* TDCLicenseUpgradeCommonActionsPrivate.h in Headers */,\n\t\t\t\t4C31558B20EB6CB300448776 /* TVCErrorMessagePopoverPrivate.h in Headers */,\n\t\t\t\t4C3157FE20EB6D0600448776 /* TVCServerListPrivate.h in Headers */,\n\t\t\t\t4C3157CE20EB6D0600448776 /* TLOLicenseManagerPrivate.h in Headers */,\n\t\t\t\t4C31579320EB6D0600448776 /* NSTableVIewHelperPrivate.h in Headers */,\n\t\t\t\t4C31578520EB6D0600448776 /* IRCExtrasPrivate.h in Headers */,\n\t\t\t\t4C31557320EB6CB300448776 /* TLOInternetAddressLookup.h in Headers */,\n\t\t\t\t4C31556D20EB6CB300448776 /* Textual.h in Headers */,\n\t\t\t\t4C31555720EB6CB300448776 /* IRCConnection.h in Headers */,\n\t\t\t\t4C31578C20EB6D0600448776 /* IRCTreeItemPrivate.h in Headers */,\n\t\t\t\t4C3157BD20EB6D0600448776 /* TDCServerEndpointListSheetTablePrivate.h in Headers */,\n\t\t\t\t4C3158B820EB6D0F00448776 /* IRCChannelUserInternal.h in Headers */,\n\t\t\t\t4C3155A220EB6CB300448776 /* TXSharedApplication.h in Headers */,\n\t\t\t\t4C7B05001D1210F300295E82 /* BuildConfig.h in Headers */,\n\t\t\t\t4C31577E20EB6D0600448776 /* IRCChannelUserPrivate.h in Headers */,\n\t\t\t\t4C31579420EB6D0600448776 /* NSViewHelperPrivate.h in Headers */,\n\t\t\t\t4C3157B220EB6D0600448776 /* TDCLicenseUpgradeActivateSheetPrivate.h in Headers */,\n\t\t\t\t4C3158BE20EB6D0F00448776 /* IRCHighlightMatchConditionInternal.h in Headers */,\n\t\t\t\t4C31558D20EB6CB300448776 /* TVCLogLine.h in Headers */,\n\t\t\t\t4C3158B220EB6D0F00448776 /* TDCChannelSpotlightAppearanceInternal.h in Headers */,\n\t\t\t\t4C31580720EB6D0600448776 /* TXSharedApplicationPrivate.h in Headers */,\n\t\t\t\t4C31578B20EB6D0600448776 /* IRCTimerCommandPrivate.h in Headers */,\n\t\t\t\t4C3157CB20EB6D0600448776 /* TLOInputHistoryPrivate.h in Headers */,\n\t\t\t\t4C3157D220EB6D0600448776 /* TLOSpokenNotificationPrivate.h in Headers */,\n\t\t\t\t4C31558820EB6CB300448776 /* TVCBasicTableView.h in Headers */,\n\t\t\t\t4C31558220EB6CB300448776 /* TPCThemeController.h in Headers */,\n\t\t\t\t4C31556720EB6CB300448776 /* NSStringHelper.h in Headers */,\n\t\t\t\t4C3157DC20EB6D0600448776 /* TPCThemeControllerPrivate.h in Headers */,\n\t\t\t\t4C3157C620EB6D0600448776 /* THOPluginProtocolPrivate.h in Headers */,\n\t\t\t\t4C3157E220EB6D0600448776 /* TVCDockIconPrivate.h in Headers */,\n\t\t\t\t4C31558720EB6CB300448776 /* TVCAutoExpandingTokenField.h in Headers */,\n\t\t\t\t4C31577B20EB6D0600448776 /* IRCChannelConfigPrivate.h in Headers */,\n\t\t\t\t4C31558C20EB6CB300448776 /* TVCLogController.h in Headers */,\n\t\t\t\t4C3158AE20EB6D0F00448776 /* IRCServerInternal.h in Headers */,\n\t\t\t\t4C31555C20EB6CB300448776 /* IRCModeInfo.h in Headers */,\n\t\t\t\t4C31555D20EB6CB300448776 /* IRCNetworkList.h in Headers */,\n\t\t\t\t4C31578420EB6D0600448776 /* IRCConnectionPrivate.h in Headers */,\n\t\t\t\t4C31558420EB6CB300448776 /* TVCAlert.h in Headers */,\n\t\t\t\t4C3157C420EB6D0600448776 /* THOPluginItemPrivate.h in Headers */,\n\t\t\t\t4C31577920EB6D0600448776 /* IRCAddressBookMatchCachePrivate.h in Headers */,\n\t\t\t\t4C31557D20EB6CB300448776 /* TPCPreferencesImportExport.h in Headers */,\n\t\t\t\t4C31556020EB6CB300448776 /* IRCSendingMessage.h in Headers */,\n\t\t\t\t4C31557A20EB6CB300448776 /* TPCPathInfo.h in Headers */,\n\t\t\t\t4C31554F20EB6CB300448776 /* IRCChannel.h in Headers */,\n\t\t\t\t4C31557420EB6CB300448776 /* TLOKeyEventHandler.h in Headers */,\n\t\t\t\t4C3158E620EB6D1600448776 /* OELReachability.h in Headers */,\n\t\t\t\t4C31555520EB6CB300448776 /* IRCColorFormat.h in Headers */,\n\t\t\t\t4C3158B620EB6D0F00448776 /* IRCClientConfigInternal.h in Headers */,\n\t\t\t\t4C3155A120EB6CB300448776 /* TXMenuController.h in Headers */,\n\t\t\t\t4C31555A20EB6CB300448776 /* IRCISupportInfo.h in Headers */,\n\t\t\t\t4C31580820EB6D0600448776 /* TXWindowControllerPrivate.h in Headers */,\n\t\t\t\t4C3157D420EB6D0600448776 /* TPCPathInfoPrivate.h in Headers */,\n\t\t\t\t4CEFEDAC22B4AF42002CEE19 /* TDCPreferencesUserStyleSheetPrivate.h in Headers */,\n\t\t\t\t4C31559720EB6CB300448776 /* TVCMemberListAppearance.h in Headers */,\n\t\t\t\t4C3158E520EB6D1600448776 /* GTMEncodeHTML.h in Headers */,\n\t\t\t\t4C3157BE20EB6D0600448776 /* TDCServerHighlightListSheetPrivate.h in Headers */,\n\t\t\t\t4C06E27120EC4E350055D09A /* StaticDefinitions.h in Headers */,\n\t\t\t\t4C31580420EB6D0600448776 /* TXGlobalModelsPrivate.h in Headers */,\n\t\t\t\t4C31580920EB6D0600448776 /* WKWebViewPrivate.h in Headers */,\n\t\t\t\t4C3157A920EB6D0600448776 /* TDCFileTransferDialogTransferControllerPrivate.h in Headers */,\n\t\t\t\t4C3157EA20EB6D0600448776 /* TVCLogViewInternalWK1.h in Headers */,\n\t\t\t\t4C31557820EB6CB300448776 /* TLOSoundPlayer.h in Headers */,\n\t\t\t\t4C31557920EB6CB300448776 /* TPCApplicationInfo.h in Headers */,\n\t\t\t\t4C3157A720EB6D0600448776 /* TDCFileTransferDialogPrivate.h in Headers */,\n\t\t\t\t4C31578320EB6D0600448776 /* IRCCommandIndexPrivate.h in Headers */,\n\t\t\t\t4C31559D20EB6CB300448776 /* TXAppearance.h in Headers */,\n\t\t\t\t4C3157DD20EB6D0600448776 /* TPCThemePrivate.h in Headers */,\n\t\t\t\t4C31554D20EB6CB300448776 /* IRCAddressBook.h in Headers */,\n\t\t\t\t4C3157D120EB6D0600448776 /* TLOSpeechSynthesizerPrivate.h in Headers */,\n\t\t\t\t4C06E24920EC4B970055D09A /* IRCConnectionConfig.h in Headers */,\n\t\t\t\t4C31557520EB6CB300448776 /* TLOLinkParser.h in Headers */,\n\t\t\t\t4C06E3F520EC51380055D09A /* RCMConnectionManagerProtocol.h in Headers */,\n\t\t\t\t4C31577F20EB6D0600448776 /* IRCClientConfigPrivate.h in Headers */,\n\t\t\t\t4C31580520EB6D0600448776 /* TXMasterControllerPrivate.h in Headers */,\n\t\t\t\t4C3157F320EB6D0600448776 /* TVCMainWindowSplitViewPrivate.h in Headers */,\n\t\t\t\t4C3157FA20EB6D0600448776 /* TVCMemberListUserInfoPopoverPrivate.h in Headers */,\n\t\t\t\t4C31579F20EB6D0600448776 /* TDCChannelModifyTopicSheetPrivate.h in Headers */,\n\t\t\t\t4C31579120EB6D0600448776 /* IRCWorldPrivate.h in Headers */,\n\t\t\t\t4C31559A20EB6CB300448776 /* TVCTextViewWithIRCFormatter.h in Headers */,\n\t\t\t\t4C31580020EB6D0600448776 /* TVCTextViewWithIRCFormatterPrivate.h in Headers */,\n\t\t\t\t4C3157EC20EB6D0600448776 /* TVCLogViewPrivate.h in Headers */,\n\t\t\t\t4C3157FF20EB6D0600448776 /* TVCTextFormatterMenuPrivate.h in Headers */,\n\t\t\t\t4C31556820EB6CB300448776 /* NSViewHelper.h in Headers */,\n\t\t\t\t4C3157F520EB6D0600448776 /* TVCMainWindowTextViewPrivate.h in Headers */,\n\t\t\t\t4C3157B920EB6D0600448776 /* TDCProgressIndicatorSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3D520EC51380055D09A /* ICLPayload.h in Headers */,\n\t\t\t\t4C8F3FD92C31AF7700118AAF /* THOPluginManager.h in Headers */,\n\t\t\t\t4C3157E420EB6D0600448776 /* TVCLogControllerInlineMediaServicePrivate.h in Headers */,\n\t\t\t\t4C3157B620EB6D0600448776 /* TDCNicknameColorSheetPrivate.h in Headers */,\n\t\t\t\t4C31578620EB6D0600448776 /* IRCHighlightLogEntryPrivate.h in Headers */,\n\t\t\t\t4C3158B520EB6D0F00448776 /* IRCChannelConfigInternal.h in Headers */,\n\t\t\t\t4C31558A20EB6CB300448776 /* TVCErrorMessagePopoverControllerPrivate.h in Headers */,\n\t\t\t\t4C3157A520EB6D0600448776 /* TDCChannelSpotlightSearchResultPrivate.h in Headers */,\n\t\t\t\t4C3157C820EB6D0600448776 /* TLOEncryptionManagerPrivate.h in Headers */,\n\t\t\t\t4C31577720EB6D0600448776 /* WebScriptObjectHelperPrivate.h in Headers */,\n\t\t\t\t4C3157F720EB6D0600448776 /* TVCMemberListAppearancePrivate.h in Headers */,\n\t\t\t\t4C31558120EB6CB300448776 /* TPCResourceManager.h in Headers */,\n\t\t\t\t4C3157D020EB6D0600448776 /* TLONotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C31579D20EB6D0600448776 /* TDCChannelInviteSheetPrivate.h in Headers */,\n\t\t\t\t4C31558F20EB6CB300448776 /* TVCLogView.h in Headers */,\n\t\t\t\t4C31554C20EB6CB300448776 /* IRC.h in Headers */,\n\t\t\t\t4C31556A20EB6CB300448776 /* TDCInputPrompt.h in Headers */,\n\t\t\t\t4C3157B520EB6D0600448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h in Headers */,\n\t\t\t\t4C3157ED20EB6D0600448776 /* TVCMainWindowAppearancePrivate.h in Headers */,\n\t\t\t\t4C06E27D20EC4E870055D09A /* TPCPreferencesUserDefaults.h in Headers */,\n\t\t\t\t4C31578720EB6D0600448776 /* IRCISupportInfoPrivate.h in Headers */,\n\t\t\t\t4C5274E220F8D78800B18F9D /* IRCConnectionErrors.h in Headers */,\n\t\t\t\t4C06E27920EC4E870055D09A /* TLOTimer.h in Headers */,\n\t\t\t\t4C31555220EB6CB300448776 /* IRCChannelUser.h in Headers */,\n\t\t\t\t4C3157FC20EB6D0600448776 /* TVCServerListAppearancePrivate.h in Headers */,\n\t\t\t\t4C3157A320EB6D0600448776 /* TDCChannelSpotlightControllerPrivate.h in Headers */,\n\t\t\t\t4C3157CF20EB6D0600448776 /* TLONicknameCompletionStatusPrivate.h in Headers */,\n\t\t\t\t4C31578920EB6D0600448776 /* IRCMessagePrivate.h in Headers */,\n\t\t\t\t4C31577D20EB6D0600448776 /* IRCChannelPrivate.h in Headers */,\n\t\t\t\t4C3157C920EB6D0600448776 /* TLOFileLoggerPrivate.h in Headers */,\n\t\t\t\t4C31555120EB6CB300448776 /* IRCChannelMode.h in Headers */,\n\t\t\t\t4C3157E120EB6D0600448776 /* TVCContentNavigationOutlineViewPrivate.h in Headers */,\n\t\t\t\t4C31556220EB6CB300448776 /* IRCTreeItem.h in Headers */,\n\t\t\t\t4C06E26820EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h in Headers */,\n\t\t\t\t4C31559220EB6CB300448776 /* TVCMainWindowLoadingScreen.h in Headers */,\n\t\t\t\t4C3158B720EB6D0F00448776 /* TVCLogLineInternal.h in Headers */,\n\t\t\t\t4C31556420EB6CB300448776 /* IRCUserRelations.h in Headers */,\n\t\t\t\t4C3157EF20EB6D0600448776 /* TVCMainWindowLoadingScreenPrivate.h in Headers */,\n\t\t\t\t4C31556120EB6CB300448776 /* IRCServer.h in Headers */,\n\t\t\t\t4C31579520EB6D0600448776 /* SwiftBridgingHeaderPrivate.h in Headers */,\n\t\t\t\t4C31578120EB6D0600448776 /* IRCClientRequestedCommandsPrivate.h in Headers */,\n\t\t\t\t4C31555E20EB6CB300448776 /* IRCNumerics.h in Headers */,\n\t\t\t\t4C31555F20EB6CB300448776 /* IRCPrefix.h in Headers */,\n\t\t\t\t4C3157E320EB6D0600448776 /* TVCLogControllerHistoricLogFilePrivate.h in Headers */,\n\t\t\t\t4CAB276C253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h in Headers */,\n\t\t\t\t4C06E41720EC52D60055D09A /* ICLPayloadLocalPrivate.h in Headers */,\n\t\t\t\t4C31557F20EB6CB300448776 /* TPCPreferencesReload.h in Headers */,\n\t\t\t\t4C31557220EB6CB300448776 /* TLONotificationController.h in Headers */,\n\t\t\t\t4C3157BB20EB6D0600448776 /* TDCServerChannelListDialogPrivate.h in Headers */,\n\t\t\t\t4C31554E20EB6CB300448776 /* IRCAddressBookUserTracking.h in Headers */,\n\t\t\t\t4C3157CA20EB6D0600448776 /* TLONotificationControllerPrivate.h in Headers */,\n\t\t\t\t4C3157BC20EB6D0600448776 /* TDCServerEndpointListSheetPrivate.h in Headers */,\n\t\t\t\t4C3157F620EB6D0600448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h in Headers */,\n\t\t\t\t4C31580320EB6D0600448776 /* TXApplicationPrivate.h in Headers */,\n\t\t\t\t4C3157F020EB6D0600448776 /* TVCMainWindowPrivate.h in Headers */,\n\t\t\t\t4C3158B020EB6D0F00448776 /* IRCAddressBookInternal.h in Headers */,\n\t\t\t\t4C31559E20EB6CB300448776 /* TXAppearanceHelper.h in Headers */,\n\t\t\t\t4C31555420EB6CB300448776 /* IRCClientConfig.h in Headers */,\n\t\t\t\t4C3157DE20EB6D0600448776 /* TVCAppearancePrivate.h in Headers */,\n\t\t\t\t4C3157C320EB6D0600448776 /* THOPluginDispatcherPrivate.h in Headers */,\n\t\t\t\t4C31556620EB6CB300448776 /* NSColorHelper.h in Headers */,\n\t\t\t\t4C31555920EB6CB300448776 /* IRCHighlightMatchCondition.h in Headers */,\n\t\t\t\t4C31558620EB6CB300448776 /* TVCAutoExpandingTextField.h in Headers */,\n\t\t\t\t4C31559920EB6CB300448776 /* TVCServerListAppearance.h in Headers */,\n\t\t\t\t4C3157F820EB6D0600448776 /* TVCMemberListCellPrivate.h in Headers */,\n\t\t\t\t4C31579020EB6D0600448776 /* IRCUserRelationsPrivate.h in Headers */,\n\t\t\t\t4C3157E020EB6D0600448776 /* TVCChannelSelectionViewControllerPrivate.h in Headers */,\n\t\t\t\t4C3157E820EB6D0600448776 /* TVCLogPolicyPrivate.h in Headers */,\n\t\t\t\t4C31557020EB6CB300448776 /* THOUnicodeHelper.h in Headers */,\n\t\t\t\t4C31558E20EB6CB300448776 /* TVCLogRenderer.h in Headers */,\n\t\t\t\t4C31559C20EB6CB300448776 /* TVCValidatedTextField.h in Headers */,\n\t\t\t\t4C31557120EB6CB300448776 /* TLOEncryptionManager.h in Headers */,\n\t\t\t\t4C3155A020EB6CB300448776 /* TXMasterController.h in Headers */,\n\t\t\t\t4C31579C20EB6D0600448776 /* TDCChannelBanListSheetPrivate.h in Headers */,\n\t\t\t\t4C31578020EB6D0600448776 /* IRCClientPrivate.h in Headers */,\n\t\t\t\t4C3157BA20EB6D0600448776 /* TDCServerChangeNicknameSheetPrivate.h in Headers */,\n\t\t\t\t4C31557E20EB6CB300448776 /* TPCPreferencesLocal.h in Headers */,\n\t\t\t\t4CAB27582537EE66009B1F07 /* IRCChannelMemberListPrivate.h in Headers */,\n\t\t\t\t4C3157B420EB6D0600448776 /* TDCLicenseUpgradeDialogPrivate.h in Headers */,\n\t\t\t\t4C31558520EB6CB300448776 /* TVCAppearance.h in Headers */,\n\t\t\t\t4C31557620EB6CB300448776 /* TLOpenLink.h in Headers */,\n\t\t\t\t4C06E28520EC4E870055D09A /* TLOLocalization.h in Headers */,\n\t\t\t\t4C3158BB20EB6D0F00448776 /* TDCFileTransferDialogInternal.h in Headers */,\n\t\t\t\t4C31555020EB6CB300448776 /* IRCChannelConfig.h in Headers */,\n\t\t\t\t4C31559320EB6CB300448776 /* TVCMainWindowSplitView.h in Headers */,\n\t\t\t\t4C3157DF20EB6D0600448776 /* TVCChannelSelectionOutlineViewCellPrivate.h in Headers */,\n\t\t\t\t4C3157A120EB6D0600448776 /* TDCChannelPropertiesSheetPrivate.h in Headers */,\n\t\t\t\t4C31579720EB6D0600448776 /* TDCAddressBookSheetPrivate.h in Headers */,\n\t\t\t\t4C3157E520EB6D0600448776 /* TVCLogControllerOperationQueuePrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4CCF2F9E15804C18006FFE21 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CB638CD2D45A06C002B2CC3 /* FeatureFlags.h in Headers */,\n\t\t\t\t4C31572C20EB6D0500448776 /* TDCServerPropertiesSheetPrivate.h in Headers */,\n\t\t\t\t4CAB27602537F71B009B1F07 /* IRCChannelMemberList.h in Headers */,\n\t\t\t\t4C31571520EB6D0500448776 /* TDCFileTransferDialogTableCellPrivate.h in Headers */,\n\t\t\t\t4C3156F720EB6D0500448776 /* IRCServerPrivate.h in Headers */,\n\t\t\t\t4C3158CE20EB6D1000448776 /* IRCHighlightLogEntryInternal.h in Headers */,\n\t\t\t\t4C31576620EB6D0500448776 /* TVCMemberListPrivate.h in Headers */,\n\t\t\t\t4C3155BC20EB6CB400448776 /* IRCWorld.h in Headers */,\n\t\t\t\t4C3156E720EB6D0500448776 /* IRCAddressBookUserTrackingPrivate.h in Headers */,\n\t\t\t\t4C3158C020EB6D1000448776 /* IRCUserInternal.h in Headers */,\n\t\t\t\t4C31571D20EB6D0500448776 /* TDCLicenseManagerMigrateAppStoreSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3FA20EC51380055D09A /* ICLInlineContentProtocol.h in Headers */,\n\t\t\t\t4C31572D20EB6D0500448776 /* TDCSharedProtocolDefinitionsPrivate.h in Headers */,\n\t\t\t\t4C3155AF20EB6CB400448776 /* IRCHighlightLogEntry.h in Headers */,\n\t\t\t\t4C06E26D20EC4C560055D09A /* NSObjectHelperPrivate.h in Headers */,\n\t\t\t\t4C06E28220EC4E870055D09A /* TPCPreferences.h in Headers */,\n\t\t\t\t4C3158CB20EB6D1000448776 /* IRCMessageInternal.h in Headers */,\n\t\t\t\t4C3155F620EB6CB400448776 /* TXGlobalModels.h in Headers */,\n\t\t\t\t4C31576820EB6D0500448776 /* TVCNotificationConfigurationViewControllerPrivate.h in Headers */,\n\t\t\t\t4C3155ED20EB6CB400448776 /* TVCMemberList.h in Headers */,\n\t\t\t\t4C3155DA20EB6CB400448776 /* TPCTheme.h in Headers */,\n\t\t\t\t4C31575E20EB6D0500448776 /* TVCMainWindowSegmentedControlPrivate.h in Headers */,\n\t\t\t\t4C3155C220EB6CB400448776 /* TDCSheetBase.h in Headers */,\n\t\t\t\t4C3155E820EB6CB400448776 /* TVCMainWindowAppearance.h in Headers */,\n\t\t\t\t4C31571320EB6D0500448776 /* TDCChannelSpotlightSearchResultsTablePrivate.h in Headers */,\n\t\t\t\t4C31570B20EB6D0500448776 /* TDCChannelModifyModesSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3FE20EC51380055D09A /* HLSHistoricLogProtocol.h in Headers */,\n\t\t\t\t4C31573920EB6D0500448776 /* TLOLicenseManagerDownloaderPrivate.h in Headers */,\n\t\t\t\t4C3156FC20EB6D0500448776 /* IRCUserPrivate.h in Headers */,\n\t\t\t\t4C31576E20EB6D0500448776 /* TVCWK1AutoScrollerPrivate.h in Headers */,\n\t\t\t\t4C31571120EB6D0500448776 /* TDCChannelSpotlightControlsPrivate.h in Headers */,\n\t\t\t\t4C3155F220EB6CB400448776 /* TVCValidatedComboBox.h in Headers */,\n\t\t\t\t4C3155C320EB6CB400448776 /* TDCWindowBase.h in Headers */,\n\t\t\t\t4C06E3B620EC51380055D09A /* GCDAsyncSocket.h in Headers */,\n\t\t\t\t4C31572E20EB6D0500448776 /* TDCWelcomeSheetPrivate.h in Headers */,\n\t\t\t\t4C31572F20EB6D0500448776 /* TextualPrivate.h in Headers */,\n\t\t\t\t4C3158CA20EB6D1000448776 /* IRCModeInfoInternal.h in Headers */,\n\t\t\t\t4C3156EF20EB6D0500448776 /* IRCColorFormatPrivate.h in Headers */,\n\t\t\t\t4C31571E20EB6D0500448776 /* TDCLicenseManagerRecoverLostLicenseSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3B220EC51380055D09A /* GCDAsyncSocketExtensions.h in Headers */,\n\t\t\t\t4C31574020EB6D0500448776 /* TPCApplicationInfoPrivate.h in Headers */,\n\t\t\t\t4C31576F20EB6D0500448776 /* TXAppearancePrivate.h in Headers */,\n\t\t\t\t4C3155AD20EB6CB400448776 /* IRCCommandIndex.h in Headers */,\n\t\t\t\t4C31570320EB6D0500448776 /* TDCAboutDialogPrivate.h in Headers */,\n\t\t\t\t4C31575420EB6D0500448776 /* TVCLogLinePrivate.h in Headers */,\n\t\t\t\t4C31570F20EB6D0500448776 /* TDCChannelSpotlightAppearancePrivate.h in Headers */,\n\t\t\t\t4C31575320EB6D0500448776 /* TVCLogControllerPrivate.h in Headers */,\n\t\t\t\t4C31574420EB6D0500448776 /* TPCPreferencesImportExportPrivate.h in Headers */,\n\t\t\t\t4C31572420EB6D0500448776 /* TDCPreferencesControllerPrivate.h in Headers */,\n\t\t\t\t4C31571C20EB6D0500448776 /* TDCLicenseManagerDialogPrivate.h in Headers */,\n\t\t\t\t4C3156F520EB6D0500448776 /* IRCMessageBatchPrivate.h in Headers */,\n\t\t\t\t4C31573A20EB6D0500448776 /* TLOLicenseManagerLastGenPrivate.h in Headers */,\n\t\t\t\t4C3155C520EB6CB400448776 /* TextualApplication.h in Headers */,\n\t\t\t\t4C3155E720EB6CB400448776 /* TVCMainWindow.h in Headers */,\n\t\t\t\t4C3155EB20EB6CB400448776 /* TVCMainWindowTextView.h in Headers */,\n\t\t\t\t4C06E26520EC4C560055D09A /* TPCPreferencesPrivate.h in Headers */,\n\t\t\t\t4C3158CD20EB6D1000448776 /* TDCChannelSpotlightControllerInternal.h in Headers */,\n\t\t\t\t4C06E25E20EC4BBD0055D09A /* IRCConnectionConfigInternal.h in Headers */,\n\t\t\t\t4C3155EC20EB6CB400448776 /* TVCMainWindowTextViewAppearance.h in Headers */,\n\t\t\t\t4C31574820EB6D0500448776 /* TPCResourceManagerPrivate.h in Headers */,\n\t\t\t\t4C06E41320EC52240055D09A /* TVCLogLineXPCPrivate.h in Headers */,\n\t\t\t\t4C31570D20EB6D0500448776 /* TDCChannelPropertiesNotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C3155BA20EB6CB400448776 /* IRCUser.h in Headers */,\n\t\t\t\t4C3155C620EB6CB400448776 /* THOPluginProtocol.h in Headers */,\n\t\t\t\t4C31571720EB6D0500448776 /* TDCHighlightEntrySheetPrivate.h in Headers */,\n\t\t\t\t4C31575620EB6D0500448776 /* TVCLogScriptEventSinkPrivate.h in Headers */,\n\t\t\t\t4C3158C520EB6D1000448776 /* IRCPrefixInternal.h in Headers */,\n\t\t\t\t4C06E3CA20EC51380055D09A /* ICLPayloadInternal.h in Headers */,\n\t\t\t\t4C31575B20EB6D0500448776 /* TVCMainWindowChannelViewPrivate.h in Headers */,\n\t\t\t\t4C31573220EB6D0500448776 /* THOPluginManagerPrivate.h in Headers */,\n\t\t\t\t4C3155D720EB6CB400448776 /* TPCPreferencesUserDefaultsLocal.h in Headers */,\n\t\t\t\t4C31574520EB6D0500448776 /* TPCPreferencesLocalPrivate.h in Headers */,\n\t\t\t\t4C31575820EB6D0500448776 /* TVCLogViewInternalWK2.h in Headers */,\n\t\t\t\t4C3155B220EB6CB400448776 /* IRCMessage.h in Headers */,\n\t\t\t\t4C3156FA20EB6D0500448776 /* IRCUserNicknameColorStyleGeneratorPrivate.h in Headers */,\n\t\t\t\t4C31572520EB6D0500448776 /* TDCPreferencesNotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C31577320EB6D0500448776 /* TXMenuControllerPrivate.h in Headers */,\n\t\t\t\t4C8878072C3371470016DB98 /* TPCSandboxMigrationPrivate.h in Headers */,\n\t\t\t\t4C3155E020EB6CB400448776 /* TVCChannelSelectionViewController.h in Headers */,\n\t\t\t\t4C3156E920EB6D0500448776 /* IRCChannelModePrivate.h in Headers */,\n\t\t\t\t4C31576120EB6D0500448776 /* TVCMainWindowTextViewAppearancePrivate.h in Headers */,\n\t\t\t\t4C3155C020EB6CB400448776 /* TDCAlert.h in Headers */,\n\t\t\t\t4C3155AA20EB6CB400448776 /* IRCClient.h in Headers */,\n\t\t\t\t4C31576A20EB6D0500448776 /* TVCServerListCellPrivate.h in Headers */,\n\t\t\t\t4C3158C220EB6D1000448776 /* TDCChannelPropertiesSheetInternal.h in Headers */,\n\t\t\t\t4C3156FB20EB6D0500448776 /* IRCUserPersistentStorePrivate.h in Headers */,\n\t\t\t\t4C3155EF20EB6CB400448776 /* TVCServerList.h in Headers */,\n\t\t\t\t4C31572020EB6D0500448776 /* TDCLicenseUpgradeCommonActionsPrivate.h in Headers */,\n\t\t\t\t4C3155E220EB6CB400448776 /* TVCErrorMessagePopoverPrivate.h in Headers */,\n\t\t\t\t4C31576B20EB6D0500448776 /* TVCServerListPrivate.h in Headers */,\n\t\t\t\t4C31573B20EB6D0500448776 /* TLOLicenseManagerPrivate.h in Headers */,\n\t\t\t\t4C31570020EB6D0500448776 /* NSTableVIewHelperPrivate.h in Headers */,\n\t\t\t\t4C3156F220EB6D0500448776 /* IRCExtrasPrivate.h in Headers */,\n\t\t\t\t4C3155CA20EB6CB400448776 /* TLOInternetAddressLookup.h in Headers */,\n\t\t\t\t4C3155C420EB6CB400448776 /* Textual.h in Headers */,\n\t\t\t\t4C3155AE20EB6CB400448776 /* IRCConnection.h in Headers */,\n\t\t\t\t4C3156F920EB6D0500448776 /* IRCTreeItemPrivate.h in Headers */,\n\t\t\t\t4C31572A20EB6D0500448776 /* TDCServerEndpointListSheetTablePrivate.h in Headers */,\n\t\t\t\t4C3158C920EB6D1000448776 /* IRCChannelUserInternal.h in Headers */,\n\t\t\t\t4C3155F920EB6CB400448776 /* TXSharedApplication.h in Headers */,\n\t\t\t\t4C7B05011D12110500295E82 /* BuildConfig.h in Headers */,\n\t\t\t\t4C3156EB20EB6D0500448776 /* IRCChannelUserPrivate.h in Headers */,\n\t\t\t\t4C31570120EB6D0500448776 /* NSViewHelperPrivate.h in Headers */,\n\t\t\t\t4C31571F20EB6D0500448776 /* TDCLicenseUpgradeActivateSheetPrivate.h in Headers */,\n\t\t\t\t4C3158CF20EB6D1000448776 /* IRCHighlightMatchConditionInternal.h in Headers */,\n\t\t\t\t4C3155E420EB6CB400448776 /* TVCLogLine.h in Headers */,\n\t\t\t\t4C3158C320EB6D1000448776 /* TDCChannelSpotlightAppearanceInternal.h in Headers */,\n\t\t\t\t4C31577420EB6D0500448776 /* TXSharedApplicationPrivate.h in Headers */,\n\t\t\t\t4C3156F820EB6D0500448776 /* IRCTimerCommandPrivate.h in Headers */,\n\t\t\t\t4C31573820EB6D0500448776 /* TLOInputHistoryPrivate.h in Headers */,\n\t\t\t\t4C31573F20EB6D0500448776 /* TLOSpokenNotificationPrivate.h in Headers */,\n\t\t\t\t4C3155DF20EB6CB400448776 /* TVCBasicTableView.h in Headers */,\n\t\t\t\t4C3155D920EB6CB400448776 /* TPCThemeController.h in Headers */,\n\t\t\t\t4C3155BE20EB6CB400448776 /* NSStringHelper.h in Headers */,\n\t\t\t\t4C31574920EB6D0500448776 /* TPCThemeControllerPrivate.h in Headers */,\n\t\t\t\t4C31573320EB6D0500448776 /* THOPluginProtocolPrivate.h in Headers */,\n\t\t\t\t4C31574F20EB6D0500448776 /* TVCDockIconPrivate.h in Headers */,\n\t\t\t\t4C3155DE20EB6CB400448776 /* TVCAutoExpandingTokenField.h in Headers */,\n\t\t\t\t4C3156E820EB6D0500448776 /* IRCChannelConfigPrivate.h in Headers */,\n\t\t\t\t4C3155E320EB6CB400448776 /* TVCLogController.h in Headers */,\n\t\t\t\t4C3158BF20EB6D1000448776 /* IRCServerInternal.h in Headers */,\n\t\t\t\t4C3155B320EB6CB400448776 /* IRCModeInfo.h in Headers */,\n\t\t\t\t4C3155B420EB6CB400448776 /* IRCNetworkList.h in Headers */,\n\t\t\t\t4C3156F120EB6D0500448776 /* IRCConnectionPrivate.h in Headers */,\n\t\t\t\t4C3155DB20EB6CB400448776 /* TVCAlert.h in Headers */,\n\t\t\t\t4C31573120EB6D0500448776 /* THOPluginItemPrivate.h in Headers */,\n\t\t\t\t4C3156E620EB6D0500448776 /* IRCAddressBookMatchCachePrivate.h in Headers */,\n\t\t\t\t4C3155D420EB6CB400448776 /* TPCPreferencesImportExport.h in Headers */,\n\t\t\t\t4C3155B720EB6CB400448776 /* IRCSendingMessage.h in Headers */,\n\t\t\t\t4C3155D120EB6CB400448776 /* TPCPathInfo.h in Headers */,\n\t\t\t\t4C3155A620EB6CB400448776 /* IRCChannel.h in Headers */,\n\t\t\t\t4C3155CB20EB6CB400448776 /* TLOKeyEventHandler.h in Headers */,\n\t\t\t\t4C3158E420EB6D1600448776 /* OELReachability.h in Headers */,\n\t\t\t\t4C3155AC20EB6CB400448776 /* IRCColorFormat.h in Headers */,\n\t\t\t\t4C3158C720EB6D1000448776 /* IRCClientConfigInternal.h in Headers */,\n\t\t\t\t4C3155F820EB6CB400448776 /* TXMenuController.h in Headers */,\n\t\t\t\t4C3155B120EB6CB400448776 /* IRCISupportInfo.h in Headers */,\n\t\t\t\t4C31577520EB6D0500448776 /* TXWindowControllerPrivate.h in Headers */,\n\t\t\t\t4C31574120EB6D0500448776 /* TPCPathInfoPrivate.h in Headers */,\n\t\t\t\t4CEFEDAB22B4AF42002CEE19 /* TDCPreferencesUserStyleSheetPrivate.h in Headers */,\n\t\t\t\t4C3155EE20EB6CB400448776 /* TVCMemberListAppearance.h in Headers */,\n\t\t\t\t4C3158E320EB6D1600448776 /* GTMEncodeHTML.h in Headers */,\n\t\t\t\t4C31572B20EB6D0500448776 /* TDCServerHighlightListSheetPrivate.h in Headers */,\n\t\t\t\t4C06E27220EC4E350055D09A /* StaticDefinitions.h in Headers */,\n\t\t\t\t4C31577120EB6D0500448776 /* TXGlobalModelsPrivate.h in Headers */,\n\t\t\t\t4C31577620EB6D0500448776 /* WKWebViewPrivate.h in Headers */,\n\t\t\t\t4C31571620EB6D0500448776 /* TDCFileTransferDialogTransferControllerPrivate.h in Headers */,\n\t\t\t\t4C31575720EB6D0500448776 /* TVCLogViewInternalWK1.h in Headers */,\n\t\t\t\t4C3155CF20EB6CB400448776 /* TLOSoundPlayer.h in Headers */,\n\t\t\t\t4C3155D020EB6CB400448776 /* TPCApplicationInfo.h in Headers */,\n\t\t\t\t4C31571420EB6D0500448776 /* TDCFileTransferDialogPrivate.h in Headers */,\n\t\t\t\t4C3156F020EB6D0500448776 /* IRCCommandIndexPrivate.h in Headers */,\n\t\t\t\t4C3155F420EB6CB400448776 /* TXAppearance.h in Headers */,\n\t\t\t\t4C31574A20EB6D0500448776 /* TPCThemePrivate.h in Headers */,\n\t\t\t\t4C3155A420EB6CB400448776 /* IRCAddressBook.h in Headers */,\n\t\t\t\t4C31573E20EB6D0500448776 /* TLOSpeechSynthesizerPrivate.h in Headers */,\n\t\t\t\t4C06E24A20EC4B970055D09A /* IRCConnectionConfig.h in Headers */,\n\t\t\t\t4C3155CC20EB6CB400448776 /* TLOLinkParser.h in Headers */,\n\t\t\t\t4C06E3F620EC51380055D09A /* RCMConnectionManagerProtocol.h in Headers */,\n\t\t\t\t4C3156EC20EB6D0500448776 /* IRCClientConfigPrivate.h in Headers */,\n\t\t\t\t4C31577220EB6D0500448776 /* TXMasterControllerPrivate.h in Headers */,\n\t\t\t\t4C31576020EB6D0500448776 /* TVCMainWindowSplitViewPrivate.h in Headers */,\n\t\t\t\t4C31576720EB6D0500448776 /* TVCMemberListUserInfoPopoverPrivate.h in Headers */,\n\t\t\t\t4C31570C20EB6D0500448776 /* TDCChannelModifyTopicSheetPrivate.h in Headers */,\n\t\t\t\t4C3156FE20EB6D0500448776 /* IRCWorldPrivate.h in Headers */,\n\t\t\t\t4C3155F120EB6CB400448776 /* TVCTextViewWithIRCFormatter.h in Headers */,\n\t\t\t\t4C31576D20EB6D0500448776 /* TVCTextViewWithIRCFormatterPrivate.h in Headers */,\n\t\t\t\t4C31575920EB6D0500448776 /* TVCLogViewPrivate.h in Headers */,\n\t\t\t\t4C31576C20EB6D0500448776 /* TVCTextFormatterMenuPrivate.h in Headers */,\n\t\t\t\t4C3155BF20EB6CB400448776 /* NSViewHelper.h in Headers */,\n\t\t\t\t4C31576220EB6D0500448776 /* TVCMainWindowTextViewPrivate.h in Headers */,\n\t\t\t\t4C31572620EB6D0500448776 /* TDCProgressIndicatorSheetPrivate.h in Headers */,\n\t\t\t\t4C06E3D620EC51380055D09A /* ICLPayload.h in Headers */,\n\t\t\t\t4C8F3FD82C31AF7700118AAF /* THOPluginManager.h in Headers */,\n\t\t\t\t4C31575120EB6D0500448776 /* TVCLogControllerInlineMediaServicePrivate.h in Headers */,\n\t\t\t\t4C31572320EB6D0500448776 /* TDCNicknameColorSheetPrivate.h in Headers */,\n\t\t\t\t4C3156F320EB6D0500448776 /* IRCHighlightLogEntryPrivate.h in Headers */,\n\t\t\t\t4C3158C620EB6D1000448776 /* IRCChannelConfigInternal.h in Headers */,\n\t\t\t\t4C3155E120EB6CB400448776 /* TVCErrorMessagePopoverControllerPrivate.h in Headers */,\n\t\t\t\t4C31571220EB6D0500448776 /* TDCChannelSpotlightSearchResultPrivate.h in Headers */,\n\t\t\t\t4C31573520EB6D0500448776 /* TLOEncryptionManagerPrivate.h in Headers */,\n\t\t\t\t4C3156E420EB6D0500448776 /* WebScriptObjectHelperPrivate.h in Headers */,\n\t\t\t\t4C31576420EB6D0500448776 /* TVCMemberListAppearancePrivate.h in Headers */,\n\t\t\t\t4C3155D820EB6CB400448776 /* TPCResourceManager.h in Headers */,\n\t\t\t\t4C31573D20EB6D0500448776 /* TLONotificationConfigurationPrivate.h in Headers */,\n\t\t\t\t4C31570A20EB6D0500448776 /* TDCChannelInviteSheetPrivate.h in Headers */,\n\t\t\t\t4C3155E620EB6CB400448776 /* TVCLogView.h in Headers */,\n\t\t\t\t4C3155A320EB6CB400448776 /* IRC.h in Headers */,\n\t\t\t\t4C3155C120EB6CB400448776 /* TDCInputPrompt.h in Headers */,\n\t\t\t\t4C31572220EB6D0500448776 /* TDCLicenseUpgradeEligibilitySheetPrivate.h in Headers */,\n\t\t\t\t4C31575A20EB6D0500448776 /* TVCMainWindowAppearancePrivate.h in Headers */,\n\t\t\t\t4C06E27E20EC4E870055D09A /* TPCPreferencesUserDefaults.h in Headers */,\n\t\t\t\t4C3156F420EB6D0500448776 /* IRCISupportInfoPrivate.h in Headers */,\n\t\t\t\t4C5274E320F8D78800B18F9D /* IRCConnectionErrors.h in Headers */,\n\t\t\t\t4C06E27A20EC4E870055D09A /* TLOTimer.h in Headers */,\n\t\t\t\t4C3155A920EB6CB400448776 /* IRCChannelUser.h in Headers */,\n\t\t\t\t4C31576920EB6D0500448776 /* TVCServerListAppearancePrivate.h in Headers */,\n\t\t\t\t4C31571020EB6D0500448776 /* TDCChannelSpotlightControllerPrivate.h in Headers */,\n\t\t\t\t4C31573C20EB6D0500448776 /* TLONicknameCompletionStatusPrivate.h in Headers */,\n\t\t\t\t4C3156F620EB6D0500448776 /* IRCMessagePrivate.h in Headers */,\n\t\t\t\t4C3156EA20EB6D0500448776 /* IRCChannelPrivate.h in Headers */,\n\t\t\t\t4C31573620EB6D0500448776 /* TLOFileLoggerPrivate.h in Headers */,\n\t\t\t\t4C3155A820EB6CB400448776 /* IRCChannelMode.h in Headers */,\n\t\t\t\t4C31574E20EB6D0500448776 /* TVCContentNavigationOutlineViewPrivate.h in Headers */,\n\t\t\t\t4C3155B920EB6CB400448776 /* IRCTreeItem.h in Headers */,\n\t\t\t\t4C06E26920EC4C560055D09A /* TPCPreferencesUserDefaultsPrivate.h in Headers */,\n\t\t\t\t4C3155E920EB6CB400448776 /* TVCMainWindowLoadingScreen.h in Headers */,\n\t\t\t\t4C3158C820EB6D1000448776 /* TVCLogLineInternal.h in Headers */,\n\t\t\t\t4C3155BB20EB6CB400448776 /* IRCUserRelations.h in Headers */,\n\t\t\t\t4C31575C20EB6D0500448776 /* TVCMainWindowLoadingScreenPrivate.h in Headers */,\n\t\t\t\t4C3155B820EB6CB400448776 /* IRCServer.h in Headers */,\n\t\t\t\t4C31570220EB6D0500448776 /* SwiftBridgingHeaderPrivate.h in Headers */,\n\t\t\t\t4C3156EE20EB6D0500448776 /* IRCClientRequestedCommandsPrivate.h in Headers */,\n\t\t\t\t4C3155B520EB6CB400448776 /* IRCNumerics.h in Headers */,\n\t\t\t\t4C3155B620EB6CB400448776 /* IRCPrefix.h in Headers */,\n\t\t\t\t4C31575020EB6D0500448776 /* TVCLogControllerHistoricLogFilePrivate.h in Headers */,\n\t\t\t\t4CAB276D253863D9009B1F07 /* IRCChannelMemberListControllerPrivate.h in Headers */,\n\t\t\t\t4C06E41820EC52D60055D09A /* ICLPayloadLocalPrivate.h in Headers */,\n\t\t\t\t4C3155D620EB6CB400448776 /* TPCPreferencesReload.h in Headers */,\n\t\t\t\t4C3155C920EB6CB400448776 /* TLONotificationController.h in Headers */,\n\t\t\t\t4C31572820EB6D0500448776 /* TDCServerChannelListDialogPrivate.h in Headers */,\n\t\t\t\t4C3155A520EB6CB400448776 /* IRCAddressBookUserTracking.h in Headers */,\n\t\t\t\t4C31573720EB6D0500448776 /* TLONotificationControllerPrivate.h in Headers */,\n\t\t\t\t4C31572920EB6D0500448776 /* TDCServerEndpointListSheetPrivate.h in Headers */,\n\t\t\t\t4C31576320EB6D0500448776 /* TVCMainWindowTitlebarAccessoryViewPrivate.h in Headers */,\n\t\t\t\t4C31577020EB6D0500448776 /* TXApplicationPrivate.h in Headers */,\n\t\t\t\t4C31575D20EB6D0500448776 /* TVCMainWindowPrivate.h in Headers */,\n\t\t\t\t4C3158C120EB6D1000448776 /* IRCAddressBookInternal.h in Headers */,\n\t\t\t\t4C3155F520EB6CB400448776 /* TXAppearanceHelper.h in Headers */,\n\t\t\t\t4C3155AB20EB6CB400448776 /* IRCClientConfig.h in Headers */,\n\t\t\t\t4C31574B20EB6D0500448776 /* TVCAppearancePrivate.h in Headers */,\n\t\t\t\t4C31573020EB6D0500448776 /* THOPluginDispatcherPrivate.h in Headers */,\n\t\t\t\t4C3155BD20EB6CB400448776 /* NSColorHelper.h in Headers */,\n\t\t\t\t4C3155B020EB6CB400448776 /* IRCHighlightMatchCondition.h in Headers */,\n\t\t\t\t4C3155DD20EB6CB400448776 /* TVCAutoExpandingTextField.h in Headers */,\n\t\t\t\t4C3155F020EB6CB400448776 /* TVCServerListAppearance.h in Headers */,\n\t\t\t\t4C31576520EB6D0500448776 /* TVCMemberListCellPrivate.h in Headers */,\n\t\t\t\t4C3156FD20EB6D0500448776 /* IRCUserRelationsPrivate.h in Headers */,\n\t\t\t\t4C31574D20EB6D0500448776 /* TVCChannelSelectionViewControllerPrivate.h in Headers */,\n\t\t\t\t4C31575520EB6D0500448776 /* TVCLogPolicyPrivate.h in Headers */,\n\t\t\t\t4C3155C720EB6CB400448776 /* THOUnicodeHelper.h in Headers */,\n\t\t\t\t4C3155E520EB6CB400448776 /* TVCLogRenderer.h in Headers */,\n\t\t\t\t4C3155F320EB6CB400448776 /* TVCValidatedTextField.h in Headers */,\n\t\t\t\t4C3155C820EB6CB400448776 /* TLOEncryptionManager.h in Headers */,\n\t\t\t\t4C3155F720EB6CB400448776 /* TXMasterController.h in Headers */,\n\t\t\t\t4C31570920EB6D0500448776 /* TDCChannelBanListSheetPrivate.h in Headers */,\n\t\t\t\t4C3156ED20EB6D0500448776 /* IRCClientPrivate.h in Headers */,\n\t\t\t\t4C31572720EB6D0500448776 /* TDCServerChangeNicknameSheetPrivate.h in Headers */,\n\t\t\t\t4C3155D520EB6CB400448776 /* TPCPreferencesLocal.h in Headers */,\n\t\t\t\t4CAB27592537EE66009B1F07 /* IRCChannelMemberListPrivate.h in Headers */,\n\t\t\t\t4C31572120EB6D0500448776 /* TDCLicenseUpgradeDialogPrivate.h in Headers */,\n\t\t\t\t4C3155DC20EB6CB400448776 /* TVCAppearance.h in Headers */,\n\t\t\t\t4C3155CD20EB6CB400448776 /* TLOpenLink.h in Headers */,\n\t\t\t\t4C06E28620EC4E870055D09A /* TLOLocalization.h in Headers */,\n\t\t\t\t4C3158CC20EB6D1000448776 /* TDCFileTransferDialogInternal.h in Headers */,\n\t\t\t\t4C3155A720EB6CB400448776 /* IRCChannelConfig.h in Headers */,\n\t\t\t\t4C3155EA20EB6CB400448776 /* TVCMainWindowSplitView.h in Headers */,\n\t\t\t\t4C31574C20EB6D0500448776 /* TVCChannelSelectionOutlineViewCellPrivate.h in Headers */,\n\t\t\t\t4C31570E20EB6D0500448776 /* TDCChannelPropertiesSheetPrivate.h in Headers */,\n\t\t\t\t4C31570420EB6D0500448776 /* TDCAddressBookSheetPrivate.h in Headers */,\n\t\t\t\t4C31575220EB6D0500448776 /* TVCLogControllerOperationQueuePrivate.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t4C1DC5511580420500A47BC9 /* Textual (Standard Release) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4C1DC5701580420500A47BC9 /* Build configuration list for PBXNativeTarget \"Textual (Standard Release)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4C1DC5501580420500A47BC9 /* Resources */,\n\t\t\t\t4CEA6AA42C36F8E700A36551 /* Copy Preference Resources */,\n\t\t\t\t4C9E534415B4C171000E84A9 /* Copy Acknowledgements */,\n\t\t\t\t4C1DC54F1580420500A47BC9 /* Frameworks */,\n\t\t\t\t4C1DC54E1580420500A47BC9 /* Sources */,\n\t\t\t\t4CCF2F9E15804C18006FFE21 /* Headers */,\n\t\t\t\t4C06E48020EC541C0055D09A /* Embed Frameworks */,\n\t\t\t\t4C2BEB612C384E16008F8F0D /* Postprocess Sparkle */,\n\t\t\t\t4C01BA101581104D007E2DAF /* Build Extensions */,\n\t\t\t\t4C52AED515811C2000940619 /* Copy Extensions */,\n\t\t\t\t4C761BAF1E155D7400A505B7 /* Build XPC Services */,\n\t\t\t\t4C761BA61E155C6E00A505B7 /* Copy XPC Services */,\n\t\t\t\t4C48B46620E4D38F00CF5F84 /* Merge Swift Libraries */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t4CBB842D16F0DA1D004E3ED6 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = \"Textual (Standard Release)\";\n\t\t\tproductName = Textual;\n\t\t\tproductReference = 4C1DC5521580420500A47BC9 /* Textual.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t4C5BA37216F1302F00A96CA2 /* Textual (Debug) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4C5BA4E116F1302F00A96CA2 /* Build configuration list for PBXNativeTarget \"Textual (Debug)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4C5BA37916F1302F00A96CA2 /* Resources */,\n\t\t\t\t4CEA6AA92C36F91400A36551 /* Copy Preference Resources */,\n\t\t\t\t4C5BA4DC16F1302F00A96CA2 /* Copy Acknowledgements */,\n\t\t\t\t4C5BA45716F1302F00A96CA2 /* Frameworks */,\n\t\t\t\t4C0444F316F1602900EBB665 /* Sources */,\n\t\t\t\t4C5BA3D916F1302F00A96CA2 /* Headers */,\n\t\t\t\t4C06E44320EC539E0055D09A /* Embed Frameworks */,\n\t\t\t\t4CEE0BDB268F3C68004CB3C3 /* Build Extensions */,\n\t\t\t\t4CEE0BDC268F3C8D004CB3C3 /* Copy Extensions */,\n\t\t\t\t4C761BB01E155DD900A505B7 /* Build XPC Services */,\n\t\t\t\t4C761BA41E155C4300A505B7 /* Copy XPC Services */,\n\t\t\t\t4C48B46520E4D37C00CF5F84 /* Merge Swift Libraries */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Textual (Debug)\";\n\t\t\tproductName = Textual;\n\t\t\tproductReference = 4C5BA4E616F1302F00A96CA2 /* Textual.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4C1DC5491580420500A47BC9 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tORGANIZATIONNAME = \"Codeux Software, LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4C1DC5511580420500A47BC9 = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tDevelopmentTeamName = \"Codeux Software, LLC\";\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.ApplicationGroups.Mac = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t4C5BA37216F1302F00A96CA2 = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tDevelopmentTeamName = \"Codeux Software, LLC\";\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tSystemCapabilities = {\n\t\t\t\t\t\t\tcom.apple.ApplicationGroups.Mac = {\n\t\t\t\t\t\t\t\tenabled = 1;\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t\t4CCF301015804DCE006FFE21 = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4C1DC54C1580420500A47BC9 /* Build configuration list for PBXProject \"Textual App\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4C1DC5471580420500A47BC9;\n\t\t\tproductRefGroup = 4C1DC5531580420500A47BC9 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4C5BA37216F1302F00A96CA2 /* Textual (Debug) */,\n\t\t\t\t4C1DC5511580420500A47BC9 /* Textual (Standard Release) */,\n\t\t\t\t4CCF301015804DCE006FFE21 /* Build Frameworks */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4C1DC5501580420500A47BC9 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E07820EC4A540055D09A /* FormattingColor_8.png in Resources */,\n\t\t\t\t4C06E1DC20EC4AC40055D09A /* TDCNicknameColorSheet.xib in Resources */,\n\t\t\t\t4C06E20820EC4AC50055D09A /* TDCLicenseManagerDialog.xib in Resources */,\n\t\t\t\t4C06E11C20EC4A630055D09A /* TPWTB_Style@2x.png in Resources */,\n\t\t\t\t4C06DFE520EC49FB0055D09A /* MainWindowSpotlightIconTemplate.pdf in Resources */,\n\t\t\t\t4CEFEDB222B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings in Resources */,\n\t\t\t\t4C06E2EE20EC4FF00055D09A /* BasicLanguage.strings in Resources */,\n\t\t\t\t4C06E08320EC4A540055D09A /* FormattingColor_4.png in Resources */,\n\t\t\t\t4CAC9D7B1F2B076100AD5F12 /* Textual-Extras.pkg in Resources */,\n\t\t\t\t4C06E0D120EC4A5B0055D09A /* channelRoomStatusIconLightInactive@2x.tif in Resources */,\n\t\t\t\t4C06E21020EC4AC50055D09A /* TVCMemberListAppearance.plist in Resources */,\n\t\t\t\t4C06E07B20EC4A540055D09A /* FormattingColor_10.png in Resources */,\n\t\t\t\t4C06E08020EC4A540055D09A /* FormattingColor_15.png in Resources */,\n\t\t\t\t4C06E11D20EC4A630055D09A /* TPWTB_General@2x.png in Resources */,\n\t\t\t\t4C06E32A20EC4FF00055D09A /* TVCNotificationConfigurationView.strings in Resources */,\n\t\t\t\t4C06E08520EC4A540055D09A /* FormattingColor_1.png in Resources */,\n\t\t\t\t4C06E02020EC4A060055D09A /* DIRedBadgeRight.png in Resources */,\n\t\t\t\t4C06E1C420EC4AC40055D09A /* TVCChannelSelectionView.xib in Resources */,\n\t\t\t\t4C06E03920EC4A0F0055D09A /* DIGreenBadgeRight.png in Resources */,\n\t\t\t\t4C06E04E20EC4A2F0055D09A /* applicationIcon.iconset in Resources */,\n\t\t\t\t4C06E1FC20EC4AC50055D09A /* TDCAboutDialog.xib in Resources */,\n\t\t\t\t4C06E05320EC4A3D0055D09A /* Copyright Information for Images.txt in Resources */,\n\t\t\t\t4C06E07A20EC4A540055D09A /* FormattingColor_11.png in Resources */,\n\t\t\t\t4C06E1CC20EC4AC40055D09A /* TVCNotificationConfigurationView.xib in Resources */,\n\t\t\t\t4C06DF3520EC49A60055D09A /* IRCNetworks.plist in Resources */,\n\t\t\t\t4C06E1EC20EC4AC50055D09A /* TVCAlert.xib in Resources */,\n\t\t\t\t4C06E32220EC4FF00055D09A /* Notifications.strings in Resources */,\n\t\t\t\t4C06E2F620EC4FF00055D09A /* TDCChannelPropertiesSheet.strings in Resources */,\n\t\t\t\t4C06E32E20EC4FF00055D09A /* TDCServerEndpointListSheet.strings in Resources */,\n\t\t\t\t4C06E31220EC4FF00055D09A /* IRC.strings in Resources */,\n\t\t\t\t4C06E1E420EC4AC40055D09A /* TDCProgressIndicatorSheet.xib in Resources */,\n\t\t\t\t4C06E34220EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings in Resources */,\n\t\t\t\t4C06DFE620EC49FB0055D09A /* ErroneousTextFieldValueIndicator.tif in Resources */,\n\t\t\t\t4C06E03820EC4A0F0055D09A /* DIGreenBadgeLeft.png in Resources */,\n\t\t\t\t4C06DF4420EC49B90055D09A /* RemoteLicenseSystemPublicKey.pub in Resources */,\n\t\t\t\t4C06E19C20EC4AC40055D09A /* TDCChannelModifyModesSheet.xib in Resources */,\n\t\t\t\t4C06E0CD20EC4A5B0055D09A /* channelRoomStatusIconLightActive.tif in Resources */,\n\t\t\t\t4C06E0CC20EC4A5B0055D09A /* channelRoomStatusIconDarkActive.tif in Resources */,\n\t\t\t\t4C06E11820EC4A630055D09A /* TPWTB_Highlights@2x.png in Resources */,\n\t\t\t\t4C06E08120EC4A540055D09A /* FormattingColor_7.png in Resources */,\n\t\t\t\t4C17305622B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib in Resources */,\n\t\t\t\t4C06E1D820EC4AC40055D09A /* TDCChannelInviteSheet.xib in Resources */,\n\t\t\t\t4C06E03A20EC4A0F0055D09A /* DIGreenBadgeCenter.png in Resources */,\n\t\t\t\t4C06E19820EC4AC40055D09A /* TDCServerEndpointListSheet.xib in Resources */,\n\t\t\t\t4C06DF3920EC49A60055D09A /* TemplateLineTypes.plist in Resources */,\n\t\t\t\t4C06E11920EC4A630055D09A /* TPWTB_Addons.png in Resources */,\n\t\t\t\t4C06E2F220EC4FF00055D09A /* Accessibility.strings in Resources */,\n\t\t\t\t4C06E11B20EC4A630055D09A /* TPWTB_Controls.png in Resources */,\n\t\t\t\t4C33341E20CC471A00ACB9AD /* Bundled Scripts in Resources */,\n\t\t\t\t4C06DF3420EC49A60055D09A /* IRCCommandIndexRemoteData.plist in Resources */,\n\t\t\t\t4C33342320CC475300ACB9AD /* Bundled Styles in Resources */,\n\t\t\t\t4C06E07C20EC4A540055D09A /* FormattingColor_12.png in Resources */,\n\t\t\t\t4C06E1D020EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib in Resources */,\n\t\t\t\t4C06E12020EC4A630055D09A /* TPWTB_Controls@2x.png in Resources */,\n\t\t\t\t4C06E20C20EC4AC50055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib in Resources */,\n\t\t\t\t4C06E1AC20EC4AC40055D09A /* TDCChannelBanListSheet.xib in Resources */,\n\t\t\t\t4C06E12220EC4A630055D09A /* TPWTB_Interface@2x.png in Resources */,\n\t\t\t\t4C06E2FE20EC4FF00055D09A /* TDCPreferencesController.strings in Resources */,\n\t\t\t\t4C06E1A820EC4AC40055D09A /* TDCServerChannelListDialog.xib in Resources */,\n\t\t\t\t4C06E0C820EC4A5B0055D09A /* channelRoomStatusIconDarkActive@2x.tif in Resources */,\n\t\t\t\t4C06E30620EC4FF00055D09A /* TDCChannelInviteSheet.strings in Resources */,\n\t\t\t\t4C06E22820EC4AC50055D09A /* TVCMainWindowAppearance.plist in Resources */,\n\t\t\t\t4C06E05D20EC4A4C0055D09A /* encryptionLockIconLight.tif in Resources */,\n\t\t\t\t4C06E11A20EC4A630055D09A /* TPWTB_Advanced.png in Resources */,\n\t\t\t\t4C06E08620EC4A540055D09A /* FormattingColor_Rainbow@2x.tif in Resources */,\n\t\t\t\t4C06E19420EC4AC40055D09A /* TDCServerHighlightListSheet.xib in Resources */,\n\t\t\t\t4C06E0CA20EC4A5B0055D09A /* channelRoomStatusIconDarkInactive@2x.tif in Resources */,\n\t\t\t\t4C06E0C720EC4A5B0055D09A /* channelRoomStatusIconLightActive@2x.tif in Resources */,\n\t\t\t\t4C06E1C820EC4AC40055D09A /* TXCMainMenu.xib in Resources */,\n\t\t\t\t4C06E23020EC4AC50055D09A /* TVCServerListAppearance.plist in Resources */,\n\t\t\t\t4C06E30A20EC4FF00055D09A /* TDCAboutDialog.strings in Resources */,\n\t\t\t\t4C06E0C920EC4A5B0055D09A /* channelRoomStatusIconLightInactive.tif in Resources */,\n\t\t\t\t4C06E2E220EC4FF00055D09A /* OffTheRecord.strings in Resources */,\n\t\t\t\t4C06DFEB20EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif in Resources */,\n\t\t\t\t4C06E2E620EC4FF00055D09A /* CommonErrors.strings in Resources */,\n\t\t\t\t4C06E30E20EC4FF00055D09A /* TDCServerPropertiesSheet.strings in Resources */,\n\t\t\t\t4C06E2FA20EC4FF00055D09A /* TDCChannelBanListSheet.strings in Resources */,\n\t\t\t\t4C06E1B420EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib in Resources */,\n\t\t\t\t4C06E07F20EC4A540055D09A /* FormattingColor_14.png in Resources */,\n\t\t\t\t4C06E08720EC4A540055D09A /* FormattingColor_0.png in Resources */,\n\t\t\t\t4C06DFED20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif in Resources */,\n\t\t\t\t4C06E1D420EC4AC40055D09A /* TDCPreferences.xib in Resources */,\n\t\t\t\t4C06E04F20EC4A2F0055D09A /* applicationIconBirthday.icns in Resources */,\n\t\t\t\t4C06E02120EC4A060055D09A /* DIRedBadgeLeft.png in Resources */,\n\t\t\t\t4C06E02220EC4A060055D09A /* DIRedBadgeCenter.png in Resources */,\n\t\t\t\t4C06E18C20EC4AC40055D09A /* TDCServerPropertiesSheet.xib in Resources */,\n\t\t\t\t4C06E20020EC4AC50055D09A /* TDCHighlightEntrySheet.xib in Resources */,\n\t\t\t\t4C06DF3820EC49A60055D09A /* StaticStore.plist in Resources */,\n\t\t\t\t4C06E12120EC4A630055D09A /* TPWTB_Interface.png in Resources */,\n\t\t\t\t4C06E22C20EC4AC50055D09A /* TVCMainWindowTextViewAppearance.plist in Resources */,\n\t\t\t\t4C06E11E20EC4A630055D09A /* TPWTB_Addons@2x.png in Resources */,\n\t\t\t\t4C06E08820EC4A540055D09A /* FormattingColor_2.png in Resources */,\n\t\t\t\t4CCD93FF1CA7291300335381 /* JavaScript in Resources */,\n\t\t\t\t4C06E07D20EC4A540055D09A /* FormattingColor_Rainbow.tif in Resources */,\n\t\t\t\t4C06E31A20EC4FF00055D09A /* TDCChannelModifyModesSheet.strings in Resources */,\n\t\t\t\t4C06E2DE20EC4FF00055D09A /* Prompts.strings in Resources */,\n\t\t\t\t4C06E33A20EC4FF00055D09A /* TDCAddressBookSheet.strings in Resources */,\n\t\t\t\t4C06E1B020EC4AC40055D09A /* TDCChannelPropertiesSheet.xib in Resources */,\n\t\t\t\t4C06E05C20EC4A4C0055D09A /* encryptionLockIconDark@2x.tif in Resources */,\n\t\t\t\t4C06E1F820EC4AC50055D09A /* TDCChannelModifyTopicSheet.xib in Resources */,\n\t\t\t\t4C06E1F420EC4AC50055D09A /* TDCServerChangeNicknameSheet.xib in Resources */,\n\t\t\t\t4C06E07E20EC4A540055D09A /* FormattingColor_13.png in Resources */,\n\t\t\t\t4C06E08220EC4A540055D09A /* FormattingColor_6.png in Resources */,\n\t\t\t\t4C06E12420EC4A630055D09A /* TPWTB_Style.png in Resources */,\n\t\t\t\t4C06E1E820EC4AC50055D09A /* TDCAddressBookSheet.xib in Resources */,\n\t\t\t\t4C06E1A020EC4AC40055D09A /* TDCChannelSpotlightController.xib in Resources */,\n\t\t\t\t4C06E0CF20EC4A5B0055D09A /* channelRoomStatusIconDarkInactive.tif in Resources */,\n\t\t\t\t4C06E05A20EC4A4C0055D09A /* encryptionLockIconLight@2x.tif in Resources */,\n\t\t\t\t4C06E05B20EC4A4C0055D09A /* encryptionLockIconDark.tif in Resources */,\n\t\t\t\t4C06E31E20EC4FF00055D09A /* TVCMainWindow.strings in Resources */,\n\t\t\t\t4C06E08920EC4A540055D09A /* FormattingColor_3.png in Resources */,\n\t\t\t\t4C06DFE820EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif in Resources */,\n\t\t\t\t4C06E11F20EC4A630055D09A /* TPWTB_Notifications@2x.png in Resources */,\n\t\t\t\t4C06E33E20EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings in Resources */,\n\t\t\t\t4C06E11720EC4A630055D09A /* TPWTB_Highlights.png in Resources */,\n\t\t\t\t4C06DFE420EC49FB0055D09A /* MainWindowSegmentedControlUserTemplate.pdf in Resources */,\n\t\t\t\t4C06E07920EC4A540055D09A /* FormattingColor_9.png in Resources */,\n\t\t\t\t4C52379415C18F6700414852 /* Style Default Templates in Resources */,\n\t\t\t\t4C06E30220EC4FF00055D09A /* TDCFileTransferDialog.strings in Resources */,\n\t\t\t\t4C06DFEE20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif in Resources */,\n\t\t\t\t4C06E31620EC4FF00055D09A /* TLOLicenseManager.strings in Resources */,\n\t\t\t\t4C06E12320EC4A630055D09A /* TPWTB_Notifications.png in Resources */,\n\t\t\t\t4C06E1E020EC4AC40055D09A /* TDCWelcomeSheet.xib in Resources */,\n\t\t\t\t4C06E12520EC4A630055D09A /* TPWTB_General.png in Resources */,\n\t\t\t\t4C06E33220EC4FF00055D09A /* TDCServerChannelListDialog.strings in Resources */,\n\t\t\t\t4C06E33620EC4FF00055D09A /* TDCChannelSpotlightController.strings in Resources */,\n\t\t\t\t4C06E1A420EC4AC40055D09A /* TDCFileTransferDialog.xib in Resources */,\n\t\t\t\t4C06DFEC20EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive.tif in Resources */,\n\t\t\t\t4C06DFE720EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */,\n\t\t\t\t4C06E08420EC4A540055D09A /* FormattingColor_5.png in Resources */,\n\t\t\t\t4C06E11620EC4A630055D09A /* TPWTB_Advanced@2x.png in Resources */,\n\t\t\t\t4C06E1F020EC4AC50055D09A /* TDCLicenseUpgradeDialog.xib in Resources */,\n\t\t\t\t4C06DF3320EC49A60055D09A /* IRCCommandIndexLocalData.plist in Resources */,\n\t\t\t\t4C06E22420EC4AC50055D09A /* TDCChannelSpotlightAppearance.plist in Resources */,\n\t\t\t\t4C06E1BC20EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib in Resources */,\n\t\t\t\t4C06E20420EC4AC50055D09A /* TVCMainWindow.xib in Resources */,\n\t\t\t\t4C06DFEF20EC49FB0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif in Resources */,\n\t\t\t\t4C06DFF020EC49FB0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C5BA37916F1302F00A96CA2 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E08A20EC4A540055D09A /* FormattingColor_8.png in Resources */,\n\t\t\t\t4C06E1DB20EC4AC40055D09A /* TDCNicknameColorSheet.xib in Resources */,\n\t\t\t\t4C06E20720EC4AC50055D09A /* TDCLicenseManagerDialog.xib in Resources */,\n\t\t\t\t4C06E10C20EC4A630055D09A /* TPWTB_Style@2x.png in Resources */,\n\t\t\t\t4C06DFCA20EC49FA0055D09A /* MainWindowSpotlightIconTemplate.pdf in Resources */,\n\t\t\t\t4CEFEDB122B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings in Resources */,\n\t\t\t\t4C06E2ED20EC4FF00055D09A /* BasicLanguage.strings in Resources */,\n\t\t\t\t4C06E09520EC4A540055D09A /* FormattingColor_4.png in Resources */,\n\t\t\t\t4CAC9D831F2B076400AD5F12 /* Textual-Extras.pkg in Resources */,\n\t\t\t\t4C06E0BF20EC4A5A0055D09A /* channelRoomStatusIconLightInactive@2x.tif in Resources */,\n\t\t\t\t4C06E20F20EC4AC50055D09A /* TVCMemberListAppearance.plist in Resources */,\n\t\t\t\t4C06E08D20EC4A540055D09A /* FormattingColor_10.png in Resources */,\n\t\t\t\t4C06E09220EC4A540055D09A /* FormattingColor_15.png in Resources */,\n\t\t\t\t4C06E10D20EC4A630055D09A /* TPWTB_General@2x.png in Resources */,\n\t\t\t\t4C06E32920EC4FF00055D09A /* TVCNotificationConfigurationView.strings in Resources */,\n\t\t\t\t4C06E09720EC4A540055D09A /* FormattingColor_1.png in Resources */,\n\t\t\t\t4C06E02620EC4A060055D09A /* DIRedBadgeRight.png in Resources */,\n\t\t\t\t4C06E1C320EC4AC40055D09A /* TVCChannelSelectionView.xib in Resources */,\n\t\t\t\t4C06E03F20EC4A100055D09A /* DIGreenBadgeRight.png in Resources */,\n\t\t\t\t4C06E04C20EC4A2E0055D09A /* applicationIcon.iconset in Resources */,\n\t\t\t\t4C06E1FB20EC4AC50055D09A /* TDCAboutDialog.xib in Resources */,\n\t\t\t\t4C06E05420EC4A3E0055D09A /* Copyright Information for Images.txt in Resources */,\n\t\t\t\t4C06E08C20EC4A540055D09A /* FormattingColor_11.png in Resources */,\n\t\t\t\t4C06E1CB20EC4AC40055D09A /* TVCNotificationConfigurationView.xib in Resources */,\n\t\t\t\t4C06DF2C20EC49A60055D09A /* IRCNetworks.plist in Resources */,\n\t\t\t\t4C06E1EB20EC4AC50055D09A /* TVCAlert.xib in Resources */,\n\t\t\t\t4C06E32120EC4FF00055D09A /* Notifications.strings in Resources */,\n\t\t\t\t4C06E2F520EC4FF00055D09A /* TDCChannelPropertiesSheet.strings in Resources */,\n\t\t\t\t4C06E32D20EC4FF00055D09A /* TDCServerEndpointListSheet.strings in Resources */,\n\t\t\t\t4C06E31120EC4FF00055D09A /* IRC.strings in Resources */,\n\t\t\t\t4C06E1E320EC4AC40055D09A /* TDCProgressIndicatorSheet.xib in Resources */,\n\t\t\t\t4C06E34120EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings in Resources */,\n\t\t\t\t4C06DFCB20EC49FA0055D09A /* ErroneousTextFieldValueIndicator.tif in Resources */,\n\t\t\t\t4C06E03E20EC4A100055D09A /* DIGreenBadgeLeft.png in Resources */,\n\t\t\t\t4C06DF4320EC49B80055D09A /* RemoteLicenseSystemPublicKey.pub in Resources */,\n\t\t\t\t4C06E19B20EC4AC40055D09A /* TDCChannelModifyModesSheet.xib in Resources */,\n\t\t\t\t4C06E0BB20EC4A5A0055D09A /* channelRoomStatusIconLightActive.tif in Resources */,\n\t\t\t\t4C06E0BA20EC4A5A0055D09A /* channelRoomStatusIconDarkActive.tif in Resources */,\n\t\t\t\t4C06E10820EC4A630055D09A /* TPWTB_Highlights@2x.png in Resources */,\n\t\t\t\t4C06E09320EC4A540055D09A /* FormattingColor_7.png in Resources */,\n\t\t\t\t4C17305522B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib in Resources */,\n\t\t\t\t4C06E1D720EC4AC40055D09A /* TDCChannelInviteSheet.xib in Resources */,\n\t\t\t\t4C06E04020EC4A100055D09A /* DIGreenBadgeCenter.png in Resources */,\n\t\t\t\t4C06E19720EC4AC40055D09A /* TDCServerEndpointListSheet.xib in Resources */,\n\t\t\t\t4C06DF3020EC49A60055D09A /* TemplateLineTypes.plist in Resources */,\n\t\t\t\t4C06E10920EC4A630055D09A /* TPWTB_Addons.png in Resources */,\n\t\t\t\t4C06E2F120EC4FF00055D09A /* Accessibility.strings in Resources */,\n\t\t\t\t4C06E10B20EC4A630055D09A /* TPWTB_Controls.png in Resources */,\n\t\t\t\t4CCD93FE1CA7291300335381 /* JavaScript in Resources */,\n\t\t\t\t4C06DF2B20EC49A60055D09A /* IRCCommandIndexRemoteData.plist in Resources */,\n\t\t\t\t4C33341D20CC471A00ACB9AD /* Bundled Scripts in Resources */,\n\t\t\t\t4C06E08E20EC4A540055D09A /* FormattingColor_12.png in Resources */,\n\t\t\t\t4C06E1CF20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib in Resources */,\n\t\t\t\t4C06E11020EC4A630055D09A /* TPWTB_Controls@2x.png in Resources */,\n\t\t\t\t4C06E20B20EC4AC50055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib in Resources */,\n\t\t\t\t4C06E1AB20EC4AC40055D09A /* TDCChannelBanListSheet.xib in Resources */,\n\t\t\t\t4C06E11220EC4A630055D09A /* TPWTB_Interface@2x.png in Resources */,\n\t\t\t\t4C06E2FD20EC4FF00055D09A /* TDCPreferencesController.strings in Resources */,\n\t\t\t\t4C06E1A720EC4AC40055D09A /* TDCServerChannelListDialog.xib in Resources */,\n\t\t\t\t4C06E0B620EC4A5A0055D09A /* channelRoomStatusIconDarkActive@2x.tif in Resources */,\n\t\t\t\t4C06E30520EC4FF00055D09A /* TDCChannelInviteSheet.strings in Resources */,\n\t\t\t\t4C06E22720EC4AC50055D09A /* TVCMainWindowAppearance.plist in Resources */,\n\t\t\t\t4C06E06120EC4A4C0055D09A /* encryptionLockIconLight.tif in Resources */,\n\t\t\t\t4C06E10A20EC4A630055D09A /* TPWTB_Advanced.png in Resources */,\n\t\t\t\t4C06E09820EC4A540055D09A /* FormattingColor_Rainbow@2x.tif in Resources */,\n\t\t\t\t4C06E19320EC4AC40055D09A /* TDCServerHighlightListSheet.xib in Resources */,\n\t\t\t\t4C06E0B820EC4A5A0055D09A /* channelRoomStatusIconDarkInactive@2x.tif in Resources */,\n\t\t\t\t4C06E0B520EC4A5A0055D09A /* channelRoomStatusIconLightActive@2x.tif in Resources */,\n\t\t\t\t4C06E1C720EC4AC40055D09A /* TXCMainMenu.xib in Resources */,\n\t\t\t\t4C06E22F20EC4AC50055D09A /* TVCServerListAppearance.plist in Resources */,\n\t\t\t\t4C06E30920EC4FF00055D09A /* TDCAboutDialog.strings in Resources */,\n\t\t\t\t4C06E0B720EC4A5A0055D09A /* channelRoomStatusIconLightInactive.tif in Resources */,\n\t\t\t\t4C06E2E120EC4FF00055D09A /* OffTheRecord.strings in Resources */,\n\t\t\t\t4C06DFD020EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive.tif in Resources */,\n\t\t\t\t4C06E2E520EC4FF00055D09A /* CommonErrors.strings in Resources */,\n\t\t\t\t4C06E30D20EC4FF00055D09A /* TDCServerPropertiesSheet.strings in Resources */,\n\t\t\t\t4C06E2F920EC4FF00055D09A /* TDCChannelBanListSheet.strings in Resources */,\n\t\t\t\t4C06E1B320EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib in Resources */,\n\t\t\t\t4C06E09120EC4A540055D09A /* FormattingColor_14.png in Resources */,\n\t\t\t\t4C06E09920EC4A540055D09A /* FormattingColor_0.png in Resources */,\n\t\t\t\t4C06DFD220EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive.tif in Resources */,\n\t\t\t\t4C06E1D320EC4AC40055D09A /* TDCPreferences.xib in Resources */,\n\t\t\t\t4C06E04D20EC4A2E0055D09A /* applicationIconBirthday.icns in Resources */,\n\t\t\t\t4C06E02720EC4A060055D09A /* DIRedBadgeLeft.png in Resources */,\n\t\t\t\t4C06E02820EC4A060055D09A /* DIRedBadgeCenter.png in Resources */,\n\t\t\t\t4C06E18B20EC4AC40055D09A /* TDCServerPropertiesSheet.xib in Resources */,\n\t\t\t\t4C06E1FF20EC4AC50055D09A /* TDCHighlightEntrySheet.xib in Resources */,\n\t\t\t\t4C06DF2F20EC49A60055D09A /* StaticStore.plist in Resources */,\n\t\t\t\t4C06E11120EC4A630055D09A /* TPWTB_Interface.png in Resources */,\n\t\t\t\t4C06E22B20EC4AC50055D09A /* TVCMainWindowTextViewAppearance.plist in Resources */,\n\t\t\t\t4C06E10E20EC4A630055D09A /* TPWTB_Addons@2x.png in Resources */,\n\t\t\t\t4C06E09A20EC4A540055D09A /* FormattingColor_2.png in Resources */,\n\t\t\t\t4C33342220CC475300ACB9AD /* Bundled Styles in Resources */,\n\t\t\t\t4C06E08F20EC4A540055D09A /* FormattingColor_Rainbow.tif in Resources */,\n\t\t\t\t4C06E31920EC4FF00055D09A /* TDCChannelModifyModesSheet.strings in Resources */,\n\t\t\t\t4C06E2DD20EC4FF00055D09A /* Prompts.strings in Resources */,\n\t\t\t\t4C06E33920EC4FF00055D09A /* TDCAddressBookSheet.strings in Resources */,\n\t\t\t\t4C06E1AF20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib in Resources */,\n\t\t\t\t4C06E06020EC4A4C0055D09A /* encryptionLockIconDark@2x.tif in Resources */,\n\t\t\t\t4C06E1F720EC4AC50055D09A /* TDCChannelModifyTopicSheet.xib in Resources */,\n\t\t\t\t4C06E1F320EC4AC50055D09A /* TDCServerChangeNicknameSheet.xib in Resources */,\n\t\t\t\t4C06E09020EC4A540055D09A /* FormattingColor_13.png in Resources */,\n\t\t\t\t4C06E09420EC4A540055D09A /* FormattingColor_6.png in Resources */,\n\t\t\t\t4C06E11420EC4A630055D09A /* TPWTB_Style.png in Resources */,\n\t\t\t\t4C06E1E720EC4AC50055D09A /* TDCAddressBookSheet.xib in Resources */,\n\t\t\t\t4C06E19F20EC4AC40055D09A /* TDCChannelSpotlightController.xib in Resources */,\n\t\t\t\t4C06E0BD20EC4A5A0055D09A /* channelRoomStatusIconDarkInactive.tif in Resources */,\n\t\t\t\t4C06E05E20EC4A4C0055D09A /* encryptionLockIconLight@2x.tif in Resources */,\n\t\t\t\t4C06E05F20EC4A4C0055D09A /* encryptionLockIconDark.tif in Resources */,\n\t\t\t\t4C06E31D20EC4FF00055D09A /* TVCMainWindow.strings in Resources */,\n\t\t\t\t4C06E09B20EC4A540055D09A /* FormattingColor_3.png in Resources */,\n\t\t\t\t4C06DFCD20EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconActive@2x.tif in Resources */,\n\t\t\t\t4C06E10F20EC4A630055D09A /* TPWTB_Notifications@2x.png in Resources */,\n\t\t\t\t4C06E33D20EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings in Resources */,\n\t\t\t\t4C06E10720EC4A630055D09A /* TPWTB_Highlights.png in Resources */,\n\t\t\t\t4C06DFC920EC49FA0055D09A /* MainWindowSegmentedControlUserTemplate.pdf in Resources */,\n\t\t\t\t4C06E08B20EC4A540055D09A /* FormattingColor_9.png in Resources */,\n\t\t\t\t4C5BA3CB16F1302F00A96CA2 /* Style Default Templates in Resources */,\n\t\t\t\t4C06E30120EC4FF00055D09A /* TDCFileTransferDialog.strings in Resources */,\n\t\t\t\t4C06DFD320EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive@2x.tif in Resources */,\n\t\t\t\t4C06E31520EC4FF00055D09A /* TLOLicenseManager.strings in Resources */,\n\t\t\t\t4C06E11320EC4A630055D09A /* TPWTB_Notifications.png in Resources */,\n\t\t\t\t4C06E1DF20EC4AC40055D09A /* TDCWelcomeSheet.xib in Resources */,\n\t\t\t\t4C06E11520EC4A630055D09A /* TPWTB_General.png in Resources */,\n\t\t\t\t4C06E33120EC4FF00055D09A /* TDCServerChannelListDialog.strings in Resources */,\n\t\t\t\t4C06E33520EC4FF00055D09A /* TDCChannelSpotlightController.strings in Resources */,\n\t\t\t\t4C06E1A320EC4AC40055D09A /* TDCFileTransferDialog.xib in Resources */,\n\t\t\t\t4C06DFD120EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconActive.tif in Resources */,\n\t\t\t\t4C06DFCC20EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */,\n\t\t\t\t4C06E09620EC4A540055D09A /* FormattingColor_5.png in Resources */,\n\t\t\t\t4C06E10620EC4A630055D09A /* TPWTB_Advanced@2x.png in Resources */,\n\t\t\t\t4C06E1EF20EC4AC50055D09A /* TDCLicenseUpgradeDialog.xib in Resources */,\n\t\t\t\t4C06DF2A20EC49A60055D09A /* IRCCommandIndexLocalData.plist in Resources */,\n\t\t\t\t4C06E22320EC4AC50055D09A /* TDCChannelSpotlightAppearance.plist in Resources */,\n\t\t\t\t4C06E1BB20EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib in Resources */,\n\t\t\t\t4C06E20320EC4AC50055D09A /* TVCMainWindow.xib in Resources */,\n\t\t\t\t4C06DFD420EC49FA0055D09A /* VibrantDarkServerListViewPrivateMessageUserIconInactive.tif in Resources */,\n\t\t\t\t4C06DFD520EC49FA0055D09A /* VibrantLightServerListViewPrivateMessageUserIconInactive@2x.tif in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t4C01BA101581104D007E2DAF /* Build Extensions */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 12;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Build Extensions\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildExtensions.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/BuildExtensions.txt\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4C2BEB612C384E16008F8F0D /* Postprocess Sparkle */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Postprocess Sparkle\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/PostprocessSparkle.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/PostprocessSparkle.txt\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4C48B46520E4D37C00CF5F84 /* Merge Swift Libraries */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Merge Swift Libraries\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/MergeSwift.sh\\\"\\n\";\n\t\t};\n\t\t4C48B46620E4D38F00CF5F84 /* Merge Swift Libraries */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Merge Swift Libraries\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/MergeSwift.sh\\\"\\n\";\n\t\t};\n\t\t4C761BAF1E155D7400A505B7 /* Build XPC Services */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Build XPC Services\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildServices.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/BuildServices.txt\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4C761BB01E155DD900A505B7 /* Build XPC Services */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Build XPC Services\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildServices.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/BuildServices.txt\\\"\\n\";\n\t\t};\n\t\t4CCF301715804DD1006FFE21 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildFrameworks.sh\\\"\\n\";\n\t\t};\n\t\t4CEE0BDB268F3C68004CB3C3 /* Build Extensions */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Build Extensions\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildExtensions.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/BuildExtensions.txt\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4C0444F316F1602900EBB665 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E57F20EC553A0055D09A /* TXAppearance.m in Sources */,\n\t\t\t\t4C06E58020EC553A0055D09A /* TXApplication.m in Sources */,\n\t\t\t\t4C06E58120EC553A0055D09A /* TXGlobalModels.m in Sources */,\n\t\t\t\t4C06E58220EC553A0055D09A /* TXMasterController.m in Sources */,\n\t\t\t\t4C06E58320EC553A0055D09A /* TXMenuController.m in Sources */,\n\t\t\t\t4C06E58420EC553A0055D09A /* TXSharedApplication.m in Sources */,\n\t\t\t\t4C06E58520EC553A0055D09A /* TXWindowController.m in Sources */,\n\t\t\t\t4C06E58A20EC553A0055D09A /* TDCChannelSpotlightControls.m in Sources */,\n\t\t\t\t4C06E58B20EC553A0055D09A /* TDCChannelSpotlightSearchResult.m in Sources */,\n\t\t\t\t4C06E58C20EC553A0055D09A /* TDCChannelSpotlightController.m in Sources */,\n\t\t\t\t4C06E58D20EC553A0055D09A /* TDCChannelSpotlightAppearance.m in Sources */,\n\t\t\t\t4C06E58E20EC553A0055D09A /* TDCChannelSpotlightSearchResultsTable.m in Sources */,\n\t\t\t\t4C06E58F20EC553A0055D09A /* TDCFileTransferDialog.m in Sources */,\n\t\t\t\t4C06E59020EC553A0055D09A /* TDCFileTransferDialogTransferController.m in Sources */,\n\t\t\t\t4C06E59120EC553A0055D09A /* TDCFileTransferDialogTableCell.m in Sources */,\n\t\t\t\t4C06E59220EC553A0055D09A /* TDCLicenseUpgradeDialog.m in Sources */,\n\t\t\t\t4CAB27522537EE44009B1F07 /* IRCChannelMemberList.m in Sources */,\n\t\t\t\t4C06E59320EC553A0055D09A /* TDCLicenseUpgradeEligibilitySheet.m in Sources */,\n\t\t\t\t4C06E59420EC553A0055D09A /* TDCLicenseManagerMigrateAppStoreSheet.m in Sources */,\n\t\t\t\t4C06E59520EC553A0055D09A /* TDCLicenseUpgradeCommonActions.m in Sources */,\n\t\t\t\t4C06E59620EC553A0055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.m in Sources */,\n\t\t\t\t4C06E59720EC553A0055D09A /* TDCLicenseUpgradeActivateSheet.m in Sources */,\n\t\t\t\t4CAB2766253863BF009B1F07 /* IRCChannelMemberListController.m in Sources */,\n\t\t\t\t4C06E59820EC553A0055D09A /* TDCLicenseManagerDialog.m in Sources */,\n\t\t\t\t4C06E59D20EC553A0055D09A /* TDCPreferencesNotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E59E20EC553A0055D09A /* TDCPreferencesController.m in Sources */,\n\t\t\t\t4C06E59F20EC553A0055D09A /* TDCServerEndpointListSheetTable.m in Sources */,\n\t\t\t\t4C06E5A020EC553A0055D09A /* TDCServerEndpointListSheet.m in Sources */,\n\t\t\t\t4C06E5A120EC553A0055D09A /* TDCAboutDialog.m in Sources */,\n\t\t\t\t4C06E5A220EC553A0055D09A /* TDCAddressBookSheet.m in Sources */,\n\t\t\t\t4C06E5A320EC553A0055D09A /* TDCAlert.m in Sources */,\n\t\t\t\t4C06E5A420EC553A0055D09A /* TDCChannelBanListSheet.m in Sources */,\n\t\t\t\t4C06E5A520EC553A0055D09A /* TDCChannelInviteSheet.m in Sources */,\n\t\t\t\t4C06E5A620EC553A0055D09A /* TDCChannelModifyModesSheet.m in Sources */,\n\t\t\t\t4C06E5A720EC553A0055D09A /* TDCChannelModifyTopicSheet.m in Sources */,\n\t\t\t\t4C06E5A820EC553A0055D09A /* TDCChannelPropertiesNotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E5A920EC553A0055D09A /* TDCChannelPropertiesSheet.m in Sources */,\n\t\t\t\t4C06E5AA20EC553A0055D09A /* TDCHighlightEntrySheet.m in Sources */,\n\t\t\t\t4C06E5AB20EC553A0055D09A /* TDCInputPrompt.m in Sources */,\n\t\t\t\t4C06E5AC20EC553A0055D09A /* TDCNicknameColorSheet.m in Sources */,\n\t\t\t\t4C06E5AD20EC553A0055D09A /* TDCProgressIndicatorSheet.m in Sources */,\n\t\t\t\t4C06E5AE20EC553A0055D09A /* TDCServerChangeNicknameSheet.m in Sources */,\n\t\t\t\t4C06E5AF20EC553A0055D09A /* TDCServerChannelListDialog.m in Sources */,\n\t\t\t\t4C06E5B020EC553A0055D09A /* TDCServerHighlightListSheet.m in Sources */,\n\t\t\t\t4C06E5B120EC553A0055D09A /* TDCServerPropertiesSheet.m in Sources */,\n\t\t\t\t4C06E5B220EC553A0055D09A /* TDCSheetBase.m in Sources */,\n\t\t\t\t4C06E5B320EC553A0055D09A /* TDCWelcomeSheet.m in Sources */,\n\t\t\t\t4C06E5B420EC553A0055D09A /* TDCWindowBase.m in Sources */,\n\t\t\t\t4C06E5B520EC553A0055D09A /* NSColorHelper.m in Sources */,\n\t\t\t\t4C06E5B620EC553A0055D09A /* NSObjectHelper.m in Sources */,\n\t\t\t\t4C06E5B720EC553A0055D09A /* NSStringHelper.m in Sources */,\n\t\t\t\t4C06E5B820EC553A0055D09A /* NSTableViewHelper.m in Sources */,\n\t\t\t\t4C06E5B920EC553A0055D09A /* NSViewHelper.m in Sources */,\n\t\t\t\t4C06E5BA20EC553A0055D09A /* TXAppearanceHelper.m in Sources */,\n\t\t\t\t4C06E5BB20EC553A0055D09A /* WebScriptObjectHelper.m in Sources */,\n\t\t\t\t4C06E5BC20EC553A0055D09A /* GTMEncodeHTML.m in Sources */,\n\t\t\t\t4C06E5BD20EC553A0055D09A /* THOPluginDispatcher.m in Sources */,\n\t\t\t\t4C06E5BE20EC553A0055D09A /* THOPluginManager.m in Sources */,\n\t\t\t\t4C06E5BF20EC553A0055D09A /* THOPluginItem.m in Sources */,\n\t\t\t\t4C06E5C020EC553A0055D09A /* THOUnicodeHelper.m in Sources */,\n\t\t\t\t4C06E5C120EC553A0055D09A /* IRCAddressBook.m in Sources */,\n\t\t\t\t4C06E5C220EC553A0055D09A /* IRCAddressBookMatchCache.m in Sources */,\n\t\t\t\t4C06E5C320EC553A0055D09A /* IRCAddressBookUserTracking.m in Sources */,\n\t\t\t\t4C06E5C420EC553A0055D09A /* IRCChannel.m in Sources */,\n\t\t\t\t4C06E5C520EC553A0055D09A /* IRCChannelConfig.m in Sources */,\n\t\t\t\t4C06E5C620EC553A0055D09A /* IRCChannelMode.m in Sources */,\n\t\t\t\t4C06E5C720EC553A0055D09A /* IRCChannelUser.m in Sources */,\n\t\t\t\t4C06E5C820EC553A0055D09A /* IRCClient.m in Sources */,\n\t\t\t\t4C06E5C920EC553A0055D09A /* IRCClientConfig.m in Sources */,\n\t\t\t\t4C06E5CA20EC553A0055D09A /* IRCClientRequestedCommands.m in Sources */,\n\t\t\t\t4C06E5CB20EC553A0055D09A /* IRCCommandIndex.m in Sources */,\n\t\t\t\t4C06E5CC20EC553A0055D09A /* IRCConnection.m in Sources */,\n\t\t\t\t4C06E5CD20EC553A0055D09A /* IRCConnectionConfig.m in Sources */,\n\t\t\t\t4C06E5CE20EC553A0055D09A /* IRCExtras.m in Sources */,\n\t\t\t\t4C06E5CF20EC553A0055D09A /* IRCHighlightLogEntry.m in Sources */,\n\t\t\t\t4C06E5D020EC553A0055D09A /* IRCHighlightMatchCondition.m in Sources */,\n\t\t\t\t4C469E3B20EC5BDB00094EA4 /* TLOLinkParser.swift in Sources */,\n\t\t\t\t4C06E5D120EC553A0055D09A /* IRCISupportInfo.m in Sources */,\n\t\t\t\t4C06E5D220EC553A0055D09A /* IRCMessage.m in Sources */,\n\t\t\t\t4C06E5D320EC553A0055D09A /* IRCMessageBatch.m in Sources */,\n\t\t\t\t4C06E5D420EC553A0055D09A /* IRCModeInfo.m in Sources */,\n\t\t\t\t4C06E5D520EC553A0055D09A /* IRCNetworkList.m in Sources */,\n\t\t\t\t4C06E5D620EC553A0055D09A /* IRCPrefix.m in Sources */,\n\t\t\t\t4C51327920F76E980033B703 /* TLOLocalization.swift in Sources */,\n\t\t\t\t4C06E5D720EC553A0055D09A /* IRCSendingMessage.m in Sources */,\n\t\t\t\t4C06E5D820EC553A0055D09A /* IRCServer.m in Sources */,\n\t\t\t\t4C06E5D920EC553A0055D09A /* IRCTimerCommand.m in Sources */,\n\t\t\t\t4C8878052C33706E0016DB98 /* TPCSandboxMigration.m in Sources */,\n\t\t\t\t4C06E5DA20EC553A0055D09A /* IRCTreeItem.m in Sources */,\n\t\t\t\t4C06E5DB20EC553A0055D09A /* IRCWorld.m in Sources */,\n\t\t\t\t4C06E5DD20EC553A0055D09A /* IRCUserRelations.m in Sources */,\n\t\t\t\t4C06E5DE20EC553A0055D09A /* IRCUser.m in Sources */,\n\t\t\t\t4C06E5DF20EC553A0055D09A /* IRCUserNicknameColorStyleGenerator.m in Sources */,\n\t\t\t\t4C06E5E020EC553A0055D09A /* IRCUserPersistentStore.m in Sources */,\n\t\t\t\t4C06E5E120EC553A0055D09A /* IRCColorFormat.m in Sources */,\n\t\t\t\t4C06E5E220EC553A0055D09A /* OELReachability.m in Sources */,\n\t\t\t\t4C06E5E320EC553A0055D09A /* TLOLicenseManager.m in Sources */,\n\t\t\t\t4C06E5E420EC553A0055D09A /* TLOLicenseManagerDownloader.m in Sources */,\n\t\t\t\t4C06E5E520EC553A0055D09A /* TLOLicenseManagerLastGen.m in Sources */,\n\t\t\t\t4C06E5E720EC553A0055D09A /* TLOEncryptionManager.m in Sources */,\n\t\t\t\t4C06E5E820EC553A0055D09A /* TLOFileLogger.m in Sources */,\n\t\t\t\t4C06E5E920EC553A0055D09A /* TLONotificationController.m in Sources */,\n\t\t\t\t4C06E5EA20EC553A0055D09A /* TLOInputHistory.m in Sources */,\n\t\t\t\t4C06E5EB20EC553A0055D09A /* TLOInternetAddressLookup.m in Sources */,\n\t\t\t\t4C06E5EC20EC553A0055D09A /* TLOKeyEventHandler.m in Sources */,\n\t\t\t\t4C06E5ED20EC553A0055D09A /* TLOLocalization.m in Sources */,\n\t\t\t\t4C06E5EE20EC553A0055D09A /* TLONicknameCompletionStatus.m in Sources */,\n\t\t\t\t4C06E5EF20EC553A0055D09A /* TLONotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E5F120EC553A0055D09A /* TLOSoundPlayer.m in Sources */,\n\t\t\t\t4C06E5F220EC553A0055D09A /* TLOSpeechSynthesizer.m in Sources */,\n\t\t\t\t4C06E5F320EC553A0055D09A /* TLOSpokenNotification.m in Sources */,\n\t\t\t\t4C06E5F420EC553A0055D09A /* TLOTimer.m in Sources */,\n\t\t\t\t4C06E5F520EC553A0055D09A /* main.m in Sources */,\n\t\t\t\t4C06E5F820EC553A0055D09A /* TPCThemeController.m in Sources */,\n\t\t\t\t4C06E5F920EC553A0055D09A /* TPCTheme.m in Sources */,\n\t\t\t\t4C06E5FA20EC553A0055D09A /* TPCApplicationInfo.m in Sources */,\n\t\t\t\t4C06E5FB20EC553A0055D09A /* TPCPathInfo.m in Sources */,\n\t\t\t\t4C469E3C20EC5BDB00094EA4 /* TLOpenLink.swift in Sources */,\n\t\t\t\t4C06E5FC20EC553A0055D09A /* TPCPreferences.m in Sources */,\n\t\t\t\t4C06E5FD20EC553A0055D09A /* TPCPreferencesLocal.m in Sources */,\n\t\t\t\t4C06E5FE20EC553A0055D09A /* TPCPreferencesImportExport.m in Sources */,\n\t\t\t\t4C06E5FF20EC553A0055D09A /* TPCPreferencesReload.m in Sources */,\n\t\t\t\t4C06E60020EC553A0055D09A /* TPCPreferencesUserDefaults.m in Sources */,\n\t\t\t\t4C06E60120EC553A0055D09A /* TPCPreferencesUserDefaultsLocal.m in Sources */,\n\t\t\t\t4C06E60320EC553A0055D09A /* TPCResourceManager.m in Sources */,\n\t\t\t\t4C06E60420EC553A0055D09A /* ICLPayloadLocal.m in Sources */,\n\t\t\t\t4C06E60620EC553A0055D09A /* GCDAsyncSocket.m in Sources */,\n\t\t\t\t4C06E60720EC553A0055D09A /* GCDAsyncSocketExtensions.m in Sources */,\n\t\t\t\t4C06E60920EC553A0055D09A /* ICLPayload.m in Sources */,\n\t\t\t\t4C06E60A20EC553A0055D09A /* TVCLogLineXPC.m in Sources */,\n\t\t\t\t4C06E60B20EC553A0055D09A /* TVCChannelSelectionOutlineCellView.m in Sources */,\n\t\t\t\t4C8F3FDD2C31B15B00118AAF /* THOPluginItemLogging.m in Sources */,\n\t\t\t\t4C06E60C20EC553A0055D09A /* TVCChannelSelectionViewController.m in Sources */,\n\t\t\t\t4C06E60D20EC553A0055D09A /* TVCLogControllerHistoricLogFile.m in Sources */,\n\t\t\t\t4C06E60E20EC553A0055D09A /* TVCLogControllerInlineMediaService.m in Sources */,\n\t\t\t\t4C06E60F20EC553A0055D09A /* TVCLogControllerOperationQueue.m in Sources */,\n\t\t\t\t4C06E61020EC553A0055D09A /* TVCLogController.m in Sources */,\n\t\t\t\t4C06E61120EC553A0055D09A /* TVCLogLine.m in Sources */,\n\t\t\t\t4C06E61220EC553A0055D09A /* TVCLogPolicy.m in Sources */,\n\t\t\t\t4C06E61320EC553A0055D09A /* TVCLogRenderer.m in Sources */,\n\t\t\t\t4C06E61420EC553A0055D09A /* TVCLogScriptEventSink.m in Sources */,\n\t\t\t\t4C06E61520EC553A0055D09A /* TVCLogView.m in Sources */,\n\t\t\t\t4C06E61620EC553A0055D09A /* TVCLogViewInternalWK1.m in Sources */,\n\t\t\t\t4C06E61720EC553A0055D09A /* TVCLogViewInternalWK2.m in Sources */,\n\t\t\t\t4C06E61820EC553A0055D09A /* TVCWK1AutoScroller.m in Sources */,\n\t\t\t\t4C06E61920EC553A0055D09A /* TVCAlert.m in Sources */,\n\t\t\t\t4C06E61A20EC553A0055D09A /* TVCErrorMessagePopover.m in Sources */,\n\t\t\t\t4C06E61B20EC553A0055D09A /* TVCErrorMessagePopoverController.m in Sources */,\n\t\t\t\t4C06E61C20EC553A0055D09A /* TVCAutoExpandingTextField.m in Sources */,\n\t\t\t\t4C06E61D20EC553A0055D09A /* TVCAutoExpandingTokenField.m in Sources */,\n\t\t\t\t4C06E61E20EC553A0055D09A /* TVCTextFormatterMenu.m in Sources */,\n\t\t\t\t4C06E61F20EC553A0055D09A /* TVCTextViewWithIRCFormatter.m in Sources */,\n\t\t\t\t4C06E62020EC553A0055D09A /* TVCValidatedComboBox.m in Sources */,\n\t\t\t\t4C06E62120EC553A0055D09A /* TVCValidatedTextField.m in Sources */,\n\t\t\t\t4C06E62220EC553A0055D09A /* TVCMainWindow.m in Sources */,\n\t\t\t\t4C06E62320EC553A0055D09A /* TVCMainWindowAppearance.m in Sources */,\n\t\t\t\t4C06E62420EC553A0055D09A /* TVCMainWindowChannelView.m in Sources */,\n\t\t\t\t4C06E62520EC553A0055D09A /* TVCMainWindowLoadingScreen.m in Sources */,\n\t\t\t\t4C06E62620EC553A0055D09A /* TVCMainWindowSegmentedControl.m in Sources */,\n\t\t\t\t4C06E62820EC553A0055D09A /* TVCMainWindowSplitView.m in Sources */,\n\t\t\t\t4C06E62920EC553A0055D09A /* TVCMainWindowTextView.m in Sources */,\n\t\t\t\t4C06E62A20EC553A0055D09A /* TVCMainWindowTextViewAppearance.m in Sources */,\n\t\t\t\t4C06E62B20EC553A0055D09A /* TVCMainWindowTitlebarAccessoryView.m in Sources */,\n\t\t\t\t4C06E62C20EC553A0055D09A /* TVCNotificationConfigurationViewController.m in Sources */,\n\t\t\t\t4C06E62D20EC553A0055D09A /* TVCServerList.m in Sources */,\n\t\t\t\t4C5274E720F8D7CD00B18F9D /* IRCConnectionErrors.m in Sources */,\n\t\t\t\t4C06E62E20EC553A0055D09A /* TVCServerListAppearance.m in Sources */,\n\t\t\t\t4C06E62F20EC553A0055D09A /* TVCServerListCell.m in Sources */,\n\t\t\t\t4C06E63020EC553A0055D09A /* TVCMemberList.m in Sources */,\n\t\t\t\t4C06E63120EC553A0055D09A /* TVCMemberListAppearance.m in Sources */,\n\t\t\t\t4C06E63220EC553A0055D09A /* TVCMemberListCell.m in Sources */,\n\t\t\t\t4C06E63320EC553A0055D09A /* TVCMemberListUserInfoPopover.m in Sources */,\n\t\t\t\t4C06E63420EC553A0055D09A /* TVCAppearance.m in Sources */,\n\t\t\t\t4C06E63520EC553A0055D09A /* TVCBasicTableView.m in Sources */,\n\t\t\t\t4C06E63620EC553A0055D09A /* TVCContentNavigationOutlineView.m in Sources */,\n\t\t\t\t4CB873DD22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m in Sources */,\n\t\t\t\t4C06E63720EC553A0055D09A /* TVCDockIcon.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C1DC54E1580420500A47BC9 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06E63820EC55B90055D09A /* TXAppearance.m in Sources */,\n\t\t\t\t4C06E63920EC55B90055D09A /* TXApplication.m in Sources */,\n\t\t\t\t4C06E63A20EC55B90055D09A /* TXGlobalModels.m in Sources */,\n\t\t\t\t4C06E63B20EC55B90055D09A /* TXMasterController.m in Sources */,\n\t\t\t\t4C06E63C20EC55B90055D09A /* TXMenuController.m in Sources */,\n\t\t\t\t4C06E63D20EC55B90055D09A /* TXSharedApplication.m in Sources */,\n\t\t\t\t4C06E63E20EC55B90055D09A /* TXWindowController.m in Sources */,\n\t\t\t\t4C06E64320EC55B90055D09A /* TDCChannelSpotlightControls.m in Sources */,\n\t\t\t\t4C06E64420EC55B90055D09A /* TDCChannelSpotlightSearchResult.m in Sources */,\n\t\t\t\t4C06E64520EC55B90055D09A /* TDCChannelSpotlightController.m in Sources */,\n\t\t\t\t4C06E64620EC55B90055D09A /* TDCChannelSpotlightAppearance.m in Sources */,\n\t\t\t\t4C06E64720EC55B90055D09A /* TDCChannelSpotlightSearchResultsTable.m in Sources */,\n\t\t\t\t4C06E64820EC55B90055D09A /* TDCFileTransferDialog.m in Sources */,\n\t\t\t\t4C06E64920EC55B90055D09A /* TDCFileTransferDialogTransferController.m in Sources */,\n\t\t\t\t4C06E64A20EC55B90055D09A /* TDCFileTransferDialogTableCell.m in Sources */,\n\t\t\t\t4C06E64B20EC55B90055D09A /* TDCLicenseUpgradeDialog.m in Sources */,\n\t\t\t\t4CAB27532537EE44009B1F07 /* IRCChannelMemberList.m in Sources */,\n\t\t\t\t4C06E64C20EC55B90055D09A /* TDCLicenseUpgradeEligibilitySheet.m in Sources */,\n\t\t\t\t4C06E64D20EC55B90055D09A /* TDCLicenseManagerMigrateAppStoreSheet.m in Sources */,\n\t\t\t\t4C06E64E20EC55B90055D09A /* TDCLicenseUpgradeCommonActions.m in Sources */,\n\t\t\t\t4C06E64F20EC55B90055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.m in Sources */,\n\t\t\t\t4C06E65020EC55B90055D09A /* TDCLicenseUpgradeActivateSheet.m in Sources */,\n\t\t\t\t4CAB2767253863BF009B1F07 /* IRCChannelMemberListController.m in Sources */,\n\t\t\t\t4C06E65120EC55B90055D09A /* TDCLicenseManagerDialog.m in Sources */,\n\t\t\t\t4C06E65620EC55B90055D09A /* TDCPreferencesNotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E65720EC55B90055D09A /* TDCPreferencesController.m in Sources */,\n\t\t\t\t4C06E65820EC55B90055D09A /* TDCServerEndpointListSheetTable.m in Sources */,\n\t\t\t\t4C06E65920EC55B90055D09A /* TDCServerEndpointListSheet.m in Sources */,\n\t\t\t\t4C06E65A20EC55B90055D09A /* TDCAboutDialog.m in Sources */,\n\t\t\t\t4C06E65B20EC55B90055D09A /* TDCAddressBookSheet.m in Sources */,\n\t\t\t\t4C06E65C20EC55B90055D09A /* TDCAlert.m in Sources */,\n\t\t\t\t4C06E65D20EC55B90055D09A /* TDCChannelBanListSheet.m in Sources */,\n\t\t\t\t4C06E65E20EC55B90055D09A /* TDCChannelInviteSheet.m in Sources */,\n\t\t\t\t4C06E65F20EC55B90055D09A /* TDCChannelModifyModesSheet.m in Sources */,\n\t\t\t\t4C06E66020EC55B90055D09A /* TDCChannelModifyTopicSheet.m in Sources */,\n\t\t\t\t4C06E66120EC55B90055D09A /* TDCChannelPropertiesNotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E66220EC55B90055D09A /* TDCChannelPropertiesSheet.m in Sources */,\n\t\t\t\t4C06E66320EC55B90055D09A /* TDCHighlightEntrySheet.m in Sources */,\n\t\t\t\t4C06E66420EC55B90055D09A /* TDCInputPrompt.m in Sources */,\n\t\t\t\t4C06E66520EC55B90055D09A /* TDCNicknameColorSheet.m in Sources */,\n\t\t\t\t4C06E66620EC55B90055D09A /* TDCProgressIndicatorSheet.m in Sources */,\n\t\t\t\t4C06E66720EC55B90055D09A /* TDCServerChangeNicknameSheet.m in Sources */,\n\t\t\t\t4C06E66820EC55B90055D09A /* TDCServerChannelListDialog.m in Sources */,\n\t\t\t\t4C06E66920EC55B90055D09A /* TDCServerHighlightListSheet.m in Sources */,\n\t\t\t\t4C06E66A20EC55B90055D09A /* TDCServerPropertiesSheet.m in Sources */,\n\t\t\t\t4C06E66B20EC55B90055D09A /* TDCSheetBase.m in Sources */,\n\t\t\t\t4C06E66C20EC55B90055D09A /* TDCWelcomeSheet.m in Sources */,\n\t\t\t\t4C06E66D20EC55B90055D09A /* TDCWindowBase.m in Sources */,\n\t\t\t\t4C06E66E20EC55B90055D09A /* NSColorHelper.m in Sources */,\n\t\t\t\t4C06E66F20EC55B90055D09A /* NSObjectHelper.m in Sources */,\n\t\t\t\t4C06E67020EC55B90055D09A /* NSStringHelper.m in Sources */,\n\t\t\t\t4C06E67120EC55B90055D09A /* NSTableViewHelper.m in Sources */,\n\t\t\t\t4C06E67220EC55B90055D09A /* NSViewHelper.m in Sources */,\n\t\t\t\t4C06E67320EC55B90055D09A /* TXAppearanceHelper.m in Sources */,\n\t\t\t\t4C06E67420EC55B90055D09A /* WebScriptObjectHelper.m in Sources */,\n\t\t\t\t4C06E67520EC55B90055D09A /* GTMEncodeHTML.m in Sources */,\n\t\t\t\t4C06E67620EC55B90055D09A /* THOPluginDispatcher.m in Sources */,\n\t\t\t\t4C06E67720EC55B90055D09A /* THOPluginManager.m in Sources */,\n\t\t\t\t4C06E67820EC55B90055D09A /* THOPluginItem.m in Sources */,\n\t\t\t\t4C06E67920EC55B90055D09A /* THOUnicodeHelper.m in Sources */,\n\t\t\t\t4C06E67A20EC55B90055D09A /* IRCAddressBook.m in Sources */,\n\t\t\t\t4C06E67B20EC55B90055D09A /* IRCAddressBookMatchCache.m in Sources */,\n\t\t\t\t4C06E67C20EC55B90055D09A /* IRCAddressBookUserTracking.m in Sources */,\n\t\t\t\t4C06E67D20EC55B90055D09A /* IRCChannel.m in Sources */,\n\t\t\t\t4C06E67E20EC55B90055D09A /* IRCChannelConfig.m in Sources */,\n\t\t\t\t4C06E67F20EC55B90055D09A /* IRCChannelMode.m in Sources */,\n\t\t\t\t4C06E68020EC55B90055D09A /* IRCChannelUser.m in Sources */,\n\t\t\t\t4C06E68120EC55B90055D09A /* IRCClient.m in Sources */,\n\t\t\t\t4C06E68220EC55B90055D09A /* IRCClientConfig.m in Sources */,\n\t\t\t\t4C06E68320EC55B90055D09A /* IRCClientRequestedCommands.m in Sources */,\n\t\t\t\t4C06E68420EC55B90055D09A /* IRCCommandIndex.m in Sources */,\n\t\t\t\t4C06E68520EC55B90055D09A /* IRCConnection.m in Sources */,\n\t\t\t\t4C06E68620EC55B90055D09A /* IRCConnectionConfig.m in Sources */,\n\t\t\t\t4C06E68720EC55B90055D09A /* IRCExtras.m in Sources */,\n\t\t\t\t4C06E68820EC55B90055D09A /* IRCHighlightLogEntry.m in Sources */,\n\t\t\t\t4C06E68920EC55B90055D09A /* IRCHighlightMatchCondition.m in Sources */,\n\t\t\t\t4C469E3D20EC5BDB00094EA4 /* TLOLinkParser.swift in Sources */,\n\t\t\t\t4C06E68A20EC55B90055D09A /* IRCISupportInfo.m in Sources */,\n\t\t\t\t4C06E68B20EC55B90055D09A /* IRCMessage.m in Sources */,\n\t\t\t\t4C06E68C20EC55B90055D09A /* IRCMessageBatch.m in Sources */,\n\t\t\t\t4C06E68D20EC55B90055D09A /* IRCModeInfo.m in Sources */,\n\t\t\t\t4C06E68E20EC55B90055D09A /* IRCNetworkList.m in Sources */,\n\t\t\t\t4C06E68F20EC55B90055D09A /* IRCPrefix.m in Sources */,\n\t\t\t\t4C51327A20F76E980033B703 /* TLOLocalization.swift in Sources */,\n\t\t\t\t4C06E69020EC55B90055D09A /* IRCSendingMessage.m in Sources */,\n\t\t\t\t4C06E69120EC55B90055D09A /* IRCServer.m in Sources */,\n\t\t\t\t4C06E69220EC55B90055D09A /* IRCTimerCommand.m in Sources */,\n\t\t\t\t4C8878042C33706E0016DB98 /* TPCSandboxMigration.m in Sources */,\n\t\t\t\t4C06E69320EC55B90055D09A /* IRCTreeItem.m in Sources */,\n\t\t\t\t4C06E69420EC55B90055D09A /* IRCWorld.m in Sources */,\n\t\t\t\t4C06E69620EC55B90055D09A /* IRCUserRelations.m in Sources */,\n\t\t\t\t4C06E69720EC55B90055D09A /* IRCUser.m in Sources */,\n\t\t\t\t4C06E69820EC55B90055D09A /* IRCUserNicknameColorStyleGenerator.m in Sources */,\n\t\t\t\t4C06E69920EC55B90055D09A /* IRCUserPersistentStore.m in Sources */,\n\t\t\t\t4C06E69A20EC55B90055D09A /* IRCColorFormat.m in Sources */,\n\t\t\t\t4C06E69B20EC55B90055D09A /* OELReachability.m in Sources */,\n\t\t\t\t4C06E69C20EC55B90055D09A /* TLOLicenseManager.m in Sources */,\n\t\t\t\t4C06E69D20EC55B90055D09A /* TLOLicenseManagerDownloader.m in Sources */,\n\t\t\t\t4C06E69E20EC55B90055D09A /* TLOLicenseManagerLastGen.m in Sources */,\n\t\t\t\t4C06E6A020EC55B90055D09A /* TLOEncryptionManager.m in Sources */,\n\t\t\t\t4C06E6A120EC55B90055D09A /* TLOFileLogger.m in Sources */,\n\t\t\t\t4C06E6A220EC55B90055D09A /* TLONotificationController.m in Sources */,\n\t\t\t\t4C06E6A320EC55B90055D09A /* TLOInputHistory.m in Sources */,\n\t\t\t\t4C06E6A420EC55B90055D09A /* TLOInternetAddressLookup.m in Sources */,\n\t\t\t\t4C06E6A520EC55B90055D09A /* TLOKeyEventHandler.m in Sources */,\n\t\t\t\t4C06E6A620EC55B90055D09A /* TLOLocalization.m in Sources */,\n\t\t\t\t4C06E6A720EC55B90055D09A /* TLONicknameCompletionStatus.m in Sources */,\n\t\t\t\t4C06E6A820EC55B90055D09A /* TLONotificationConfiguration.m in Sources */,\n\t\t\t\t4C06E6AA20EC55B90055D09A /* TLOSoundPlayer.m in Sources */,\n\t\t\t\t4C06E6AB20EC55B90055D09A /* TLOSpeechSynthesizer.m in Sources */,\n\t\t\t\t4C06E6AC20EC55B90055D09A /* TLOSpokenNotification.m in Sources */,\n\t\t\t\t4C06E6AD20EC55B90055D09A /* TLOTimer.m in Sources */,\n\t\t\t\t4C06E6AE20EC55B90055D09A /* main.m in Sources */,\n\t\t\t\t4C06E6B120EC55B90055D09A /* TPCThemeController.m in Sources */,\n\t\t\t\t4C06E6B220EC55B90055D09A /* TPCTheme.m in Sources */,\n\t\t\t\t4C06E6B320EC55B90055D09A /* TPCApplicationInfo.m in Sources */,\n\t\t\t\t4C06E6B420EC55B90055D09A /* TPCPathInfo.m in Sources */,\n\t\t\t\t4C469E3E20EC5BDB00094EA4 /* TLOpenLink.swift in Sources */,\n\t\t\t\t4C06E6B520EC55B90055D09A /* TPCPreferences.m in Sources */,\n\t\t\t\t4C06E6B620EC55B90055D09A /* TPCPreferencesLocal.m in Sources */,\n\t\t\t\t4C06E6B720EC55B90055D09A /* TPCPreferencesImportExport.m in Sources */,\n\t\t\t\t4C06E6B820EC55B90055D09A /* TPCPreferencesReload.m in Sources */,\n\t\t\t\t4C06E6B920EC55B90055D09A /* TPCPreferencesUserDefaults.m in Sources */,\n\t\t\t\t4C06E6BA20EC55B90055D09A /* TPCPreferencesUserDefaultsLocal.m in Sources */,\n\t\t\t\t4C06E6BC20EC55B90055D09A /* TPCResourceManager.m in Sources */,\n\t\t\t\t4C06E6BD20EC55B90055D09A /* ICLPayloadLocal.m in Sources */,\n\t\t\t\t4C06E6BF20EC55B90055D09A /* GCDAsyncSocket.m in Sources */,\n\t\t\t\t4C06E6C020EC55B90055D09A /* GCDAsyncSocketExtensions.m in Sources */,\n\t\t\t\t4C06E6C220EC55B90055D09A /* ICLPayload.m in Sources */,\n\t\t\t\t4C06E6C320EC55B90055D09A /* TVCLogLineXPC.m in Sources */,\n\t\t\t\t4C06E6C420EC55B90055D09A /* TVCChannelSelectionOutlineCellView.m in Sources */,\n\t\t\t\t4C8F3FDC2C31B15B00118AAF /* THOPluginItemLogging.m in Sources */,\n\t\t\t\t4C06E6C520EC55B90055D09A /* TVCChannelSelectionViewController.m in Sources */,\n\t\t\t\t4C06E6C620EC55B90055D09A /* TVCLogControllerHistoricLogFile.m in Sources */,\n\t\t\t\t4C06E6C720EC55B90055D09A /* TVCLogControllerInlineMediaService.m in Sources */,\n\t\t\t\t4C06E6C820EC55B90055D09A /* TVCLogControllerOperationQueue.m in Sources */,\n\t\t\t\t4C06E6C920EC55B90055D09A /* TVCLogController.m in Sources */,\n\t\t\t\t4C06E6CA20EC55B90055D09A /* TVCLogLine.m in Sources */,\n\t\t\t\t4C06E6CB20EC55B90055D09A /* TVCLogPolicy.m in Sources */,\n\t\t\t\t4C06E6CC20EC55B90055D09A /* TVCLogRenderer.m in Sources */,\n\t\t\t\t4C06E6CD20EC55B90055D09A /* TVCLogScriptEventSink.m in Sources */,\n\t\t\t\t4C06E6CE20EC55B90055D09A /* TVCLogView.m in Sources */,\n\t\t\t\t4C06E6CF20EC55B90055D09A /* TVCLogViewInternalWK1.m in Sources */,\n\t\t\t\t4C06E6D020EC55B90055D09A /* TVCLogViewInternalWK2.m in Sources */,\n\t\t\t\t4C06E6D120EC55B90055D09A /* TVCWK1AutoScroller.m in Sources */,\n\t\t\t\t4C06E6D220EC55B90055D09A /* TVCAlert.m in Sources */,\n\t\t\t\t4C06E6D320EC55B90055D09A /* TVCErrorMessagePopover.m in Sources */,\n\t\t\t\t4C06E6D420EC55B90055D09A /* TVCErrorMessagePopoverController.m in Sources */,\n\t\t\t\t4C06E6D520EC55B90055D09A /* TVCAutoExpandingTextField.m in Sources */,\n\t\t\t\t4C06E6D620EC55B90055D09A /* TVCAutoExpandingTokenField.m in Sources */,\n\t\t\t\t4C06E6D720EC55B90055D09A /* TVCTextFormatterMenu.m in Sources */,\n\t\t\t\t4C06E6D820EC55B90055D09A /* TVCTextViewWithIRCFormatter.m in Sources */,\n\t\t\t\t4C06E6D920EC55B90055D09A /* TVCValidatedComboBox.m in Sources */,\n\t\t\t\t4C06E6DA20EC55B90055D09A /* TVCValidatedTextField.m in Sources */,\n\t\t\t\t4C06E6DB20EC55B90055D09A /* TVCMainWindow.m in Sources */,\n\t\t\t\t4C06E6DC20EC55B90055D09A /* TVCMainWindowAppearance.m in Sources */,\n\t\t\t\t4C06E6DD20EC55B90055D09A /* TVCMainWindowChannelView.m in Sources */,\n\t\t\t\t4C06E6DE20EC55B90055D09A /* TVCMainWindowLoadingScreen.m in Sources */,\n\t\t\t\t4C06E6DF20EC55B90055D09A /* TVCMainWindowSegmentedControl.m in Sources */,\n\t\t\t\t4C06E6E120EC55B90055D09A /* TVCMainWindowSplitView.m in Sources */,\n\t\t\t\t4C06E6E220EC55B90055D09A /* TVCMainWindowTextView.m in Sources */,\n\t\t\t\t4C06E6E320EC55B90055D09A /* TVCMainWindowTextViewAppearance.m in Sources */,\n\t\t\t\t4C06E6E420EC55B90055D09A /* TVCMainWindowTitlebarAccessoryView.m in Sources */,\n\t\t\t\t4C06E6E520EC55B90055D09A /* TVCNotificationConfigurationViewController.m in Sources */,\n\t\t\t\t4C06E6E620EC55B90055D09A /* TVCServerList.m in Sources */,\n\t\t\t\t4C5274E820F8D7CD00B18F9D /* IRCConnectionErrors.m in Sources */,\n\t\t\t\t4C06E6E720EC55B90055D09A /* TVCServerListAppearance.m in Sources */,\n\t\t\t\t4C06E6E820EC55B90055D09A /* TVCServerListCell.m in Sources */,\n\t\t\t\t4C06E6E920EC55B90055D09A /* TVCMemberList.m in Sources */,\n\t\t\t\t4C06E6EA20EC55B90055D09A /* TVCMemberListAppearance.m in Sources */,\n\t\t\t\t4C06E6EB20EC55B90055D09A /* TVCMemberListCell.m in Sources */,\n\t\t\t\t4C06E6EC20EC55B90055D09A /* TVCMemberListUserInfoPopover.m in Sources */,\n\t\t\t\t4C06E6ED20EC55B90055D09A /* TVCAppearance.m in Sources */,\n\t\t\t\t4C06E6EE20EC55B90055D09A /* TVCBasicTableView.m in Sources */,\n\t\t\t\t4C06E6EF20EC55B90055D09A /* TVCContentNavigationOutlineView.m in Sources */,\n\t\t\t\t4CB873DE22B4A56B005AB046 /* TDCPreferencesUserStyleSheet.m in Sources */,\n\t\t\t\t4C06E6F020EC55B90055D09A /* TVCDockIcon.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t4CBB842D16F0DA1D004E3ED6 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 4CCF301015804DCE006FFE21 /* Build Frameworks */;\n\t\t\ttargetProxy = 4CBB842C16F0DA1D004E3ED6 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C06E13920EC4AC40055D09A /* TDCServerPropertiesSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E13A20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerPropertiesSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E13D20EC4AC40055D09A /* TDCServerHighlightListSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E13E20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerHighlightListSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E13F20EC4AC40055D09A /* TDCServerEndpointListSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14020EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerEndpointListSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14120EC4AC40055D09A /* TDCChannelModifyModesSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14220EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelModifyModesSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14320EC4AC40055D09A /* TDCChannelSpotlightController.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14420EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelSpotlightController.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14520EC4AC40055D09A /* TDCFileTransferDialog.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14620EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCFileTransferDialog.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14720EC4AC40055D09A /* TDCServerChannelListDialog.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14820EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerChannelListDialog.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14920EC4AC40055D09A /* TDCChannelBanListSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14A20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelBanListSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14B20EC4AC40055D09A /* TDCChannelPropertiesSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14C20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelPropertiesSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E14D20EC4AC40055D09A /* TDCLicenseManagerMigrateAppStoreSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E14E20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseManagerMigrateAppStoreSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15120EC4AC40055D09A /* TDCLicenseUpgradeEligibilitySheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15220EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseUpgradeEligibilitySheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15520EC4AC40055D09A /* TVCChannelSelectionView.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15620EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCChannelSelectionView.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15720EC4AC40055D09A /* TXCMainMenu.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15820EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TXCMainMenu.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15920EC4AC40055D09A /* TVCNotificationConfigurationView.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15A20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCNotificationConfigurationView.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15B20EC4AC40055D09A /* TDCLicenseUpgradeActivateSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15C20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseUpgradeActivateSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15D20EC4AC40055D09A /* TDCPreferences.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E15E20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCPreferences.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E15F20EC4AC40055D09A /* TDCChannelInviteSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16020EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelInviteSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16120EC4AC40055D09A /* TDCNicknameColorSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16220EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCNicknameColorSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16320EC4AC40055D09A /* TDCWelcomeSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16420EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCWelcomeSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16520EC4AC40055D09A /* TDCProgressIndicatorSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16620EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCProgressIndicatorSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16720EC4AC40055D09A /* TDCAddressBookSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16820EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCAddressBookSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16920EC4AC40055D09A /* TVCAlert.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16A20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCAlert.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16B20EC4AC40055D09A /* TDCLicenseUpgradeDialog.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16C20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseUpgradeDialog.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16D20EC4AC40055D09A /* TDCServerChangeNicknameSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E16E20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerChangeNicknameSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E16F20EC4AC40055D09A /* TDCChannelModifyTopicSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17020EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelModifyTopicSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17120EC4AC40055D09A /* TDCAboutDialog.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17220EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCAboutDialog.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17320EC4AC40055D09A /* TDCHighlightEntrySheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17420EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCHighlightEntrySheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17520EC4AC40055D09A /* TVCMainWindow.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17620EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCMainWindow.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17720EC4AC40055D09A /* TDCLicenseManagerDialog.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17820EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseManagerDialog.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E17920EC4AC40055D09A /* TDCLicenseManagerRecoverLostLicenseSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E17A20EC4AC40055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseManagerRecoverLostLicenseSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2A720EC4FF00055D09A /* Prompts.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2A820EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = Prompts.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2A920EC4FF00055D09A /* OffTheRecord.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2AA20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = OffTheRecord.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2AB20EC4FF00055D09A /* CommonErrors.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2AC20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = CommonErrors.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2AF20EC4FF00055D09A /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B020EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2B120EC4FF00055D09A /* Accessibility.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B220EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = Accessibility.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2B320EC4FF00055D09A /* TDCChannelPropertiesSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B420EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelPropertiesSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2B520EC4FF00055D09A /* TDCChannelBanListSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B620EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelBanListSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2B720EC4FF00055D09A /* TDCPreferencesController.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2B820EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCPreferencesController.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2B920EC4FF00055D09A /* TDCFileTransferDialog.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2BA20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCFileTransferDialog.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2BB20EC4FF00055D09A /* TDCChannelInviteSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2BC20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelInviteSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2BD20EC4FF00055D09A /* TDCAboutDialog.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2BE20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCAboutDialog.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2BF20EC4FF00055D09A /* TDCServerPropertiesSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2C020EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerPropertiesSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2C120EC4FF00055D09A /* IRC.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2C220EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = IRC.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2C320EC4FF00055D09A /* TLOLicenseManager.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2C420EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TLOLicenseManager.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2C520EC4FF00055D09A /* TDCChannelModifyModesSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2C620EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelModifyModesSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2C720EC4FF00055D09A /* TVCMainWindow.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2C820EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCMainWindow.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2C920EC4FF00055D09A /* Notifications.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2CA20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = Notifications.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2CD20EC4FF00055D09A /* TVCNotificationConfigurationView.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2CE20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TVCNotificationConfigurationView.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2CF20EC4FF00055D09A /* TDCServerEndpointListSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2D020EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerEndpointListSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2D120EC4FF00055D09A /* TDCServerChannelListDialog.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2D220EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCServerChannelListDialog.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2D320EC4FF00055D09A /* TDCChannelSpotlightController.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2D420EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelSpotlightController.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2D520EC4FF00055D09A /* TDCAddressBookSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2D620EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCAddressBookSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2D720EC4FF00055D09A /* TDCLicenseUpgradeEligibilitySheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2D820EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCLicenseUpgradeEligibilitySheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C06E2D920EC4FF00055D09A /* TDCChannelModifyTopicSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06E2DA20EC4FF00055D09A /* en */,\n\t\t\t);\n\t\t\tname = TDCChannelModifyTopicSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C17305222B4A94000DC5836 /* TDCPreferencesUserStyleSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C17305322B4A94000DC5836 /* en */,\n\t\t\t);\n\t\t\tname = TDCPreferencesUserStyleSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CEFEDAE22B4B6E8002CEE19 /* TDCPreferencesUserStyleSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4CEFEDAF22B4B6E8002CEE19 /* en */,\n\t\t\t);\n\t\t\tname = TDCPreferencesUserStyleSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4C13442320C75C4900343AB7 /* Release (Sandboxed) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (Sandboxed)\";\n\t\t};\n\t\t4C13442520C75C4900343AB7 /* Release (Sandboxed) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (Sandboxed)\";\n\t\t};\n\t\t4C13442620C75C4900343AB7 /* Release (Sandboxed) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (Sandboxed)\";\n\t\t};\n\t\t4C13442820C75C4900343AB7 /* Release (Sandboxed) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = \"Release (Sandboxed)\";\n\t\t};\n\t\t4C1DC56E1580420500A47BC9 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C3154DF20EB685700448776 /* Textual App.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C1DC56F1580420500A47BC9 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C3154B720EB685700448776 /* Textual App.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C1DC5711580420500A47BC9 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C1DC5721580420500A47BC9 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C5BA4E216F1302F00A96CA2 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C5BA4E316F1302F00A96CA2 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CCF301215804DCE006FFE21 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4CCF301315804DCE006FFE21 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4C1DC54C1580420500A47BC9 /* Build configuration list for PBXProject \"Textual App\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C1DC56E1580420500A47BC9 /* Debug */,\n\t\t\t\t4C1DC56F1580420500A47BC9 /* Release */,\n\t\t\t\t4C13442320C75C4900343AB7 /* Release (Sandboxed) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4C1DC5701580420500A47BC9 /* Build configuration list for PBXNativeTarget \"Textual (Standard Release)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C1DC5711580420500A47BC9 /* Debug */,\n\t\t\t\t4C1DC5721580420500A47BC9 /* Release */,\n\t\t\t\t4C13442620C75C4900343AB7 /* Release (Sandboxed) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4C5BA4E116F1302F00A96CA2 /* Build configuration list for PBXNativeTarget \"Textual (Debug)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C5BA4E216F1302F00A96CA2 /* Debug */,\n\t\t\t\t4C5BA4E316F1302F00A96CA2 /* Release */,\n\t\t\t\t4C13442520C75C4900343AB7 /* Release (Sandboxed) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4CCF301115804DCE006FFE21 /* Build configuration list for PBXAggregateTarget \"Build Frameworks\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4CCF301215804DCE006FFE21 /* Debug */,\n\t\t\t\t4CCF301315804DCE006FFE21 /* Release */,\n\t\t\t\t4C13442820C75C4900343AB7 /* Release (Sandboxed) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 4C1DC5491580420500A47BC9 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/App/Textual App.xcodeproj/xcshareddata/xcschemes/Textual (App Store).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1600\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"NO\">\n      <PreActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;mkdir -p &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/&quot;&#10;&#10;exec &quot;${PROJECT_DIR}/Build Scripts/UpdateVersionInfo.sh&quot; &gt; &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateVersionInfo.txt&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C0BA4F81990798800857343\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (App Store)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PreActions>\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4C0BA4F81990798800857343\"\n               BuildableName = \"Textual.app\"\n               BlueprintName = \"Textual (App Store)\"\n               ReferencedContainer = \"container:Textual App.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"App Store\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"App Store\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C0BA4F81990798800857343\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (App Store)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"App Store\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C0BA4F81990798800857343\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (App Store)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"App Store\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"App Store\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/App/Textual App.xcodeproj/xcshareddata/xcschemes/Textual (Debug).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1600\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"NO\">\n      <PreActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;mkdir -p &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/&quot;&#10;&#10;exec &quot;${PROJECT_DIR}/Build Scripts/UpdateVersionInfo.sh&quot; &gt; &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateVersionInfo.txt&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C5BA37216F1302F00A96CA2\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (Debug)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PreActions>\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4C5BA37216F1302F00A96CA2\"\n               BuildableName = \"Textual.app\"\n               BlueprintName = \"Textual (Debug)\"\n               ReferencedContainer = \"container:Textual App.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C5BA37216F1302F00A96CA2\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Debug)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Debug\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C5BA37216F1302F00A96CA2\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Debug)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Debug\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/App/Textual App.xcodeproj/xcshareddata/xcschemes/Textual (Standard Release Sandboxed).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1600\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"NO\">\n      <PreActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;mkdir -p &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/&quot;&#10;&#10;exec &quot;${PROJECT_DIR}/Build Scripts/UpdateVersionInfo.sh&quot; &gt; &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateVersionInfo.txt&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C47314220C7599800713C91\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (Standard Release Sandboxed)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PreActions>\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4C47314220C7599800713C91\"\n               BuildableName = \"Textual.app\"\n               BlueprintName = \"Textual (Standard Release Sandboxed)\"\n               ReferencedContainer = \"container:Textual App.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Release (Sandboxed)\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release (Sandboxed)\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C47314220C7599800713C91\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Standard Release Sandboxed)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release (Sandboxed)\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C47314220C7599800713C91\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Standard Release Sandboxed)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Release (Sandboxed)\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release (Sandboxed)\"\n      revealArchiveInOrganizer = \"YES\">\n      <PostActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;exec &quot;${PROJECT_DIR}/Build Scripts/ExportArchive.sh&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C47314220C7599800713C91\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (Standard Release Sandboxed)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PostActions>\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/App/Textual App.xcodeproj/xcshareddata/xcschemes/Textual (Standard Release).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1600\"\n   version = \"1.7\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"NO\">\n      <PreActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;mkdir -p &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/&quot;&#10;&#10;exec &quot;${PROJECT_DIR}/Build Scripts/UpdateVersionInfo.sh&quot; &gt; &quot;${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/UpdateVersionInfo.txt&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C1DC5511580420500A47BC9\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (Standard Release)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PreActions>\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4C1DC5511580420500A47BC9\"\n               BuildableName = \"Textual.app\"\n               BlueprintName = \"Textual (Standard Release)\"\n               ReferencedContainer = \"container:Textual App.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C1DC5511580420500A47BC9\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Standard Release)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4C1DC5511580420500A47BC9\"\n            BuildableName = \"Textual.app\"\n            BlueprintName = \"Textual (Standard Release)\"\n            ReferencedContainer = \"container:Textual App.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Release\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n      <PostActions>\n         <ExecutionAction\n            ActionType = \"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction\">\n            <ActionContent\n               title = \"Run Script\"\n               scriptText = \"&#10;exec &quot;${PROJECT_DIR}/Build Scripts/ExportArchive.sh&quot;&#10;\">\n               <EnvironmentBuildable>\n                  <BuildableReference\n                     BuildableIdentifier = \"primary\"\n                     BlueprintIdentifier = \"4C1DC5511580420500A47BC9\"\n                     BuildableName = \"Textual.app\"\n                     BlueprintName = \"Textual (Standard Release)\"\n                     ReferencedContainer = \"container:Textual App.xcodeproj\">\n                  </BuildableReference>\n               </EnvironmentBuildable>\n            </ActionContent>\n         </ExecutionAction>\n      </PostActions>\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/ACKNOWLEDGEMENT.txt",
    "content": "\n|----------------------------------------------------------------------------|\n|                                                                            |\n|  Portions of the “Blowfish Encryption Extension” project may utilize       |\n|  copyrighted work derived from various 3rd party, open source projects     |\n|  The use of this work is hereby acknowledged.                              |\n|                                                                            |\n|----------------------------------------------------------------------------|\n\nClasses/BlowfishEncryptionKeyExchange.mm\nClasses/BlowfishEncryptionKeyExchange.h\n\n// Copyright (c) 2005-2013 Mathias Karlsson\n//\n// This program is free software; you can redistribute it and/or\n// modify it under the terms of the GNU General Public License\n// as published by the Free Software Foundation; either version 2\n// of the License, or (at your option) any later version.\n//\n// Please see LICENSE-GPLv2.txt for further information.\n\n|-----------------------------------------------------------------------|\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Blowfish Encryption Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AAFD20F27F8E007CA939 /* TPIBlowfishEncryption.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAFB20F27F8E007CA939 /* TPIBlowfishEncryption.xib */; };\n\t\t4C36AB0020F27F95007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAFE20F27F95007CA939 /* BasicLanguage.strings */; };\n\t\t4C46A1BF20EC705F00094EA4 /* BlowfishEncryptionBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1B520EC705F00094EA4 /* BlowfishEncryptionBase.m */; };\n\t\t4C46A1C020EC705F00094EA4 /* TPIBlowfishEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1B620EC705F00094EA4 /* TPIBlowfishEncryption.m */; };\n\t\t4C46A1C120EC705F00094EA4 /* BlowfishEncryptionKeyExchange.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1B720EC705F00094EA4 /* BlowfishEncryptionKeyExchange.mm */; };\n\t\t4C46A1C220EC705F00094EA4 /* BlowfishEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1B820EC705F00094EA4 /* BlowfishEncryption.m */; };\n\t\t4C46A1C320EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1BB20EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.m */; };\n\t\t4C46A1C420EC705F00094EA4 /* NSDataHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1BC20EC705F00094EA4 /* NSDataHelper.m */; };\n\t\t4C46A1C520EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A1BD20EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.mm */; };\n\t\t4C46A1D420EC70B600094EA4 /* LICENSE-GPLv2.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A1D120EC70B600094EA4 /* LICENSE-GPLv2.txt */; };\n\t\t4C46A1D520EC70B600094EA4 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A1D220EC70B600094EA4 /* LICENSE.txt */; };\n\t\t4C46A1D620EC70B600094EA4 /* ACKNOWLEDGEMENT.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A1D320EC70B600094EA4 /* ACKNOWLEDGEMENT.txt */; };\n\t\t4CBE7B4C1A91471A008FB230 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBE7B4A1A91471A008FB230 /* CocoaExtensions.framework */; };\n\t\t4CF284A01F8EEA0E00C14E24 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF2849F1F8EE9BA00C14E24 /* libcrypto.a */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C36AAFC20F27F8E007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPIBlowfishEncryption.xib; sourceTree = \"<group>\"; };\n\t\t4C36AAFF20F27F95007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C46A1AF20EC705F00094EA4 /* TPIBlowfishEncryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPIBlowfishEncryption.h; sourceTree = \"<group>\"; };\n\t\t4C46A1B120EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowfishEncryptionKeyExchangeBase.h; sourceTree = \"<group>\"; };\n\t\t4C46A1B220EC705F00094EA4 /* BlowfishEncryption.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowfishEncryption.h; sourceTree = \"<group>\"; };\n\t\t4C46A1B320EC705F00094EA4 /* NSDataHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDataHelper.h; sourceTree = \"<group>\"; };\n\t\t4C46A1B420EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPIBlowfishEncryptionSwizzledClasses.h; sourceTree = \"<group>\"; };\n\t\t4C46A1B520EC705F00094EA4 /* BlowfishEncryptionBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlowfishEncryptionBase.m; sourceTree = \"<group>\"; };\n\t\t4C46A1B620EC705F00094EA4 /* TPIBlowfishEncryption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPIBlowfishEncryption.m; sourceTree = \"<group>\"; };\n\t\t4C46A1B720EC705F00094EA4 /* BlowfishEncryptionKeyExchange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BlowfishEncryptionKeyExchange.mm; sourceTree = \"<group>\"; };\n\t\t4C46A1B820EC705F00094EA4 /* BlowfishEncryption.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlowfishEncryption.m; sourceTree = \"<group>\"; };\n\t\t4C46A1B920EC705F00094EA4 /* BlowfishEncryptionBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowfishEncryptionBase.h; sourceTree = \"<group>\"; };\n\t\t4C46A1BA20EC705F00094EA4 /* BlowfishEncryptionKeyExchange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlowfishEncryptionKeyExchange.h; sourceTree = \"<group>\"; };\n\t\t4C46A1BB20EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPIBlowfishEncryptionSwizzledClasses.m; sourceTree = \"<group>\"; };\n\t\t4C46A1BC20EC705F00094EA4 /* NSDataHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDataHelper.m; sourceTree = \"<group>\"; };\n\t\t4C46A1BD20EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BlowfishEncryptionKeyExchangeBase.mm; sourceTree = \"<group>\"; };\n\t\t4C46A1C820EC70A200094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A1D120EC70B600094EA4 /* LICENSE-GPLv2.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = \"LICENSE-GPLv2.txt\"; sourceTree = SOURCE_ROOT; };\n\t\t4C46A1D220EC70B600094EA4 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = SOURCE_ROOT; };\n\t\t4C46A1D320EC70B600094EA4 /* ACKNOWLEDGEMENT.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ACKNOWLEDGEMENT.txt; sourceTree = SOURCE_ROOT; };\n\t\t4C46A1DA20EC70C000094EA4 /* Inherited.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Inherited.entitlements; sourceTree = \"<group>\"; };\n\t\t4C46A1DE20EC70C000094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A1DF20EC70C000094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1E320EC70C000094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1E620EC70C000094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A1E720EC70C000094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1EB20EC70C000094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1EF20EC70C000094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A1F020EC70C000094EA4 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1F120EC70C000094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1F320EC70C000094EA4 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A1F620EC70C000094EA4 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1FA20EC70C000094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A1FB20EC70C000094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1FF20EC70C000094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A20220EC70C000094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A20320EC70C000094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A20720EC70C000094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CBE7B4A1A91471A008FB230 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CF2849F1F8EE9BA00C14E24 /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = \"../../../Frameworks/Static Libraries/Libraries/libcrypto.a\"; sourceTree = SOURCE_ROOT; };\n\t\t8D576316048677EA00EA77CD /* BlowfishEncryption.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BlowfishEncryption.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CF284A01F8EEA0E00C14E24 /* libcrypto.a in Frameworks */,\n\t\t\t\t4CBE7B4C1A91471A008FB230 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BlowfishCommandLine */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1AE20EC705F00094EA4 /* Classes */,\n\t\t\t\t4C46A1C620EC70A200094EA4 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BlowfishCommandLine;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C8F2F6C1AAE661B007821CC /* External Frameworks */,\n\t\t\t\t4CF2849E1F8EE99E00C14E24 /* External Libraries */,\n\t\t\t\t4CD8861D16C09BA00000CF8D /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* BlowfishEncryption.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1AE20EC705F00094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1B220EC705F00094EA4 /* BlowfishEncryption.h */,\n\t\t\t\t4C46A1B820EC705F00094EA4 /* BlowfishEncryption.m */,\n\t\t\t\t4C46A1B920EC705F00094EA4 /* BlowfishEncryptionBase.h */,\n\t\t\t\t4C46A1B520EC705F00094EA4 /* BlowfishEncryptionBase.m */,\n\t\t\t\t4C46A1BA20EC705F00094EA4 /* BlowfishEncryptionKeyExchange.h */,\n\t\t\t\t4C46A1B720EC705F00094EA4 /* BlowfishEncryptionKeyExchange.mm */,\n\t\t\t\t4C46A1B120EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.h */,\n\t\t\t\t4C46A1BD20EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.mm */,\n\t\t\t\t4C46A1B320EC705F00094EA4 /* NSDataHelper.h */,\n\t\t\t\t4C46A1BC20EC705F00094EA4 /* NSDataHelper.m */,\n\t\t\t\t4C46A1AF20EC705F00094EA4 /* TPIBlowfishEncryption.h */,\n\t\t\t\t4C46A1B620EC705F00094EA4 /* TPIBlowfishEncryption.m */,\n\t\t\t\t4C46A1B420EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.h */,\n\t\t\t\t4C46A1BB20EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1C620EC70A200094EA4 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1D720EC70C000094EA4 /* Configurations */,\n\t\t\t\t4C46A1D020EC70AB00094EA4 /* Documents */,\n\t\t\t\t4C46A1C920EC70A200094EA4 /* Language Files */,\n\t\t\t\t4C46A1C720EC70A200094EA4 /* Property Lists */,\n\t\t\t\t4C46A1CB20EC70A200094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1C720EC70A200094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1C820EC70A200094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1C920EC70A200094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAFE20F27F95007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1CB20EC70A200094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAFB20F27F8E007CA939 /* TPIBlowfishEncryption.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1D020EC70AB00094EA4 /* Documents */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1D320EC70B600094EA4 /* ACKNOWLEDGEMENT.txt */,\n\t\t\t\t4C46A1D120EC70B600094EA4 /* LICENSE-GPLv2.txt */,\n\t\t\t\t4C46A1D220EC70B600094EA4 /* LICENSE.txt */,\n\t\t\t);\n\t\t\tname = Documents;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1D720EC70C000094EA4 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1DB20EC70C000094EA4 /* Build */,\n\t\t\t\t4C46A1D920EC70C000094EA4 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C46A1D920EC70C000094EA4 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1DA20EC70C000094EA4 /* Inherited.entitlements */,\n\t\t\t);\n\t\t\tpath = Sandbox;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1DB20EC70C000094EA4 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1E420EC70C000094EA4 /* App Store Release */,\n\t\t\t\t4C46A1ED20EC70C000094EA4 /* Common */,\n\t\t\t\t4C46A20020EC70C000094EA4 /* Debug */,\n\t\t\t\t4C46A1DC20EC70C000094EA4 /* Standard Release */,\n\t\t\t\t4C46A1F820EC70C000094EA4 /* Standard Release Sandboxed */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1DC20EC70C000094EA4 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1E320EC70C000094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A1DF20EC70C000094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A1DE20EC70C000094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1E420EC70C000094EA4 /* App Store Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1EB20EC70C000094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A1E720EC70C000094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A1E620EC70C000094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"App Store Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1ED20EC70C000094EA4 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1F620EC70C000094EA4 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C46A1F320EC70C000094EA4 /* Foundation.xcconfig */,\n\t\t\t\t4C46A1F020EC70C000094EA4 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C46A1F120EC70C000094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A1EF20EC70C000094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A1F820EC70C000094EA4 /* Standard Release Sandboxed */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1FF20EC70C000094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A1FB20EC70C000094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A1FA20EC70C000094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release Sandboxed\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A20020EC70C000094EA4 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A20720EC70C000094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A20320EC70C000094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A20220EC70C000094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8F2F6C1AAE661B007821CC /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBE7B4A1A91471A008FB230 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CD8861D16C09BA00000CF8D /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CF2849E1F8EE99E00C14E24 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CF2849F1F8EE9BA00C14E24 /* libcrypto.a */,\n\t\t\t);\n\t\t\tname = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* Blowfish Encryption Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Blowfish Encryption Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4CD4026F16C8CE4E00FEA686 /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Blowfish Encryption Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BlowfishCommandLine;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* BlowfishEncryption.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1250;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Blowfish Encryption Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BlowfishCommandLine */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* Blowfish Encryption Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4CD4026F16C8CE4E00FEA686 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AAFD20F27F8E007CA939 /* TPIBlowfishEncryption.xib in Resources */,\n\t\t\t\t4C36AB0020F27F95007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t\t4C46A1D420EC70B600094EA4 /* LICENSE-GPLv2.txt in Resources */,\n\t\t\t\t4C46A1D520EC70B600094EA4 /* LICENSE.txt in Resources */,\n\t\t\t\t4C46A1D620EC70B600094EA4 /* ACKNOWLEDGEMENT.txt in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A1C220EC705F00094EA4 /* BlowfishEncryption.m in Sources */,\n\t\t\t\t4C46A1C420EC705F00094EA4 /* NSDataHelper.m in Sources */,\n\t\t\t\t4C46A1C320EC705F00094EA4 /* TPIBlowfishEncryptionSwizzledClasses.m in Sources */,\n\t\t\t\t4C46A1C520EC705F00094EA4 /* BlowfishEncryptionKeyExchangeBase.mm in Sources */,\n\t\t\t\t4C46A1BF20EC705F00094EA4 /* BlowfishEncryptionBase.m in Sources */,\n\t\t\t\t4C46A1C120EC705F00094EA4 /* BlowfishEncryptionKeyExchange.mm in Sources */,\n\t\t\t\t4C46A1C020EC705F00094EA4 /* TPIBlowfishEncryption.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAFB20F27F8E007CA939 /* TPIBlowfishEncryption.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAFC20F27F8E007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPIBlowfishEncryption.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAFE20F27F95007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAFF20F27F95007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A20320EC70C000094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Headers/**\\\"\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Sources/App/Classes/Headers/Private/**\\\"\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Libraries/**\\\"\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-BlowfishEncryption\";\n\t\t\t\tPRODUCT_NAME = BlowfishEncryption;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Headers/**\\\"\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Sources/App/Classes/Headers/Private/**\\\"\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Libraries/**\\\"\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-BlowfishEncryption\";\n\t\t\t\tPRODUCT_NAME = BlowfishEncryption;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A1DF20EC70C000094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CCD21D81FA41CE80056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A1E720EC70C000094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4CCD21D91FA41CE80056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tHEADER_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Headers/**\\\"\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Sources/App/Classes/Headers/Private/**\\\"\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"${inherited}\",\n\t\t\t\t\t\"\\\"${TEXTUAL_WORKSPACE_DIR}/Frameworks/Static Libraries/Libraries/**\\\"\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-BlowfishEncryption\";\n\t\t\t\tPRODUCT_NAME = BlowfishEncryption;\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Blowfish Encryption Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4CCD21D91FA41CE80056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Blowfish Encryption Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4CCD21D81FA41CE80056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Blowfish Encryption Extension.xcodeproj/xcshareddata/xcschemes/Blowfish Encryption Extension.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1250\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n               BuildableName = \"BlowfishEncryption.bundle\"\n               BlueprintName = \"Blowfish Encryption Extension\"\n               ReferencedContainer = \"container:Blowfish Encryption Extension.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"BlowfishEncryption.bundle\"\n            BlueprintName = \"Blowfish Encryption Extension\"\n            ReferencedContainer = \"container:Blowfish Encryption Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"BlowfishEncryption.bundle\"\n            BlueprintName = \"Blowfish Encryption Extension\"\n            ReferencedContainer = \"container:Blowfish Encryption Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Release\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryption.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <Foundation/Foundation.h>\n\ntypedef enum EKBlowfishEncryptionModeOfOperation : NSInteger {\n\tEKBlowfishEncryptionNoneModeOfOperation\t\t= -1,\t\t\t\t// Does nothing, just returns original\n\tEKBlowfishEncryptionDefaultModeOfOperation\t= 0,\t\t\t\t// Default goes to ECB\n\tEKBlowfishEncryptionECBModeOfOperation\t\t= 1,\n\tEKBlowfishEncryptionCBCModeOfOperation\t\t= 2\n} EKBlowfishEncryptionModeOfOperation;\n\n@interface EKBlowfishEncryption : NSObject\n+ (NSUInteger)estimatedLengthOfEncodedDataOfLength:(NSUInteger)dataLength;\n\n+ (NSString *)encodeData:(NSString *)input key:(NSString *)phrase mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)local;\n+ (NSString *)decodeData:(NSString *)input key:(NSString *)phrase mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)local lostBytes:(NSInteger *)lostBytes;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryption.m",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BlowfishEncryption.h\"\n#import \"BlowfishEncryptionBase.h\"\n\n@implementation EKBlowfishEncryption\n\n+ (NSUInteger)estimatedLengthOfEncodedDataOfLength:(NSUInteger)dataLength\n{\n\treturn [EKBlowfishEncryptionBase estimatedLengthOfEncodedDataOfLength:dataLength];\n}\n\n+ (NSString *)encodeData:(NSString *)input key:(NSString *)phrase mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)local\n{\n\tif (mode == EKBlowfishEncryptionNoneModeOfOperation) {\n\t\treturn input;\n\t}\n\t\n\tif ([phrase length] > 56) {\n\t\tNSLog(@\"[EKBlowfishEncryption] WARNING: Using a key length greater than 56 will result in that key itself being truncated to the first 56 characters.\");\n\n\t\tphrase = [phrase substringToIndex:56];\n\t}\n\n\tNSString *result = [EKBlowfishEncryptionBase encrypt:input key:phrase mode:mode encoding:local];\n\n\tif ([result length] <= 0) {\n\t\treturn nil;\n\t}\n\n\tif (mode == EKBlowfishEncryptionCBCModeOfOperation) {\n\t\treturn [@\"+OK *\" stringByAppendingString:result];\n\t} else {\n\t\treturn [@\"+OK \" stringByAppendingString:result];\n\t}\n}\n\n+ (NSString *)decodeData:(NSString *)input key:(NSString *)phrase mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)local lostBytes:(NSInteger *)lostBytes\n{\n\tif (mode == EKBlowfishEncryptionNoneModeOfOperation) {\n\t\treturn input;\n\t}\n\n\tBOOL hasOKPrefix = [input hasPrefix:@\"+OK \"];\n\tBOOL hasMCPSPrefix = [input hasPrefix:@\"mcps \"];\n\n\tif ((hasOKPrefix || hasMCPSPrefix)) {\n\t\tif (hasOKPrefix) {\n\t\t\tif ([input length] == 4) {\n\t\t\t\treturn @\" \"; /* Allow for empty strings. */\n\t\t\t} else {\n\t\t\t\tinput = [input substringFromIndex:4];\n\t\t\t}\n\t\t} else if (hasMCPSPrefix) {\n\t\t\tif ([input length] == 5) {\n\t\t\t\treturn @\" \"; /* Allow for empty strings. */\n\t\t\t} else {\n\t\t\t\tinput = [input substringFromIndex:5];\n\t\t\t}\n\t\t}\n\t} else {\n\t\treturn nil;\n\t}\n\t\n\t/* Star symbol acts as an auto-on. */\n\tif ([input hasPrefix:@\"*\"]) {\n\t\tinput = [input substringFromIndex:1];\n\t\t\n\t\tmode = EKBlowfishEncryptionCBCModeOfOperation;\n\t} else {\n\t\tmode = EKBlowfishEncryptionECBModeOfOperation;\n\t}\n\t\n\tif ([phrase length] > 56) {\n\t\tNSLog(@\"[EKBlowfishEncryption] WARNING: Using a key length greater than 56 will result in that key itself being truncated to the first 56 characters.\");\n\n\t\tphrase = [phrase substringToIndex:56];\n\t}\n\n\tNSString *result = [EKBlowfishEncryptionBase decrypt:input key:phrase mode:mode encoding:local lostBytes:lostBytes];\n\n\tif ([result length] <= 0) {\n\t\treturn nil;\n\t}\n\n\treturn result;\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionBase.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BlowfishEncryption.h\" // for enum\n\n@interface EKBlowfishEncryptionBase : NSObject\n+ (NSUInteger)estimatedLengthOfEncodedDataOfLength:(NSUInteger)dataLength;\n\n+ (NSString *)encrypt:(NSString *)rawInput key:(NSString *)secretKey mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)dataEncoding;\n+ (NSString *)decrypt:(NSString *)rawInput key:(NSString *)secretKey mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)dataEncoding lostBytes:(NSInteger *)lostBytes;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionBase.m",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* A portion of this source file contains copyrighted work derived from one or more\n 3rd party, open source projects. The use of this work is hereby acknowledged. */\n\n// Copyright (c) 2005-2013 Mathias Karlsson\n//\n// This program is free software; you can redistribute it and/or\n// modify it under the terms of the GNU General Public License\n// as published by the Free Software Foundation; either version 2\n// of the License, or (at your option) any later version.\n//\n// Please see LICENSE-GPLv2.txt for further information.\n\n#import \"BlowfishEncryptionBase.h\"\n\n#import \"NSDataHelper.h\"\n\n#import <CocoaExtensions/XRBase64Encoding.h>\n\n#import <CommonCrypto/CommonCrypto.h>\n#import <CommonCrypto/CommonRandom.h>\n\nstatic const char blowfish_ecb_base64_chars[64] = \"./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n#pragma mark -\n#pragma mark Implementation.\n\n@implementation EKBlowfishEncryptionBase\n\n+ (NSUInteger)estimatedLengthOfEncodedDataOfLength:(NSUInteger)dataLength\n{\n\t/* The returned estimation is the result of base64 encoded,\n\t properly padded encryption block up to input length. */\n\tNSUInteger blockLength = dataLength;\n\n\tNSUInteger blockLengthRemainder = (blockLength % kCCBlockSizeBlowfish);\n\n\tif (blockLengthRemainder != 0) {\n\t\tblockLength += (kCCBlockSizeBlowfish - blockLengthRemainder);\n\t}\n\n\treturn (ceil(blockLength / 3) * 4);\n}\n\n+ (NSString *)encrypt:(NSString *)rawInput key:(NSString *)secretKey mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)dataEncoding\n{\n\tif (mode == EKBlowfishEncryptionDefaultModeOfOperation || mode == EKBlowfishEncryptionECBModeOfOperation) {\n\t\treturn [self ecb_encrypt:rawInput key:secretKey encoding:dataEncoding];\n\t} else {\n\t\treturn [self cbc_encrypt:rawInput key:secretKey encoding:dataEncoding];\n\t}\n}\n\n+ (NSString *)decrypt:(NSString *)rawInput key:(NSString *)secretKey mode:(EKBlowfishEncryptionModeOfOperation)mode encoding:(NSStringEncoding)dataEncoding lostBytes:(NSInteger *)lostBytes\n{\n\tif (mode == EKBlowfishEncryptionDefaultModeOfOperation || mode == EKBlowfishEncryptionECBModeOfOperation) {\n\t\treturn [self ecb_decrypt:rawInput key:secretKey encoding:dataEncoding lostBytes:lostBytes];\n\t} else {\n\t\treturn [self cbc_decrypt:rawInput key:secretKey encoding:dataEncoding];\n\t}\n}\n\nNSData *_commonCryptoInitializationVector(void)\n{\n\tuint8_t initializationVector[kCCBlockSizeBlowfish] = {0};\n\n\tCCRNGStatus cryptoRandomBytesStatus =\n\tCCRandomGenerateBytes(&initializationVector, 8);\n\n\tif (cryptoRandomBytesStatus == kCCSuccess) {\n\t\treturn [NSData dataWithBytes:initializationVector length:kCCBlockSizeBlowfish];\n\t} else {\n\t\treturn nil;\n\t}\n}\n\nNSData *_performCommonCryptoOperation(CCOperation ccInOperation,\n\t\t\t\t\t\t\t\t\t  CCAlgorithm ccInOperationAlgorithm,\n\t\t\t\t\t\t\t\t\t  CCMode ccInOperationMode,\n\t\t\t\t\t\t\t\t\t  BOOL ccInOperationUsesPadding,\n\t\t\t\t\t\t\t\t\t  NSData *ccInitializationVector,\n\t\t\t\t\t\t\t\t\t  NSData *ccInSecretKey,\n\t\t\t\t\t\t\t\t\t  NSData *ccInRelatedData)\n{\n\t/* Perform basic validation on input data. */\n\tif (ccInSecretKey == nil || ccInRelatedData == nil) {\n\t\treturn nil;\n\t}\n\n\t/* Validate key length is within an expected range. */\n\tswitch (ccInOperationAlgorithm) {\n\t\tcase kCCAlgorithmAES128:\n\t\t{\n\t\t\tif ([ccInSecretKey length] != kCCKeySizeAES128 &&\n\t\t\t\t[ccInSecretKey length] != kCCKeySizeAES192 &&\n\t\t\t\t[ccInSecretKey length] != kCCKeySizeAES256)\n\t\t\t{\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithmDES:\n\t\t{\n\t\t\tif ([ccInSecretKey length] != kCCKeySizeDES) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithm3DES:\n\t\t{\n\t\t\tif ([ccInSecretKey length] != kCCKeySize3DES) {\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithmCAST:\n\t\t{\n\t\t\tif ([ccInSecretKey length] < kCCKeySizeMinCAST ||\n\t\t\t\t[ccInSecretKey length] > kCCKeySizeMaxCAST)\n\t\t\t{\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithmRC4:\n\t\t{\n\t\t\tif ([ccInSecretKey length] < kCCKeySizeMinRC4 ||\n\t\t\t\t[ccInSecretKey length] > kCCKeySizeMaxRC4)\n\t\t\t{\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithmRC2:\n\t\t{\n\t\t\tif ([ccInSecretKey length] < kCCKeySizeMinRC2 ||\n\t\t\t\t[ccInSecretKey length] > kCCKeySizeMaxRC2)\n\t\t\t{\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tcase kCCAlgorithmBlowfish:\n\t\t{\n\t\t\tif (/* [ccInSecretKey length] < kCCKeySizeMinBlowfish || */\n\t\t\t\t[ccInSecretKey length] > kCCKeySizeMaxBlowfish)\n\t\t\t{\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* Attempt to create a cryptor reference using input. */\n\tCCPadding ccInPadding;\n\n\tif (ccInOperationUsesPadding) {\n\t\tccInPadding = ccPKCS7Padding;\n\t} else {\n\t\tccInPadding = ccNoPadding;\n\t}\n\n\tCCCryptorRef cryptorRef;\n\n\tCCCryptorStatus cryptorCreateStatus =\n\tCCCryptorCreateWithMode(ccInOperation,\n\t\t\t\t\t\t\tccInOperationMode,\n\t\t\t\t\t\t\tccInOperationAlgorithm,\n\t\t\t\t\t\t\tccInPadding,\n\t\t\t\t\t\t\t[ccInitializationVector bytes],\n\t\t\t\t\t\t\t[ccInSecretKey bytes],\n\t\t\t\t\t\t\t[ccInSecretKey length],\n\t\t\t\t\t\t\tNULL,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t&cryptorRef);\n\n\tif (cryptorCreateStatus != kCCSuccess) {\n\t\treturn nil;\n\t}\n\n\t/* Create output buffer using expected output length. */\n\tBOOL willCallCryptorFinal = (ccInPadding == ccPKCS7Padding || ccInOperationAlgorithm == kCCAlgorithmRC4);\n\n\tsize_t outputBufferSize = CCCryptorGetOutputLength(cryptorRef, [ccInRelatedData length], willCallCryptorFinal);\n\n\tNSMutableData *outputBuffer = [NSMutableData dataWithLength:outputBufferSize];;\n\n\t/* Perform update operation on the cryptor. */\n\tsize_t cryptorUpdateDataOutMoved = 0;\n\n\tCCCryptorStatus cryptorUpdateStatus =\n\tCCCryptorUpdate(cryptorRef,\n\t\t\t\t\t[ccInRelatedData bytes],\n\t\t\t\t\t[ccInRelatedData length],\n\t\t\t\t\t[outputBuffer mutableBytes],\n\t\t\t\t\t[outputBuffer length],\n\t\t\t\t\t&cryptorUpdateDataOutMoved);\n\n\tif (cryptorUpdateStatus != kCCSuccess) {\n\t\tgoto cleanup_function;\n\t}\n\n\t/* Perform final operation on the cryptor. */\n\tsize_t totalBytesWritten = cryptorUpdateDataOutMoved;\n\n\tif (willCallCryptorFinal) {\n\t\tvoid *cryptorFinalDataOut = ([outputBuffer mutableBytes] + cryptorUpdateDataOutMoved);\n\n\t\tsize_t cryptorFinalDataOutSize = ([outputBuffer length] - cryptorUpdateDataOutMoved);\n\n\t\tCCCryptorStatus cryptorFinalStatus =\n\t\tCCCryptorFinal(cryptorRef,\n\t\t\t\t\t   cryptorFinalDataOut,\n\t\t\t\t\t   cryptorFinalDataOutSize,\n\t\t\t\t\t   &cryptorUpdateDataOutMoved);\n\n\t\tif (cryptorFinalStatus != kCCSuccess) {\n\t\t\tgoto cleanup_function;\n\t\t}\n\n\t\ttotalBytesWritten += cryptorUpdateDataOutMoved;\n\n\t\t[outputBuffer setLength:totalBytesWritten];\n\t}\n\ncleanup_function:\n\tif (cryptorRef) {\n\t\tCCCryptorRelease(cryptorRef);\n\t}\n\t\n\treturn outputBuffer;\n}\n\n#pragma mark -\n#pragma mark CBC Encryption\n\n+ (NSString *)cbc_encrypt:(NSString *)rawInput key:(NSString *)secretKey encoding:(NSStringEncoding)dataEncoding\n{\n\tNSData *secretKeyData = [secretKey dataUsingEncoding:dataEncoding];\n\n\tNSData *rawInputData = [rawInput dataUsingEncoding:dataEncoding paddedByBytes:kCCBlockSizeBlowfish];\n\n\tNSData *initializationVectorData = _commonCryptoInitializationVector();\n\n\tif (initializationVectorData == nil) {\n\t\treturn nil;\n\t}\n\n\t/* mIRC fish 10 places the initialization vector directly on the data\n\t stream rather than allowing the crypto library to handle that itself. \n\t If we do not append the IV here and instead feed it to Common Crypto,\n\t mIRC will not handle the operation properly. */\n\tNSMutableData *objectToEncrypt = [NSMutableData data];\n\n\t[objectToEncrypt appendData:initializationVectorData];\n\t[objectToEncrypt appendData:rawInputData];\n\n\tNSData *encryptedData =\n\t_performCommonCryptoOperation(kCCEncrypt, kCCAlgorithmBlowfish, kCCModeCBC, NO, nil, secretKeyData, objectToEncrypt);\n\n\treturn [XRBase64Encoding encodeData:encryptedData];\n}\n\n#pragma mark -\n#pragma mark CBC Decryption\n\n+ (NSString *)cbc_decrypt:(NSString *)rawInput key:(NSString *)secretKey encoding:(NSStringEncoding)dataEncoding\n{\n\tNSData *secretKeyData = [secretKey dataUsingEncoding:dataEncoding];\n\n\tNSData *rawInputData = [XRBase64Encoding decodeData:rawInput];\n\n\tNSData *decryptedData =\n\t_performCommonCryptoOperation(kCCDecrypt, kCCAlgorithmBlowfish, kCCModeCBC, NO, nil, secretKeyData, rawInputData);\n\n\t/* If we contain at least two blocks, then remove the first block. \n\t mIRC fish 10 has the IV in the first block then we want at least\n\t one block of user data. */\n\tif ([decryptedData length] >= (kCCBlockSizeBlowfish * 2)) {\n\t\t decryptedData = [decryptedData subdataWithRange:NSMakeRange(kCCBlockSizeBlowfish,\n\t\t\t\t\t\t\t\t\t\t   ([decryptedData length] - kCCBlockSizeBlowfish))];\n\t} else {\n\t\treturn nil;\n\t}\n\n\tNSMutableData *decryptedDataCleaned = [decryptedData mutableCopy];\n\t[decryptedDataCleaned removeBadCharacters];\n\n\treturn [[NSString alloc] initWithData:decryptedDataCleaned encoding:dataEncoding];\n}\n\n#pragma mark -\n#pragma mark ECB Mode Encryption\n\n+ (NSString *)ecb_encrypt:(NSString *)rawInput key:(NSString *)secretKey encoding:(NSStringEncoding)dataEncoding\n{\n\tNSData *secretKeyData = [secretKey dataUsingEncoding:dataEncoding];\n\n\tNSData *rawInputData = [rawInput dataUsingEncoding:dataEncoding paddedByBytes:kCCBlockSizeBlowfish];\n\n\tNSData *encryptedData =\n\t_performCommonCryptoOperation(kCCEncrypt, kCCAlgorithmBlowfish, kCCModeECB, NO, nil, secretKeyData, rawInputData);\n\n\tNSString *encryptedString = [EKBlowfishEncryptionBase ecb_encrypt_base64Encode:encryptedData];\n\n\treturn encryptedString;\n}\n\n+ (NSString *)ecb_decrypt:(NSString *)rawInput key:(NSString *)secretKey encoding:(NSStringEncoding)dataEncoding lostBytes:(NSInteger *)lostBytes\n{\n\tNSData *secretKeyData = [secretKey dataUsingEncoding:dataEncoding];\n\n\tNSData *encodedRawData = [rawInput dataUsingEncoding:dataEncoding fitToPadding:12 trimmedCharacters:lostBytes];\n\n\tNSData *rawInputData = [EKBlowfishEncryptionBase ecb_decrypt_base64Decode:encodedRawData];\n\n\tNSData *decryptedData =\n\t_performCommonCryptoOperation(kCCDecrypt, kCCAlgorithmBlowfish, kCCModeECB, NO, nil, secretKeyData, rawInputData);\n\n\tNSMutableData *decryptedDataCleaned = [decryptedData mutableCopy];\n\t[decryptedDataCleaned removeBadCharacters];\n\n\treturn [[NSString alloc] initWithData:decryptedDataCleaned encoding:dataEncoding];\n}\n\n#pragma mark -\n#pragma mark ECB Mode Encoding\n\n+ (NSString *)ecb_encrypt_base64Encode:(NSData *)encryptedData\n{\n\tif (encryptedData == nil) {\n\t\treturn nil;\n\t}\n\n\tif (([encryptedData length] % kCCBlockSizeBlowfish) != 0) {\n\t\treturn nil;\n\t}\n\n\tNSMutableData *outputBuffer = [NSMutableData data];\n\n\tunsigned char *s = (unsigned char *)[encryptedData bytes];\n\n\tfor (NSInteger i = 0; i < [encryptedData length]; i += 8) {\n\t\tunsigned int left;\n\t\tunsigned int right;\n\n\t\tleft  = (*s++ << 24);\n\t\tleft += (*s++ << 16);\n\t\tleft += (*s++ << 8);\n\t\tleft +=  *s++;\n\n\t\tright  = (*s++ << 24);\n\t\tright += (*s++ << 16);\n\t\tright += (*s++ << 8);\n\t\tright +=  *s++;\n\n\t\tfor (NSInteger k = 0; k < 6; k++) {\n\t\t\tunsigned char partChar = blowfish_ecb_base64_chars[(right & 0x3f)];\n\n\t\t\t[outputBuffer appendBytes:&partChar length:sizeof(partChar)];\n\n\t\t\tright = (right >> 6);\n\t\t}\n\n\t\tfor (NSInteger k = 0; k < 6; k++) {\n\t\t\tunsigned char partChar = blowfish_ecb_base64_chars[(left & 0x3f)];\n\n\t\t\t[outputBuffer appendBytes:&partChar length:sizeof(partChar)];\n\n\t\t\tleft = (left >> 6);\n\t\t}\n\t}\n\n\treturn [[NSString alloc] initWithData:outputBuffer encoding:NSASCIIStringEncoding];\n}\n\n+ (int)ecb_decrypt_base64DecodeCharacterIndex:(char)c\n{\n\tint i = (-1);\n\n\tfor (i = 0; i < 64; i++) {\n\t\tif (blowfish_ecb_base64_chars[i] == c) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn i;\n}\n\n+ (NSData *)ecb_decrypt_base64Decode:(NSData *)dataToDecrypt\n{\n\tif (dataToDecrypt == nil) {\n\t\treturn nil;\n\t}\n\n\tif (([dataToDecrypt length] % 12) != 0) {\n\t\treturn nil;\n\t}\n\n\tNSMutableData *outputBuffer = [NSMutableData data];\n\n\tunsigned char *s = (unsigned char *)[dataToDecrypt bytes];\n\n\tfor (NSInteger i = 0; i < [dataToDecrypt length]; i += 12) {\n\t\tunsigned int left = 0;\n\t\tunsigned int right = 0;\n\n\t\tfor (NSInteger k = 0; k < 6; k++) {\n\t\t\tint partChar = [EKBlowfishEncryptionBase ecb_decrypt_base64DecodeCharacterIndex:(*s++)];\n\n\t\t\tif (partChar == (-1)) {\n\t\t\t\treturn nil; // Bad character in block\n\t\t\t}\n\n\t\t\tright |= (partChar << k * 6);\n\t\t}\n\n\t\tfor (NSInteger k = 0; k < 6; k++) {\n\t\t\tint partChar = [EKBlowfishEncryptionBase ecb_decrypt_base64DecodeCharacterIndex:(*s++)];\n\n\t\t\tif (partChar == (-1)) {\n\t\t\t\treturn nil; // Bad character in block\n\t\t\t}\n\n\t\t\tleft |= (partChar << k * 6);\n\t\t}\n\n\t\tuint8_t bufferByte[8];\n\n\t\tbufferByte[0] = ((left >> 24) & 0xFF);\n\t\tbufferByte[1] = ((left >> 16) & 0xFF);\n\t\tbufferByte[2] = ((left >> 8) & 0xFF);\n\t\tbufferByte[3] =  (left & 0xFF);\n\n\t\tbufferByte[4] = ((right >> 24) & 0xFF);\n\t\tbufferByte[5] = ((right >> 16) & 0xFF);\n\t\tbufferByte[6] = ((right >> 8) & 0xFF);\n\t\tbufferByte[7] =  (right & 0xFF);\n\n\t\t[outputBuffer appendBytes:&bufferByte length:sizeof(bufferByte)];\n\t}\n\n\treturn [outputBuffer copy];\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionKeyExchange.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <Foundation/Foundation.h>\n\n@interface EKBlowfishEncryptionKeyExchange : NSObject\n- (NSString *)generatePublicKey;\n- (NSString *)secretKeyFromPublicKey:(NSString *)publicKey;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionKeyExchange.mm",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"BlowfishEncryptionKeyExchange.h\"\n#import \"BlowfishEncryptionKeyExchangeBase.h\"\n\n@interface EKBlowfishEncryptionKeyExchange ()\n@property (nonatomic, strong) EKBlowfishEncryptionKeyExchangeBase *keyExchanger;\n@end\n\n@implementation EKBlowfishEncryptionKeyExchange\n\n#pragma mark -\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\tself.keyExchanger = [EKBlowfishEncryptionKeyExchangeBase new];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\tself.keyExchanger = nil;\n}\n\n#pragma mark -\n\n- (NSString *)generatePublicKey\n{\n\tNSData *publicKeyRaw = [[self keyExchanger] rawPublicKey];\n\t\n    if ([publicKeyRaw length] >= 1) {\n        return [[self keyExchanger] publicKeyValue:publicKeyRaw];\n    }\n\t\n\treturn nil;\n}\n\n- (NSString *)secretKeyFromPublicKey:(NSString *)publicKey\n{\n\tNSData *publicKeyData = [[self keyExchanger] base64Decode:publicKey];\n\n\tif ([publicKeyData length] < EKBlowfishEncryptionKeyExchangeRequiredKeyLength ||\n\t\t[publicKeyData length] > EKBlowfishEncryptionKeyExchangeRequiredKeyLength)\n\t{\n\t\treturn nil;\n\t}\n\t\n\t[[self keyExchanger] setKeyForComputation:publicKeyData];\n\t[[self keyExchanger] computeKey];\n\n\tNSString *secretString = [[self keyExchanger] secretStringValue];\n\n\tif ([secretString length] <= 0) {\n\t\treturn nil;\n\t}\n\n\treturn secretString;\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionKeyExchangeBase.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* A portion of this source file contains copyrighted work derived from one or more\n 3rd party, open source projects. The use of this work is hereby acknowledged. */\n\n// Copyright (c) 2005-2013 Mathias Karlsson\n//\n// This program is free software; you can redistribute it and/or\n// modify it under the terms of the GNU General Public License\n// as published by the Free Software Foundation; either version 2\n// of the License, or (at your option) any later version.\n//\n// Please see LICENSE-GPLv2.txt for further information.\n\n#import <Foundation/Foundation.h>\n\n#define EKBlowfishEncryptionKeyExchangeRequiredKeyLength             135\n\n@interface EKBlowfishEncryptionKeyExchangeBase : NSObject\n- (void)computeKey;\n- (void)setKeyForComputation:(NSData *)publicKey;\n\n- (void)resetStatus;\n- (void)resetPublicInformation;\n\n- (NSString *)secretStringValue;\n\n- (NSData *)rawPublicKey;\n- (NSString *)publicKeyValue:(NSData *)publicInput;\n\n- (NSString *)base64Encode:(NSData *)input;\n- (NSData *)base64Decode:(NSString *)input;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/BlowfishEncryptionKeyExchangeBase.mm",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* A portion of this source file contains copyrighted work derived from one or more\n 3rd party, open source projects. The use of this work is hereby acknowledged. */\n\n// Copyright (c) 2005-2013 Mathias Karlsson\n//\n// This program is free software; you can redistribute it and/or\n// modify it under the terms of the GNU General Public License\n// as published by the Free Software Foundation; either version 2\n// of the License, or (at your option) any later version.\n//\n// Please see LICENSE-GPLv2.txt for further information.\n\n#import \"BlowfishEncryptionKeyExchangeBase.h\"\n\n#import <CocoaExtensions/XRBase64Encoding.h>\n\n/* OpenSSL Header Files. */\n#include <openssl/sha.h>\n#include <openssl/dh.h>\n#include <openssl/bn.h>\n\n/* Private Interface. */\n@interface EKBlowfishEncryptionKeyExchangeBase ()\n@property (nonatomic, strong) NSData *secretValue;\n@property (nonatomic, unsafe_unretained) DH *DHStatus;\n@property (nonatomic, unsafe_unretained) BIGNUM *publicBigNum;\n@end\n\n/* Static Values. */\n\n/* \n\tfishPrimeB64 is the exact value of the prime used by the original\n\tDH1080 implementation. DH->p and DH->g need to be the same value\n\tfor each user involved in a Diffie-Hellman key exchange. Therefore,\n\tto ensure compatibility with existing users, we have used the same\n\tprime value (DH->p) as well as using \"2\" for DH->g. \n\n\tDH1080Base also matches the Base64 format for encoding and decoding. \n*/\nstatic NSString *fishPrimeB64 = @\"++ECLiPSE+is+proud+to+present+latest+FiSH+release+featuring+even+more+security+for+you+++shouts+go+out+to+TMG+for+helping+to+generate+this+cool+sophie+germain+prime+number++++/C32L\";\n\n/* Static Definitions. */\n#define DHAssertNO(c)\t\tif (c == NO)\t{ NSAssert(NO, @\"DH1080 Key Exchange Failure.\"); }\n#define DHAssertYES(c)\t\tif (c)\t\t\t{ NSAssert(NO, @\"DH1080 Key Exchange Failure.\"); }\n\n/* Implementation. */\n@implementation EKBlowfishEncryptionKeyExchangeBase\n\n#pragma mark -\n\n- (id)init\n{\n    if ((self = [super init])) {\n\t\tself.DHStatus = 0;\n\n\t\tself.publicBigNum = 0;\n\n\t\t[self initializeKeyExchange];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n    [self resetStatus];\n    [self resetPublicInformation];\n}\n\n- (void)resetPublicInformation\n{\n\tif (self.publicBigNum != 0) {\n\t\tBN_free(self.publicBigNum);\n\n\t\tself.publicBigNum = 0;\n\t}\n}\n\n- (void)resetStatus\n{\n\tif (self.DHStatus != 0) {\n\t\tDH_free(self.DHStatus);\n\n\t\tself.DHStatus = 0;\n\t}\n}\n\n#pragma mark -\n\n- (void)initializeKeyExchange\n{\n\tDHAssertNO(self.DHStatus == 0);\n\n\tself.DHStatus = DH_new();\n\t\n\tDHAssertYES(self.DHStatus == 0);\n\n\tDHAssertNO(DH_get0_g(self.DHStatus) == 0);\n\tDHAssertNO(DH_get0_p(self.DHStatus) == 0);\n\t\n\tNSData *primeData = [self base64Decode:fishPrimeB64];\n\n\tBIGNUM *g = BN_new();\n\tBIGNUM *p = BN_new();\n\n\tDH_set0_pqg(self.DHStatus, p, NULL, g);\n\n\tBN_dec2bn(&g, \"2\");\n\n\tDHAssertNO([primeData length] >= 1);\n\n\tBIGNUM *ret = BN_bin2bn((unsigned char *)[primeData bytes], (int)[primeData length], p);\n\n\tDHAssertYES(ret == 0);\n\tDHAssertYES(DH_get0_g(self.DHStatus) == 0);\n\tDHAssertYES(DH_get0_p(self.DHStatus) == 0);\n\n\tint check, codes;\n\n\tcheck = DH_check(self.DHStatus, &codes);\n\n\tDHAssertNO(check == 1);\n\tDHAssertNO(codes == 0);\n\n\tint genr = DH_generate_key(self.DHStatus);\n\n\tDHAssertNO(genr == 1);\n}\n\n#pragma mark -\n\n- (void)computeKey\n{\n\tDHAssertYES(self.DHStatus == 0);\n\tDHAssertYES(DH_get0_g(self.DHStatus) == 0);\n\tDHAssertYES(DH_get0_p(self.DHStatus) == 0);\n\t\n\tDHAssertYES(self.publicBigNum == 0);\n\n\tNSInteger size = DH_size(self.DHStatus);\n\n\tDHAssertNO(size == EKBlowfishEncryptionKeyExchangeRequiredKeyLength);\n\n\tunsigned char key[EKBlowfishEncryptionKeyExchangeRequiredKeyLength];\n\n\tNSInteger num = DH_compute_key(key, self.publicBigNum, self.DHStatus);\n\n\tDHAssertNO(num == size);\n\t\n\tNSData *secretValue = [[NSData alloc] initWithBytes:key length:sizeof(key)];\n\n\tDHAssertNO([secretValue length] >= 1);\n\n\tself.secretValue = secretValue;\n}\n\n- (void)setKeyForComputation:(NSData *)publicKey\n{\n\tif (self.publicBigNum == 0) {\n\t\tself.publicBigNum = BN_new();\n\t}\n\n\tDHAssertYES(self.publicBigNum == 0);\n\n\tBIGNUM *ret = BN_bin2bn((unsigned char *)[publicKey bytes], (int)[publicKey length], self.publicBigNum);\n\n\tDHAssertYES(ret == 0);\n\tDHAssertYES(self.publicBigNum == 0);\n}\n\n#pragma mark -\n\n- (NSString *)secretStringValue\n{\n\tNSData *secretValue = [self secretValue];\n\n\tDHAssertNO(secretValue.length >= 1);\n\t\n\tunsigned char sha_md[32];\n\t\n\tSHA256((unsigned char *)[secretValue bytes], (int)[secretValue length], sha_md);\n\n\tNSData *secretHash = [[NSData alloc] initWithBytes:sha_md length:sizeof(sha_md)];\n\n\tDHAssertNO([secretHash length] >= 1);\n\n    return [self base64Encode:secretHash];\n}\n\n- (NSString *)publicKeyValue:(NSData *)publicInput\n{\n\tDHAssertNO([publicInput length] >= 1);\n\n\treturn [self base64Encode:publicInput];\n}\n\n- (NSData *)rawPublicKey\n{\n\tDHAssertYES(self.DHStatus == 0);\n\tDHAssertYES(DH_get0_g(self.DHStatus) == 0);\n\tDHAssertYES(DH_get0_p(self.DHStatus) == 0);\n\n\tNSInteger size = DH_size(self.DHStatus);\n\n\tDHAssertNO(size == EKBlowfishEncryptionKeyExchangeRequiredKeyLength);\n\n\tunsigned char key[EKBlowfishEncryptionKeyExchangeRequiredKeyLength];\n\n\tconst BIGNUM *publicKey = DH_get0_pub_key(self.DHStatus);\n\n\tBN_bn2bin(publicKey, key);\n\n\tNSData *publicInput = [[NSData alloc] initWithBytes:key length:sizeof(key)];\n\n\tDHAssertNO([publicInput length] >= 1);\n\n\treturn publicInput;\n}\n\n#pragma mark -\n\n- (NSString *)base64Encode:(NSData *)input\n{\n\tNSString *output = [XRBase64Encoding encodeData:input];\n\n\tDHAssertNO([output length] >= 1);\n\n\tBOOL equalFound = NO;\n\n\twhile (YES) {\n\t\tNSRange equalRange = [output rangeOfString:@\"=\"];\n\n\t\tif (equalRange.location == NSNotFound) {\n\t\t\tif (equalFound == NO) {\n\t\t\t\toutput = [output stringByAppendingString:@\"A\"];\n\t\t\t}\n\n\t\t\tbreak;\n\t\t} else {\n\t\t\tequalFound = YES;\n\n\t\t\toutput = [output substringWithRange:NSMakeRange(0, ([output length] - 1))];\n\t\t}\n\t}\n\n\treturn output;\n}\n\n- (NSData *)base64Decode:(NSString *)input\n{\n\tNSInteger inputLength = [input length];\n\n\tDHAssertNO([input length] >= 1);\n\n\tNSString *ecv = [input substringFromIndex:(inputLength - 1)];\n\n\tif ((inputLength % 4) == 1 && [ecv isEqualToString:@\"A\"]) {\n\t\tinput = [input substringToIndex:(inputLength - 1)];\n\t}\n\n\twhile ((([input length] % 4) == 0) == NO) {\n\t\tinput = [input stringByAppendingString:@\"=\"];\n\t}\n\t\n\treturn [XRBase64Encoding decodeData:input];\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/NSDataHelper.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <Foundation/Foundation.h>\n\n@interface NSMutableData (BlowfishEncryptionDatHelper)\n- (void)removeBadCharacters;\n@end\n\n@interface NSString (BlowfishEncryptionStringHelper)\n/* If the data object does not fit in the block size, then NULL \n characters are set to fill in the half-sized block */\n- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding paddedByBytes:(NSInteger)bytePadding;\n\n/* If the data object does not fit in the block size, then the\n tail is truncated and the number of bytes lost is returned. */\n- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding fitToPadding:(NSInteger)bytePadding trimmedCharacters:(NSInteger *)bytesRemoved;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/NSDataHelper.m",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSDataHelper.h\"\n\n@implementation NSMutableData (BlowfishEncryptionDataHelper)\n\n- (void)removeBadCharacters\n{\n\t[self replaceAllOccurrencesOfData:[NSData dataWithBytes:\"\\x0D\" length:1] withBytes:NULL length:0]; // Line break\n\t[self replaceAllOccurrencesOfData:[NSData dataWithBytes:\"\\x0A\" length:1] withBytes:NULL length:0]; // Line feed\n\t[self replaceAllOccurrencesOfData:[NSData dataWithBytes:\"\\x00\" length:1] withBytes:NULL length:0]; // NULL character\n}\n\n- (void)replaceAllOccurrencesOfData:(NSData *)needle withBytes:(const void *)replacementBytes length:(NSUInteger)replacementLength\n{\n\tNSUInteger start = 0;\n\t\n\twhile (1 == 1) {\n\t\tif (start >= [self length]) {\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\tNSRange r = [self rangeOfData:needle options:0 range:NSMakeRange(start, ([self length] - start))];\n\n\t\tif (r.location == NSNotFound) {\n\t\t\tbreak;\n\t\t}\n\t\t\n\t\t[self replaceBytesInRange:r withBytes:replacementBytes length:replacementLength];;\n\t\t\n\t\tstart = (r.location + replacementLength + 1);\n\t}\n}\n\n@end\n\n@implementation NSString (BlowfishEncryptionStringHelper)\n\n- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding fitToPadding:(NSInteger)bytePadding trimmedCharacters:(NSInteger *)bytesRemoved\n{\n\tif (bytePadding <= 0) {\n\t\treturn nil;\n\t}\n\n\tNSData *dataObject = [self dataUsingEncoding:encoding allowLossyConversion:NO];\n\n\tNSUInteger dataObjectLength = [dataObject length];\n\tNSUInteger dataObjectLengthRemainder = (dataObjectLength % bytePadding);\n\n\tif (dataObjectLengthRemainder > 0) {\n\t\tdataObjectLength -= dataObjectLengthRemainder;\n\n\t\tif ( bytesRemoved) {\n\t\t\t*bytesRemoved = dataObjectLengthRemainder;\n\t\t}\n\n\t\treturn [NSData dataWithBytes:[dataObject bytes] length:dataObjectLength];\n\t} else {\n\t\tif ( bytesRemoved) {\n\t\t\t*bytesRemoved = 0;\n\t\t}\n\n\t\treturn dataObject;\n\t}\n}\n\n- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding paddedByBytes:(NSInteger)bytePadding\n{\n\tif (bytePadding <= 0) {\n\t\treturn nil;\n\t}\n\n\tNSData *dataObject = [self dataUsingEncoding:encoding allowLossyConversion:NO];\n\n\tNSUInteger dataObjectLength = [dataObject length];\n\tNSUInteger dataObjectLengthRemainder = (dataObjectLength % bytePadding);\n\n\tif (dataObjectLengthRemainder > 0) {\n\t\tNSMutableData *dataObjectMutable = [dataObject mutableCopy];\n\n\t\t[dataObjectMutable increaseLengthBy:(bytePadding - dataObjectLengthRemainder)];\n\n\t\treturn [dataObjectMutable copy];\n\t} else {\n\t\treturn dataObject;\n\t}\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/TPIBlowfishEncryption.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\n#import \"BlowfishEncryption.h\"\n#import \"BlowfishEncryptionKeyExchange.h\"\n\n@interface TPIBlowfishEncryption : NSObject <THOPluginProtocol>\n+ (BOOL)isPluginEnabled;\n\n+ (NSString *)encryptionKeyForChannel:(IRCChannel *)channel;\n+ (void)setEncryptionKey:(NSString *)encryptionKey forChannel:(IRCChannel *)channel;\n\n+ (EKBlowfishEncryptionModeOfOperation)encryptionModeOfOperationForChannel:(IRCChannel *)channel;\n+ (void)setEncryptionModeOfOperation:(EKBlowfishEncryptionModeOfOperation)modeOfOperation forChannel:(IRCChannel *)channel;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/TPIBlowfishEncryption.m",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPIBlowfishEncryption.h\"\n\n#import \"TVCLogControllerPrivate.h\"\n\n#define TXExchangeRequestPrefix\t\t\t\t@\"DH1080_INIT \"\n#define TXExchangeResponsePrefix\t\t\t@\"DH1080_FINISH \"\n\n#define TXExchangeReuqestTimeoutDelay\t\t10\n\n@interface TPIBlowfishEncryption ()\n@property (nonatomic, strong) IBOutlet NSView *preferencePaneView;\n\n/* \n\t  key format:\tSTRING(\"<channel UUID> –> <remote nickname>\")\n\tvalue format:\t ARRAY(\"<pointer to EKBlowfishEncryptionKeyExchange>\", \"<pointer to IRCChannel>\")\n \n\t-keyExchangeDictionaryKey: can be used to generate key.\n*/\n@property (nonatomic, strong) NSMutableDictionary *keyExchangeRequests;\n\n- (IBAction)preferencesChanged:(id)sender;\n@end\n\n@implementation TPIBlowfishEncryption\n\n#pragma mark -\n#pragma mark Plugin Structure\n\n+ (BOOL)isPluginEnabled\n{\n\tstatic BOOL _servicesEnabledChecked = NO;\n\tstatic BOOL _servicesEnabled = NO;\n\n\tif (_servicesEnabledChecked == NO) {\n\t\t_servicesEnabledChecked = YES;\n\n\t\t_servicesEnabled = [RZUserDefaults() boolForKey:@\"Blowfish Encryption Extension -> Enable Service\"];\n\t}\n\n\treturn _servicesEnabled;\n}\n\n- (BOOL)isPluginEnabled\n{\n\treturn [TPIBlowfishEncryption isPluginEnabled];\n}\n\n- (void)pluginLoadedIntoMemory\n{\n\t[self performBlockOnMainThread:^{\n\t\t[TPIBundleFromClass() loadNibNamed:@\"TPIBlowfishEncryption\" owner:self topLevelObjects:nil];\n\t}];\n\n\tif ([self isPluginEnabled]) {\n\t\tself.keyExchangeRequests = [NSMutableDictionary dictionary];\n\t}\n}\n\n- (void)pluginWillBeUnloadedFromMemory\n{\n\tif ([self isPluginEnabled]) {\n\t\tself.keyExchangeRequests = nil;\n\n\t\t[NSObject cancelPreviousPerformRequestsWithTarget:self];\n\t}\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn TPILocalizedString(@\"BasicLanguage[8o8-tj]\");\n}\n\n- (NSView *)pluginPreferencesPaneView\n{\n\treturn self.preferencePaneView;\n}\n\n- (void)preferencesChanged:(id)sender\n{\n\t[TDCAlert alertSheetWithWindow:[NSApp keyWindow]\n\t\t\t\t\t\t\t  body:TPILocalizedString(@\"BasicLanguage[ei0-4a]\")\n\t\t\t\t\t\t\t title:TPILocalizedString(@\"BasicLanguage[0h8-o3]\")\n\t\t\t\t\t defaultButton:TPILocalizedString(@\"BasicLanguage[4qo-gl]\")\n\t\t\t\t   alternateButton:nil\n\t\t\t\t\t   otherButton:nil];\n}\n\n- (void)didReceiveServerInput:(THOPluginDidReceiveServerInputConcreteObject *)inputObject onClient:(IRCClient *)client\n{\n\tif ([self isPluginEnabled] == NO) {\n\t\treturn; // Cancel operation...\n\t}\n\n\t[self performBlockOnMainThread:^{\n\t\tNSString *person = [inputObject senderNickname];\n\n\t\tNSString *message = [inputObject messageSequence];\n\n\t\tif ([message hasPrefix:@\"+\"]) {\n\t\t\tmessage = [message substringFromIndex:1];\n\t\t}\n\n\t\tBOOL isRequest = [message hasPrefix:TXExchangeRequestPrefix];\n\t\tBOOL isResponse = [message hasPrefix:TXExchangeResponsePrefix];\n\n\t\tif (isRequest || isResponse) {\n\t\t\tif (isRequest) {\n\t\t\t\t/* A request may create a query so it must be invoked on\n\t\t\t\t the main thread. Creating a channel requires access to\n\t\t\t\t WebKit and WebKit will throw an exception because they\n\t\t\t\t hate running on anything else. */\n\n\t\t\t\t[self keyExchangeRequestReceived:message on:client from:person];\n\t\t\t} else {\n\t\t\t\t/* We do not want to create the channel if it is a response.\n\t\t\t\t If the user closed the query, then allow old request to expire.\n\t\t\t\t This is done so that the IRCChannel pointer part of our request\n\t\t\t\t dictionary will remain same instead of creating a new one and\n\t\t\t\t the old pointing to nothing. */\n\t\t\t\t\n\t\t\t\tIRCChannel *channel = [client findChannel:person];\n\n\t\t\t\tif (channel) {\n\t\t\t\t\tNSString *requestKey = [self keyExchangeDictionaryKey:channel];\n\n\t\t\t\t\tif (requestKey) {\n\t\t\t\t\t\t[self keyExchangeResponseReceived:message on:client from:requestKey];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}];\n}\n\n- (void)userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t  commandString:(NSString *)commandString\n\t\t\t\t\t\t  messageString:(NSString *)messageString\n{\n\t[self performBlockOnMainThread:^{\n\t\tif ([self isPluginEnabled] == NO) {\n\t\t\t[TDCAlert alertWithMessage:TPILocalizedString(@\"BasicLanguage[87t-ge]\", [commandString lowercaseString])\n\t\t\t\t\t\t\t\t title:TPILocalizedString(@\"BasicLanguage[qb6-7a]\")\n\t\t\t\t\t\t defaultButton:TPILocalizedString(@\"BasicLanguage[oyj-zy]\")\n\t\t\t\t\t   alternateButton:nil\n\t\t\t\t\t\tsuppressionKey:nil\n\t\t\t\t\t   suppressionText:nil];\n\n\t\t\treturn; // Cancel operation...\n\t\t}\n\n\t\tIRCChannel *c = [mainWindow() selectedChannelOn:client];\n\t\t\n\t\tif ([c isChannel] || [c isPrivateMessage]) {\n\t\t\tNSString *_messageString = [messageString trimAndGetFirstToken];\n\n\t\t\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:c];\n\t\t\t\n\t\t\tif ([commandString isEqualToString:@\"SETKEY\"]) {\n\t\t\t\tif (NSObjectIsEmpty(_messageString)) {\n\t\t\t\t\t[TPIBlowfishEncryption setEncryptionKey:nil forChannel:c];\n\t\t\t\t\t\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[ime-kt]\") inChannel:c];\n\t\t\t\t} else {\n\t\t\t\t\tif (NSObjectIsNotEmpty(encryptionKey)) {\n\t\t\t\t\t\tif ([encryptionKey isEqualToString:_messageString] == NO) {\n\t\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[9k1-jc]\") inChannel:c];\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ([c isPrivateMessage]) {\n\t\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[rhu-sw]\") inChannel:c];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[1dv-qi]\") inChannel:c];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ([_messageString length] > 56) {\n\t\t\t\t\t\t _messageString = [_messageString substringToIndex:56];\n\n\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[fmt-65]\") inChannel:c];\n\t\t\t\t\t}\n\n\t\t\t\t\t[TPIBlowfishEncryption setEncryptionKey:_messageString forChannel:c];\n\t\t\t\t}\n\t\t\t} else if ([commandString isEqualToString:@\"DELKEY\"]) {\n\t\t\t\t[TPIBlowfishEncryption setEncryptionKey:nil forChannel:c];\n\t\t\t\t\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[ime-kt]\") inChannel:c];\n\t\t\t} else if ([commandString isEqualToString:@\"KEY\"]) {\n\t\t\t\tif (NSObjectIsNotEmpty(encryptionKey)) {\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[st5-x8]\", encryptionKey) inChannel:c];\n\t\t\t\t} else {\t\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[sd4-2b]\") inChannel:c];\n\t\t\t\t}\n\t\t\t} else if ([commandString isEqualToString:@\"SETKEYMODE\"]) {\n\t\t\t\tif ([_messageString isEqualIgnoringCase:@\"CBC\"]) {\n\t\t\t\t\t[TPIBlowfishEncryption setEncryptionModeOfOperation:EKBlowfishEncryptionCBCModeOfOperation forChannel:c];\n\t\t\t\t\t\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[vph-s9]\") inChannel:c];\n\t\t\t\t} else {\n\t\t\t\t\t[TPIBlowfishEncryption setEncryptionModeOfOperation:EKBlowfishEncryptionECBModeOfOperation forChannel:c];\n\t\t\t\t\t\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[5e8-56]\") inChannel:c];\n\t\t\t\t}\n\t\t\t} else if ([commandString isEqualToString:@\"KEYX\"]) {\n\t\t\t\tif ([c isPrivateMessage] == NO) {\n\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[2kj-i5]\") inChannel:c];\n\t\t\t\t} else {\n\t\t\t\t\tif ([self keyExchangeRequestExists:c]) {\n\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[wi6-cy]\", [c name]) inChannel:c];\n\t\t\t\t\t} else if (NSObjectIsNotEmpty(encryptionKey)) {\n\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[2oq-wt]\", [c name]) inChannel:c];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tEKBlowfishEncryptionKeyExchange *keyRequest = [EKBlowfishEncryptionKeyExchange new];\n\n\t\t\t\t\t\tNSString *publicKey = [keyRequest generatePublicKey];\n\n\t\t\t\t\t\tif (NSObjectIsEmpty(publicKey)) {\n\t\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[wo2-d2]\") inChannel:c];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tNSString *requestKey = [self keyExchangeDictionaryKey:c];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tNSString *requestMsg = nil;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tif ([_messageString isEqualIgnoringCase:@\"nocbc\"]) {\n\t\t\t\t\t\t\t\trequestMsg = [NSString stringWithFormat:@\"%@%@\", TXExchangeRequestPrefix, publicKey];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\trequestMsg = [NSString stringWithFormat:@\"%@%@ CBC\", TXExchangeRequestPrefix, publicKey];\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t[[self keyExchangeRequests] setObject:@[keyRequest, c] forKey:requestKey];\n\n\t\t\t\t\t\t\t[client send:@\"NOTICE\", [c name], requestMsg, nil];\n\n\t\t\t\t\t\t\t[self keyExchangeSetupTimeoutTimer:requestKey];\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[ezp-nq]\", [c name]) inChannel:c];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tencryptionKey = nil;\n\t\t}\n\t}];\n}\n\n- (NSArray *)subscribedUserInputCommands\n{\n\treturn @[@\"setkey\", @\"delkey\", @\"key\", @\"keyx\", @\"setkeymode\"];\n}\n\n- (NSArray *)subscribedServerInputCommands\n{\n\treturn @[@\"notice\"];\n}\n\n- (NSArray *)pluginOutputSuppressionRules\n{\n    /* Rule 1 */\n    THOPluginOutputSuppressionRule *noticeRule1 = [THOPluginOutputSuppressionRule new];\n    \n    [noticeRule1 setRestrictConsole:YES];\n    [noticeRule1 setRestrictChannel:YES];\n    [noticeRule1 setRestrictPrivateMessage:YES];\n\n    [noticeRule1 setMatch:[@\"^\" stringByAppendingString:TXExchangeRequestPrefix]];\n    \n    /* Rule 2 */\n    THOPluginOutputSuppressionRule *noticeRule2 = [THOPluginOutputSuppressionRule new];\n    \n    [noticeRule2 setRestrictConsole:YES];\n    [noticeRule2 setRestrictChannel:YES];\n    [noticeRule2 setRestrictPrivateMessage:YES];\n    \n    [noticeRule2 setMatch:[@\"^\" stringByAppendingString:TXExchangeResponsePrefix]];\n    \n    \n    return @[noticeRule1, noticeRule2];\n}\n\n#pragma mark -\n#pragma mark Options\n\n+ (void)setEncryptionKey:(NSString *)encryptionKey forChannel:(IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSString *serviceName = [NSString stringWithFormat:@\"textual.cblowfish.%@\", [channel uniqueIdentifier]];\n\n\t\tif (encryptionKey == nil) {\n\t\t\t[XRKeychain deleteKeychainItem:@\"Textual (Blowfish Encryption)\"\n\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t   serviceName:serviceName];\n\n\t\t\t[[channel viewController] setEncrypted:NO];\n\t\t} else {\n\t\t\t[XRKeychain modifyOrAddKeychainItem:@\"Textual (Blowfish Encryption)\"\n\t\t\t\t\t\t\t\t   withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\tforUsername:nil\n\t\t\t\t\t\t\t\twithNewPassword:encryptionKey\n\t\t\t\t\t\t\t\t\tserviceName:serviceName];\n\n\t\t\t[[channel viewController] setEncrypted:YES];\n\t\t}\n\t}\n}\n\n+ (NSString *)encryptionKeyForChannel:(IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSString *serviceName = [NSString stringWithFormat:@\"textual.cblowfish.%@\", [channel uniqueIdentifier]];\n\n\t\treturn [XRKeychain getPasswordFromKeychainItem:@\"Textual (Blowfish Encryption)\"\n\t\t\t\t\t\t\t\t\t\t  withItemKind:@\"application password\"\n\t\t\t\t\t\t\t\t\t\t   forUsername:nil\n\t\t\t\t\t\t\t\t\t\t   serviceName:serviceName];\n\t} else {\n\t\treturn nil;\n\t}\n}\n\n+ (void)setEncryptionModeOfOperation:(EKBlowfishEncryptionModeOfOperation)modeOfOperation forChannel:(IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSString *defaultsKey = [NSString stringWithFormat:@\"Private Extension Store -> Blowfish Encryption Extension -> Encryption Mode of Operation -> %@\", [channel uniqueIdentifier]];\n\n\t\tif (modeOfOperation == EKBlowfishEncryptionDefaultModeOfOperation) {\n\t\t\t[RZUserDefaults() removeObjectForKey:defaultsKey];\n\t\t} else {\n\t\t\t[RZUserDefaults() setInteger:modeOfOperation forKey:defaultsKey];\n\t\t}\n\t}\n}\n\n+ (EKBlowfishEncryptionModeOfOperation)encryptionModeOfOperationForChannel:(IRCChannel *)channel\n{\n\tif (channel) {\n\t\tNSString *defaultsKey = [NSString stringWithFormat:@\"Private Extension Store -> Blowfish Encryption Extension -> Encryption Mode of Operation -> %@\", [channel uniqueIdentifier]];\n\n\t\tid defaultsValue = [RZUserDefaults() objectForKey:defaultsKey];\n\n\t\tif (defaultsValue) {\n\t\t\treturn (EKBlowfishEncryptionModeOfOperation)[defaultsValue integerValue];\n\t\t} else {\n\t\t\treturn EKBlowfishEncryptionDefaultModeOfOperation;\n\t\t}\n\t} else {\n\t\treturn EKBlowfishEncryptionNoneModeOfOperation;\n\t}\n}\n\n#pragma mark -\n#pragma mark Key Exchange\n\n- (void)keyExchangeRequestReceived:(NSString *)requestDataRaw on:(IRCClient *)client from:(NSString *)requestSender\n{\n\tIRCChannel *channel = [client findChannelOrCreate:requestSender isPrivateMessage:YES];\n\t\n\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:channel];\n\t\n    if (NSObjectIsNotEmpty(encryptionKey)) {\n        [client printDebugInformation:TPILocalizedString(@\"BasicLanguage[9eq-sn]\", [channel name]) inChannel:channel];\n\n        return;\n    }\n\t\n\tEKBlowfishEncryptionModeOfOperation mode = EKBlowfishEncryptionDefaultModeOfOperation;\n\n\tNSString *requestData = nil;\n\t\n\tif ([requestDataRaw length] > [TXExchangeRequestPrefix length]) {\n\t\trequestData = [requestDataRaw substringFromIndex:[TXExchangeRequestPrefix length]];\n\t\t\n\t\tNSArray *parts = [requestData split:NSStringWhitespacePlaceholder];\n\t\t\n\t\trequestData = parts[0];\n\t\t\n\t\tif ([parts count] > 1 && [parts[1] isEqualToString:@\"CBC\"]) {\n\t\t\tmode = EKBlowfishEncryptionCBCModeOfOperation;\n\t\t}\n\t} else {\n\t\trequestData =  requestDataRaw;\n\t}\n\n\t//LogToConsoleDebug(\"Key Exchange Request Received:\");\n\t//LogToConsoleDebug(\"\tClient: %@\", client);\n\t//LogToConsoleDebug(\"\tChannel: %@\", channel);\n\t//LogToConsoleDebug(\"\tMessage: %@\", requestData);\n\t\n\tif ([requestData length] <= 0) {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[lo0-tu]\") inChannel:channel];\n\t} else {\n\t\tif ([self keyExchangeRequestExists:channel]) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[8nu-ow]\", [channel name]) inChannel:channel];\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[wi6-cy]\", [channel name]) inChannel:channel];\n\t\t} else {\n\t\t\tEKBlowfishEncryptionKeyExchange *keyRequest = [EKBlowfishEncryptionKeyExchange new];\n\n\t\t\t/* Process secret from the Receiver. */\n\t\t\tNSString *theSecret = [keyRequest secretKeyFromPublicKey:requestData];\n\n\t\t\tif (NSObjectIsEmpty(theSecret)) {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[tr4-jd]\") inChannel:channel];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Generate our own public key. If everything has gone correctly up to here,\n\t\t\t then when the user that sent the request computes our public key, we both\n\t\t\t should have the same secret. */\n\t\t\tNSString *publicKey = [keyRequest generatePublicKey];\n\n\t\t\tif (NSObjectIsEmpty(publicKey)) {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[wo2-d2]\") inChannel:channel];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t//LogToConsoleDebug(\"\tShared Secret: %@\", theSecret);\n\n\t\t\t[TPIBlowfishEncryption setEncryptionKey:theSecret forChannel:channel];\n\t\t\t[TPIBlowfishEncryption setEncryptionModeOfOperation:mode forChannel:channel];\n\n\t\t\t/* Finish up. */\n\t\t\tNSString *requestMsg = [TXExchangeResponsePrefix stringByAppendingString:publicKey];\n\t\t\t\n\t\t\tif (mode == EKBlowfishEncryptionCBCModeOfOperation) {\n\t\t\t\trequestMsg = [requestMsg stringByAppendingString:@\" CBC\"];\n\t\t\t}\n\n\t\t\t[client send:@\"NOTICE\", [channel name], requestMsg, nil];\n\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[8nu-ow]\", [channel name]) inChannel:channel];\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[184-19]\", [channel name]) inChannel:channel];\n\t\t\t\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[jmi-xp]\", [channel name]) inChannel:channel];\n\t\t\t\n\t\t\tif (mode == EKBlowfishEncryptionDefaultModeOfOperation || mode == EKBlowfishEncryptionECBModeOfOperation) {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[5p8-18]\") inChannel:channel];\n\t\t\t} else {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[3px-4w]\") inChannel:channel];\n\t\t\t}\n\t\t\t\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[cdb-6z]\", [channel name]) inChannel:channel];\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[7sz-gy]\", [channel name]) inChannel:channel];\n\t\t}\n\t}\n}\n\n- (void)keyExchangeResponseReceived:(NSString *)responseDataRaw on:(IRCClient *)client from:(NSString *)responseKey\n{\n\tNSArray *exchangeData = [self keyExchangeInformation:responseKey];\n\n\tif (exchangeData) {\n\t\tNSString *responseData = nil;\n\t\t\n\t\tEKBlowfishEncryptionModeOfOperation mode = EKBlowfishEncryptionDefaultModeOfOperation;\n\n\t\tif ([responseDataRaw length] > [TXExchangeResponsePrefix length]) {\n\t\t\tresponseData = [responseDataRaw substringFromIndex:[TXExchangeResponsePrefix length]];\n\t\t\t\n\t\t\tNSArray *parts = [responseData split:NSStringWhitespacePlaceholder];\n\t\t\t\n\t\t\tresponseData = parts[0];\n\t\t\t\n\t\t\tif ([parts count] > 1 && [parts[1] isEqualToString:@\"CBC\"]) {\n\t\t\t\tmode = EKBlowfishEncryptionCBCModeOfOperation;\n\t\t\t}\n\t\t} else {\n\t\t\tresponseData =  responseDataRaw;\n\t\t}\n\t\t\n\t\t//LogToConsoleDebug(\"Key Exchange Response Received:\");\n\t\t//LogToConsoleDebug(\"\tResponse Key: %@\", responseKey);\n\t\t//LogToConsoleDebug(\"\tResponse Info: %@\", exchangeData);\n\t\t//LogToConsoleDebug(\"\tMessage: %@\", responseData);\n\n\t\tEKBlowfishEncryptionKeyExchange *request = exchangeData[0];\n\t\t\n\t\tIRCChannel *channel = exchangeData[1];\n\t\t\n\t\tif ([responseData length] <= 0) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[lo0-tu]\") inChannel:channel];\n\t\t} else {\n\t\t\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:channel];\n\t\t\t\n\t\t\tif (NSObjectIsNotEmpty(encryptionKey)) {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[9eq-sn]\", [channel name]) inChannel:channel];\n\t\t\t\t\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[eqo-bn]\", [channel name]) inChannel:channel];\n\t\t\t\n\t\t\t/* Compute the public key received against our own. Our original public key\n\t\t\t was sent to the user which has responded by computing their own against\n\t\t\t that. Now we compute the key received to obtain the shared secret. What?… */\n\t\t\tNSString *theSecret = [request secretKeyFromPublicKey:responseData];\n\t\t\t\n\t\t\tif (NSObjectIsEmpty(theSecret)) {\n\t\t\t\treturn [client printDebugInformation:TPILocalizedString(@\"BasicLanguage[tr4-jd]\") inChannel:channel];\n\t\t\t}\n\t\t\t\n\t\t\t//LogToConsoleDebug(\"\tShared Secret: %@\", theSecret);\n\n\t\t\t[TPIBlowfishEncryption setEncryptionKey:theSecret forChannel:channel];\n\t\t\t[TPIBlowfishEncryption setEncryptionModeOfOperation:mode forChannel:channel];\n\t\t\t\n\t\t\t/* Finish up. */\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[jmi-xp]\", [channel name]) inChannel:channel];\n\t\t\t\n\t\t\tif (mode == EKBlowfishEncryptionDefaultModeOfOperation || mode == EKBlowfishEncryptionECBModeOfOperation) {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[5p8-18]\") inChannel:channel];\n\t\t\t} else {\n\t\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[3px-4w]\") inChannel:channel];\n\t\t\t}\n\t\t\t\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[cdb-6z]\", [channel name]) inChannel:channel];\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[7sz-gy]\", [channel name]) inChannel:channel];\n\t\t}\n\t\t\n\t\t[[self keyExchangeRequests] removeObjectForKey:responseKey];\n\t}\n}\n\n#pragma mark -\n#pragma mark Key Exchange Timer.\n\n- (void)keyExchangeSetupTimeoutTimer:(NSString *)requestKey\n{\n\t[self performSelector:@selector(keyExchangeTimedOut:) withObject:requestKey afterDelay:TXExchangeReuqestTimeoutDelay];\n}\n\n- (void)keyExchangeTimedOut:(NSString *)requestKey\n{\n\tNSArray *requestData = [self keyExchangeInformation:requestKey];\n\n\tif (NSObjectIsNotEmpty(requestKey)) {\n\t\tIRCChannel *channel = requestData[1];\n\t\t\n\t\t[[channel associatedClient] printDebugInformation:TPILocalizedString(@\"BasicLanguage[c3y-2b]\", [channel name]) inChannel:channel];\n\n\t\t[[self keyExchangeRequests] removeObjectForKey:requestKey];\n\t}\n}\n\n#pragma mark -\n#pragma mark Key Exchange Information.\n\n- (BOOL)keyExchangeRequestExists:(IRCChannel *)channel\n{\n\tNSString *requestKey = [self keyExchangeDictionaryKey:channel];\n\n\treturn NSObjectIsNotEmpty([self keyExchangeInformation:requestKey]);\n}\n\n- (NSArray *)keyExchangeInformation:(NSString *)requestKey\n{\n\tNSArray *requestData = [[self keyExchangeRequests] arrayForKey:requestKey];\n\n\tif (NSObjectIsNotEmpty(requestData)) {\n\t\tid request = requestData[0];\n\t\tid channel = requestData[1];\n\n\t\tif ([requestData count] == 2\t\t\t\t\t\t\t\t\t\t\t&& \t// Array count is equal to 2.\n\t\t\trequest != nil\t\t\t\t\t\t\t\t\t\t\t\t\t\t&& \t// Pointer are not empty.\n\t\t\tchannel != nil\t\t\t\t\t\t\t\t\t\t\t\t\t\t&& \t// Pointer are not empty.\n\t\t\t[request isKindOfClass:[EKBlowfishEncryptionKeyExchange class]]\t\t&& \t// Type of class is correct.\n\t\t\t[channel isKindOfClass:[IRCChannel class]]) {\t\t\t\t\t\t\t// Type of class is correct.\n\n\t\t\treturn requestData;\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (NSString *)keyExchangeDictionaryKey:(IRCChannel *)channel\n{\n\tif (channel == nil || [channel isPrivateMessage] == NO) {\n\t\treturn nil;\n\t}\n\t\n\treturn [NSString stringWithFormat:@\"%@ –> %@\", [channel uniqueIdentifier], [channel name]];\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/TPIBlowfishEncryptionSwizzledClasses.h",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\n@interface TPCPreferencesUserDefaults (TPCPreferencesUserDefaultsSwizzled)\n@end\n\n@interface IRCClient (IRCClientSwizzled)\n@end\n\n@interface IRCChannel (IRCChannelSwizzled)\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Classes/TPIBlowfishEncryptionSwizzledClasses.m",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPIBlowfishEncryption.h\"\n#import \"TPIBlowfishEncryptionSwizzledClasses.h\"\n\n@implementation IRCClient (IRCClientSwizzled)\n\n+ (void)load\n{\n\tXRExchangeInstanceMethod(@\"IRCClient\", @\"encryptionAllowedForTarget:\", @\"__tpi_encryptionAllowedForTarget:\");\n\tXRExchangeInstanceMethod(@\"IRCClient\", @\"decryptMessage:from:target:decodingCallback:\", @\"__tpi_decryptMessage:from:target:decodingCallback:\");\n\tXRExchangeInstanceMethod(@\"IRCClient\", @\"encryptMessage:directedAt:encodingCallback:injectionCallback:\", @\"__tpi_encryptMessage:directedAt:encodingCallback:injectionCallback:\");\n\tXRExchangeInstanceMethod(@\"IRCClient\", @\"lengthOfEncryptedMessageDirectedAt:thatFitsWithinBounds:\", @\"__tpi_lengthOfEncryptedMessageDirectedAt:thatFitsWithinBounds:\");\n}\n\n- (BOOL)__tpi_encryptionAllowedForTarget:(NSString *)target\n{\n\tif ([TPIBlowfishEncryption isPluginEnabled] == NO) {\n\t\treturn [self __tpi_encryptionAllowedForTarget:target];\n\t}\n\n\treturn NO;\n}\n\n- (NSInteger)__tpi_lengthOfEncryptedMessageDirectedAt:(NSString *)messageTo thatFitsWithinBounds:(NSInteger)maximumLength\n{\n\tif ([TPIBlowfishEncryption isPluginEnabled] == NO) {\n\t\treturn [self __tpi_lengthOfEncryptedMessageDirectedAt:messageTo thatFitsWithinBounds:maximumLength];\n\t}\n\n\tIRCChannel *targetChannel = [self findChannel:messageTo];\n\n\tif (targetChannel == nil) {\n\t\treturn 0;\n\t}\n\n\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:targetChannel];\n\n\tif (encryptionKey == nil) {\n\t\treturn 0;\n\t}\n\n\tNSInteger lastEstimatedSize = 0;\n\n\tfor (NSInteger i = maximumLength; i >= 0; i--) {\n\t\tNSInteger sizeForLength = [EKBlowfishEncryption estimatedLengthOfEncodedDataOfLength:i];\n\n\t\tif (sizeForLength < maximumLength) {\n\t\t\tbreak;\n\t\t} else {\n\t\t\tlastEstimatedSize = i;\n\t\t}\n\t}\n\n\treturn lastEstimatedSize;\n}\n\n- (void)__tpi_encryptMessage:(NSString *)messageBody directedAt:(NSString *)messageTo encodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)encodingCallback injectionCallback:(TLOEncryptionManagerInjectCallbackBlock)injectionCallback\n{\n#define _callback(_encodedString_, _wasEncrypted_) \t\\\n\tif (encodingCallback) { \t\\\n\t\tencodingCallback(messageBody, _wasEncrypted_); \t\\\n\t} \t\\\n\tif (injectionCallback) { \t\\\n\t\tinjectionCallback(_encodedString_); \t\\\n\t} \t\\\n\n\tif ([TPIBlowfishEncryption isPluginEnabled] == NO) {\n\t\t[self __tpi_encryptMessage:messageBody directedAt:messageTo encodingCallback:encodingCallback injectionCallback:injectionCallback];\n\n\t\treturn;\n\t}\n\n\tIRCChannel *targetChannel = [self findChannel:messageTo];\n\n\tif (targetChannel == nil) {\n\t\t_callback(messageBody, NO);\n\n\t\treturn;\n\t}\n\n\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:targetChannel];\n\n\tif (encryptionKey == nil) {\n\t\t_callback(messageBody, NO);\n\n\t\treturn;\n\t}\n\n\tEKBlowfishEncryptionModeOfOperation decodeMode = [TPIBlowfishEncryption encryptionModeOfOperationForChannel:targetChannel];\n\n\tNSString *encodedString = [EKBlowfishEncryption encodeData:messageBody key:encryptionKey mode:decodeMode encoding:NSUTF8StringEncoding];\n\n\tif ([encodedString length] < 5) {\n\t\t[self printDebugInformation:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[1ve-yc]\") inChannel:targetChannel];\n\n\t\treturn;\n\t}\n\n\t_callback(encodedString, YES);\n\n#undef _callback\n}\n\n- (void)__tpi_decryptMessage:(NSString *)messageBody from:(NSString *)messageFrom target:(NSString *)target decodingCallback:(TLOEncryptionManagerEncodingDecodingCallbackBlock)decodingCallback\n{\n#define _callback(_decodedString_, _wasEncrypted_) \t\\\n\tif (decodingCallback) { \t\\\n\t\tdecodingCallback(_decodedString_, _wasEncrypted_); \t\\\n\t}\n\n\tif ([TPIBlowfishEncryption isPluginEnabled] == NO) {\n\t\t[self __tpi_decryptMessage:messageBody from:messageFrom target:target decodingCallback:decodingCallback];\n\n\t\treturn;\n\t}\n\n\tif ([messageBody hasPrefix:@\"+OK \"] == NO &&\n\t\t[messageBody hasPrefix:@\"mcps\"] == NO)\n\t{\n\t\t_callback(messageBody, NO);\n\n\t\treturn;\n\t}\n\n\tIRCChannel *targetChannel = nil;\n\n\tif ([self stringIsChannelName:target]) {\n\t\ttargetChannel = [self findChannel:target];\n\t} else {\n\t\ttargetChannel = [self findChannel:messageFrom];\n\t}\n\n\tif (targetChannel == nil) {\n\t\t_callback(messageBody, NO);\n\n\t\treturn;\n\t}\n\n\tNSString *encryptionKey = [TPIBlowfishEncryption encryptionKeyForChannel:targetChannel];\n\n\tif (encryptionKey == nil) {\n\t\t_callback(messageBody, NO);\n\n\t\treturn;\n\t}\n\n\tNSInteger lostBytes = 0;\n\n\tEKBlowfishEncryptionModeOfOperation decodeMode = [TPIBlowfishEncryption encryptionModeOfOperationForChannel:targetChannel];\n\n\tNSString *decodedString = [EKBlowfishEncryption decodeData:messageBody key:encryptionKey mode:decodeMode encoding:NSUTF8StringEncoding lostBytes:&lostBytes];\n\n\tif (decodedString == nil) {\n\t\t[self printDebugInformation:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[np3-3g]\") inChannel:targetChannel];\n\n\t\treturn;\n\t}\n\n\tif (lostBytes > 0) {\n\t\t[self printDebugInformation:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[4mm-6d]\", lostBytes) inChannel:targetChannel];\n\n\t\t/* Do not return for this. This is not a fatal error. */\n\t}\n\n\t_callback(decodedString, YES);\n\n#undef _callback\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCChannel (IRCChannelSwizzled)\n\n+ (void)load\n{\n\tXRExchangeInstanceMethod(@\"IRCChannel\", @\"prepareForApplicationTermination\", @\"__tpi_prepareForApplicationTermination\");\n\tXRExchangeInstanceMethod(@\"IRCChannel\", @\"prepareForPermanentDestruction\", @\"__tpi_prepareForPermanentDestruction\");\n}\n\n- (void)__tpi_destroyEncryptionKeychain\n{\n\tif ([TPIBlowfishEncryption isPluginEnabled] == NO) {\n\t\treturn;\n\t}\n\n\tif ([self isPrivateMessage] == NO) {\n\t\treturn;\n\t}\n\n\t[TPIBlowfishEncryption setEncryptionKey:nil forChannel:self];\n\n\t[TPIBlowfishEncryption setEncryptionModeOfOperation:EKBlowfishEncryptionDefaultModeOfOperation forChannel:self];\n}\n\n- (void)__tpi_prepareForApplicationTermination\n{\n\t[self __tpi_destroyEncryptionKeychain];\n\n\t[self __tpi_prepareForApplicationTermination];\n}\n\n- (void)__tpi_prepareForPermanentDestruction\n{\n\t[self __tpi_destroyEncryptionKeychain];\n\n\t[self __tpi_prepareForPermanentDestruction];\n}\n\n@end\n\n#pragma mark -\n\n@implementation TPCPreferencesUserDefaults (TPIBlowfishEncryptionSwizzledPreferences)\n\n+ (void)load\n{\n\tXRExchangeInstanceMethod(@\"TPCPreferencesUserDefaults\", @\"objectForKey:\", @\"__tpi_objectForKey:\");\n\tXRExchangeInstanceMethod(@\"TPCPreferencesUserDefaults\", @\"setObject:forKey:\", @\"__tpi_setObject:forKey:\");\n}\n\n- (void)__tpi_setObject:(id)value forKey:(NSString *)defaultName\n{\n\tif ([TPIBlowfishEncryption isPluginEnabled]) {\n\t\tif ([defaultName hasPrefix:@\"Off-the-Record Messaging -> \"]) {\n\t\t\tstatic dispatch_once_t onceToken;\n\n\t\t\tdispatch_once(&onceToken, ^{\n\t\t\t\t[TDCAlert alertSheetWithWindow:[NSApp keyWindow]\n\t\t\t\t\t\t\t\t\t\t  body:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[alk-c6]\")\n\t\t\t\t\t\t\t\t\t\t title:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[d2x-dh]\")\n\t\t\t\t\t\t\t\t defaultButton:TXLocalizedStringAlternative([NSBundle bundleForClass:[TPIBlowfishEncryption class]], @\"BasicLanguage[tv1-4l]\")\n\t\t\t\t\t\t\t   alternateButton:nil\n\t\t\t\t\t\t\t\t   otherButton:nil];\n\t\t\t});\n\n\t\t\treturn; // Cancel operation...\n\t\t}\n\t}\n\n\t[self __tpi_setObject:value forKey:defaultName];\n}\n\n- (id)__tpi_objectForKey:(NSString *)defaultName\n{\n\tif ([TPIBlowfishEncryption isPluginEnabled]) {\n\t\tif ([defaultName hasPrefix:@\"Off-the-Record Messaging -> \"]) {\n\t\t\treturn @(NO);\n\t\t}\n\t}\n\n\treturn [self __tpi_objectForKey:defaultName];\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/LICENSE-GPLv2.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.,\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License."
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/LICENSE.txt",
    "content": "\nThe “Blowfish Encryption Extension” project consists of several components \nwhich are distributed under different licenses. Work originating from Codeux \nSoftware, LLC falls under the following license declaration. All other work, \nincluding license information, can be found by viewing the included \nACKNOWLEDGEMENT.txt file.\n\n/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *\n *         Copyright (c) 2015 - 2018 Codeux Software, LLC\n *     Please see ACKNOWLEDGEMENT for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of \"Codeux Software, LLC\", nor the names of its\n *    contributors may be used to endorse or promote products derived\n *    from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"sd4-2b\" = \"No encryption key is set.\";\n\"st5-x8\" = \"Current Encryption Key: %@\";\n\n\"rhu-sw\" = \"Encryption started in query. If this query is closed, then the key must be set again.\";\n\n\"lo0-tu\" = \"Key exchange failed: corrupted data\";\n\"wo2-d2\" = \"Key exchange failed: failure to generate public key.\";\n\"tr4-jd\" = \"Key exchange failed: failure to compute secret from public key.\";\n\n\"jmi-xp\" = \"Successful key exchange. Messages sent to \\002%@\\002 will now be encrypted.\";\n\"cdb-6z\" = \"To view the actual key used to encrypt these messages, use the \\002key\\002 command.\";\n\"7sz-gy\" = \"\\0034\\002Warning:\\002\\003 If this query is closed, then a new key exchange is required to continue the encrypted chat.\";\n\"2kj-i5\" = \"Key exchange is for queries only.\";\n\"wi6-cy\" = \"A key exchange request already exists for \\002%@\\002. Please wait for the current one to expire before requesting a new one.\";\n\"8nu-ow\" = \"Received key exchange request from \\002%@\\002. Processing…\";\n\"ezp-nq\" = \"Key exchange request has been sent to \\002%@\\002.\";\n\"c3y-2b\" = \"Key exchange request for \\002%@\\002 has expired.\";\n\"184-19\" = \"Key exchange response has been sent to \\002%@\\002.\";\n\"eqo-bn\" = \"Received key exchange response from \\002%@\\002. Processing…\";\n\"5p8-18\" = \"The Electronic Codebook (ECB) mode of operation is currently in use for encryption.\";\n\"3px-4w\" = \"The Cipher-block Chaining (CBC) mode of operation is currently in use for encryption.\";\n\n\"9eq-sn\" = \"Cannot process key exchange request from \\002%@\\002 until the active encryption keys are reset. This task can be accomplished by using the \\002delkey\\002 command.\";\n\"2oq-wt\" = \"Cannot process key exchange request for \\002%@\\002 until the active encryption keys are reset. This task can be accomplished by using the \\002delkey\\002 command.\";\n\n\"vph-s9\" = \"The Cipher-block Chaining (CBC) mode of operation will be used for encryption.\";\n\"5e8-56\" = \"The Electronic Codebook (ECB) mode of operation will be used for encryption.\";\n\n\"np3-3g\" = \"Decryption failed\";\n\"1ve-yc\" = \"Encryption of message failed; not sending to server.\";\n\"9k1-jc\" = \"Encryption key changed; adjusting accordingly.\";\n\"1dv-qi\" = \"Encryption started\";\n\"ime-kt\" = \"Encryption stopped\";\n\"4mm-6d\" = \"\\0034\\002Decryption lost data!\\002\\003 When decrypting message, %ld bytes were found at the end of the message which do not form a complete 8 byte encryption block. These bytes were removed and could not be decrypted.\";\n\n\"fmt-65\" = \"The key you entered is longer than 56 bytes. The Blowfish block cipher has a maximum key length of 56 bytes. \\002Your key will be truncated.\\002\";\n\n\"8o8-tj\" = \"Blowfish Encryption\";\n\n\"0h8-o3\" = \"Restart required\";\n\"ei0-4a\" = \"Please restart Textual to apply changes\";\n\"4qo-gl\" = \"OK\";\n\n\"qb6-7a\" = \"Services not enabled\";\n\"87t-ge\" = \"In order to use the command “%@“, “FiSH” encryption must be enabled by browsing to Preferences ➜ Addons ➜ Blowfish Encryption\";\n\"oyj-zy\" = \"OK\";\n\n\"d2x-dh\" = \"Cannot toggle preference\";\n\"alk-c6\" = \"Changes to preferences related to Off-the-Record Messaging (OTR) will have no effect when “FiSH” encryption is enabled. \";\n\"tv1-4l\" = \"OK\";\n\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.18</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2015 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPIBlowfishEncryption</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Blowfish Encryption/Resources/User Interface/en.lproj/TPIBlowfishEncryption.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPIBlowfishEncryption\">\n            <connections>\n                <outlet property=\"preferencePaneView\" destination=\"LOA-uM-qhd\" id=\"DnN-Nb-rHU\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView id=\"LOA-uM-qhd\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"671\" height=\"224\"/>\n            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMinY=\"YES\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JUL-dK-X0r\">\n                    <rect key=\"frame\" x=\"271\" y=\"116\" width=\"126\" height=\"26\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable FiSH\" bezelStyle=\"regularSquare\" imagePosition=\"left\" controlSize=\"large\" state=\"on\" inset=\"2\" id=\"rLW-So-J3H\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\" size=\"18\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"preferencesChanged:\" target=\"-2\" id=\"hWM-vl-JE2\"/>\n                        <binding destination=\"Bbo-6V-xug\" name=\"value\" keyPath=\"values.Blowfish Encryption Extension -&gt; Enable Service\" id=\"sOZ-hQ-7lc\"/>\n                    </connections>\n                </button>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KZ9-Ql-hLa\">\n                    <rect key=\"frame\" x=\"115\" y=\"54\" width=\"441\" height=\"42\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"437\" id=\"F1R-57-iWz\"/>\n                    </constraints>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"WARNING: There is absolutely no guarantee that data you encrypt using FiSH is secure.\" id=\"omF-Az-3FB\">\n                        <font key=\"font\" metaFont=\"systemBold\" size=\"18\"/>\n                        <color key=\"textColor\" red=\"0.85371291035353536\" green=\"0.10235263760745605\" blue=\"0.0\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"V4q-92-b4n\">\n                    <rect key=\"frame\" x=\"125\" y=\"162\" width=\"421\" height=\"32\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"8mc-xf-sYs\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">“FiSH” refers to a dated implementation of the Blowfish block cipher which is popular for encrypting the contents of chatrooms. </string>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <textField horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ggE-sE-pgP\">\n                    <rect key=\"frame\" x=\"115\" y=\"30\" width=\"413\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" title=\"FiSH uses the Blowfish block cipher with a weak mode of operation.\" id=\"G8T-WE-zDc\">\n                        <font key=\"font\" usesAppearanceFont=\"YES\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"JUL-dK-X0r\" firstAttribute=\"centerX\" secondItem=\"LOA-uM-qhd\" secondAttribute=\"centerX\" id=\"LDV-ey-3nx\"/>\n                <constraint firstItem=\"V4q-92-b4n\" firstAttribute=\"centerX\" secondItem=\"LOA-uM-qhd\" secondAttribute=\"centerX\" id=\"M7u-aA-fTm\"/>\n                <constraint firstItem=\"KZ9-Ql-hLa\" firstAttribute=\"centerX\" secondItem=\"LOA-uM-qhd\" secondAttribute=\"centerX\" id=\"O9j-US-ZCM\"/>\n                <constraint firstItem=\"KZ9-Ql-hLa\" firstAttribute=\"top\" secondItem=\"JUL-dK-X0r\" secondAttribute=\"bottom\" constant=\"20\" id=\"Sil-BA-5mM\"/>\n                <constraint firstItem=\"ggE-sE-pgP\" firstAttribute=\"leading\" secondItem=\"KZ9-Ql-hLa\" secondAttribute=\"leading\" id=\"UJq-rj-sMK\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"ggE-sE-pgP\" secondAttribute=\"bottom\" constant=\"30\" id=\"XVd-o2-pPW\"/>\n                <constraint firstItem=\"ggE-sE-pgP\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"KZ9-Ql-hLa\" secondAttribute=\"trailing\" id=\"Y3W-EA-YX4\"/>\n                <constraint firstItem=\"JUL-dK-X0r\" firstAttribute=\"top\" secondItem=\"V4q-92-b4n\" secondAttribute=\"bottom\" constant=\"20\" id=\"dQx-VI-L5f\"/>\n                <constraint firstItem=\"V4q-92-b4n\" firstAttribute=\"top\" secondItem=\"LOA-uM-qhd\" secondAttribute=\"top\" constant=\"30\" id=\"qFd-Bj-T47\"/>\n                <constraint firstItem=\"ggE-sE-pgP\" firstAttribute=\"top\" secondItem=\"KZ9-Ql-hLa\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"x6m-yA-qWh\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"331.5\" y=\"246\"/>\n        </customView>\n        <userDefaultsController id=\"Bbo-6V-xug\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Caffeine Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AAF420F27E9B007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAF220F27E9B007CA939 /* BasicLanguage.strings */; };\n\t\t4C36AAF720F27EA3007CA939 /* TPI_Caffeine.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAF520F27EA3007CA939 /* TPI_Caffeine.xib */; };\n\t\t4C46A15320EC6F2600094EA4 /* TPI_Caffeine.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A15020EC6F2600094EA4 /* TPI_Caffeine.m */; };\n\t\t4CBE7B591A91485C008FB230 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBE7B341A913F34008FB230 /* CocoaExtensions.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C36AAF320F27E9B007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C36AAF620F27EA3007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPI_Caffeine.xib; sourceTree = \"<group>\"; };\n\t\t4C46A14F20EC6F2600094EA4 /* TPI_Caffeine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_Caffeine.h; sourceTree = \"<group>\"; };\n\t\t4C46A15020EC6F2600094EA4 /* TPI_Caffeine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_Caffeine.m; sourceTree = \"<group>\"; };\n\t\t4C46A15B20EC6F3100094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A15C20EC6F3100094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A16020EC6F3100094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A16C20EC6F3100094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A16D20EC6F3100094EA4 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A16E20EC6F3100094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A17020EC6F3100094EA4 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A17320EC6F3100094EA4 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A17F20EC6F3100094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A18020EC6F3100094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A18420EC6F3100094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A1AD20EC701B00094EA4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4CBE7B341A913F34008FB230 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../../.tmp/SharedBuildResults-Frameworks/CocoaExtensions.framework\"; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* Caffeine.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Caffeine.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CBE7B591A91485C008FB230 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BragSpam */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A14E20EC6F2600094EA4 /* Classes */,\n\t\t\t\t4C46A14820EC6F2600094EA4 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BragSpam;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBE7B341A913F34008FB230 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* Caffeine.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14820EC6F2600094EA4 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A15420EC6F3100094EA4 /* Configurations */,\n\t\t\t\t4C46A14920EC6F2600094EA4 /* Property Lists */,\n\t\t\t\t4C46A14A20EC6F2600094EA4 /* Language Files */,\n\t\t\t\t4C46A14C20EC6F2600094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14920EC6F2600094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A1AD20EC701B00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14A20EC6F2600094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAF220F27E9B007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14C20EC6F2600094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAF520F27EA3007CA939 /* TPI_Caffeine.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14E20EC6F2600094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A14F20EC6F2600094EA4 /* TPI_Caffeine.h */,\n\t\t\t\t4C46A15020EC6F2600094EA4 /* TPI_Caffeine.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A15420EC6F3100094EA4 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A15820EC6F3100094EA4 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C46A15820EC6F3100094EA4 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A16A20EC6F3100094EA4 /* Common */,\n\t\t\t\t4C46A17D20EC6F3100094EA4 /* Debug */,\n\t\t\t\t4C46A15920EC6F3100094EA4 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A15920EC6F3100094EA4 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A16020EC6F3100094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A15C20EC6F3100094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A15B20EC6F3100094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A16A20EC6F3100094EA4 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A17320EC6F3100094EA4 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C46A17020EC6F3100094EA4 /* Foundation.xcconfig */,\n\t\t\t\t4C46A16D20EC6F3100094EA4 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C46A16E20EC6F3100094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A16C20EC6F3100094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A17D20EC6F3100094EA4 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A18420EC6F3100094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A18020EC6F3100094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A17F20EC6F3100094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* Caffeine Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Caffeine Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Caffeine Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BragSpam;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* Caffeine.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Caffeine Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BragSpam */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* Caffeine Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AAF720F27EA3007CA939 /* TPI_Caffeine.xib in Resources */,\n\t\t\t\t4C36AAF420F27E9B007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A15320EC6F2600094EA4 /* TPI_Caffeine.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAF220F27E9B007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAF320F27E9B007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAF520F27EA3007CA939 /* TPI_Caffeine.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAF620F27EA3007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_Caffeine.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-Caffeine-bundled\";\n\t\t\t\tPRODUCT_NAME = Caffeine;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-Caffeine-bundled\";\n\t\t\t\tPRODUCT_NAME = Caffeine;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A18020EC6F3100094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A15C20EC6F3100094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CCD21E41FA41DE20056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4CCD21E51FA41DE20056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-Caffeine-bundled\";\n\t\t\t\tPRODUCT_NAME = Caffeine;\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Caffeine Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4CCD21E51FA41DE20056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Caffeine Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4CCD21E41FA41DE20056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Caffeine Extension.xcodeproj/xcshareddata/xcschemes/Caffeine Extension.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1600\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n               BuildableName = \"Caffeine.bundle\"\n               BlueprintName = \"Caffeine Extension\"\n               ReferencedContainer = \"container:Caffeine Extension.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"Caffeine.bundle\"\n            BlueprintName = \"Caffeine Extension\"\n            ReferencedContainer = \"container:Caffeine Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"Caffeine.bundle\"\n            BlueprintName = \"Caffeine Extension\"\n            ReferencedContainer = \"container:Caffeine Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Release\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Classes/TPI_Caffeine.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_Caffeine : NSObject <THOPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Classes/TPI_Caffeine.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_Caffeine.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_Caffeine ()\n@property (nonatomic, strong) NSMutableArray<IRCClient *> *observedClients;\n@property (nonatomic, strong) NSProgress *progressObject;\n@property (nonatomic, strong) IBOutlet NSView *preferencesPaneView;\n@end\n\n@implementation TPI_Caffeine\n\n#pragma mark -\n#pragma mark Progress Management\n\n- (BOOL)disableSleepModeWhenConnected\n{\n\treturn [RZUserDefaults() boolForKey:@\"Private Extension Store -> Caffeine Extension -> Prevent Sleep\"];\n}\n\n- (void)disableSleepMode\n{\n\tself.progressObject = [RZProcessInfo() beginActivityWithOptions:NSActivityUserInitiated reason:@\"Disable sleep mode\"];\n\n\tLogToConsoleWithSubsystem(THOPluginLoggingSubsystem(), \"Disabled sleep mode\");\n}\n\n- (void)enableSleepMode\n{\n\tif (self.progressObject == nil) {\n\t\treturn;\n\t}\n\n\t[RZProcessInfo() endActivity:self.progressObject];\n\n\tself.progressObject = nil;\n\n\tLogToConsoleWithSubsystem(THOPluginLoggingSubsystem(), \"Enabled sleep mode\");\n}\n\n- (void)toggleSleepMode\n{\n\tBOOL oneClientLoggedIn = NO;\n\n\t@synchronized(self.observedClients) {\n\t\tfor (IRCClient *client in self.observedClients) {\n\t\t\tif (client.isLoggedIn == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\toneClientLoggedIn = YES;\n\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (oneClientLoggedIn) {\n\t\t[self disableSleepMode];\n\t} else {\n\t\t[self enableSleepMode];\n\t}\n}\n\n#pragma mark -\n#pragma mark Key-value Observation\n\n- (void)rebuildObservedClients\n{\n\t/* This method is called anytime the client list changes\n\t which means we only begin observing clients here if they\n\t are not already observed. */\n\t/* This method will remove observed clients if the user \n\t has disabled the option to disable sleep mode. If the\n\t option is enabled, then this method observes clients \n\t and toggles sleep mode once completed. */\n\t@synchronized(self.observedClients) {\n\t\tBOOL observeClients = [self disableSleepModeWhenConnected];\n\n\t\tNSArray *clientList = worldController().clientList;\n\n\t\tfor (IRCClient *client in self.observedClients) {\n\t\t\t/* Only stop observing client if they are still in -clientList */\n\t\t\t/* If they are not, then we are only dangling a reference to a\n\t\t\t client that no longer exists and can free it below. */\n\n\t\t\tif ([clientList containsObject:client] || observeClients == NO) {\n\t\t\t\t@try {\n\t\t\t\t\t[client removeObserver:self forKeyPath:@\"isLoggedIn\"];\n\t\t\t\t} @catch (NSException *exception) {\n\t\t\t\t\tLogToConsoleFaultWithSubsystem(THOPluginLoggingSubsystem(), \"Caught exception: %{public}@\", [exception reason]);\n\n\t\t\t\t\tLogStackTraceWithSubsystem(THOPluginLoggingSubsystem());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (observeClients == NO) {\n\t\t\tself.observedClients = nil;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (self.observedClients == nil) {\n\t\t\t\tself.observedClients = [NSMutableArray array];\n\t\t\t}\n\n\t\t\tfor (IRCClient *client in clientList) {\n\t\t\t\tif ([self.observedClients containsObject:client] == NO) {\n\t\t\t\t\t[self.observedClients addObject:client];\n\n\t\t\t\t\t[client addObserver:self\n\t\t\t\t\t\t\t forKeyPath:@\"isLoggedIn\"\n\t\t\t\t\t\t\t\toptions:NSKeyValueObservingOptionNew\n\t\t\t\t\t\t\t\tcontext:NULL];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t[self toggleSleepMode];\n\t}\n}\n\n#ifdef TXSystemIsOSXSierraOrLater\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context\n#else\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context\n#endif\n{\n\t[self toggleSleepMode];\n}\n\n- (IBAction)toggledDisableSleepModeWhileConnected:(id)sender\n{\n\t[self rebuildObservedClients];\n}\n\n#pragma mark -\n#pragma mark Plugin API\n\n- (void)pluginLoadedIntoMemory\n{\n\t/* This plugin uses NSProgress which is not available on Mountain Lion */\n\t/* The Textual Extras installer can detect operating system and will not\n\t allow it to be installed on Mountain Lion, but still good to have some\n\t type of sanity type. */\n\tif (TEXTUAL_RUNNING_ON(10.9, Mavericks) == NO) {\n\t\treturn;\n\t}\n\n\t/* Load interface and begin observing client list changes */\n\t(void)[TPIBundleFromClass() loadNibNamed:@\"TPI_Caffeine\" owner:self topLevelObjects:nil];\n\n\t[RZNotificationCenter() addObserverForName:IRCWorldClientListWasModifiedNotification\n\t\t\t\t\t\t\t\t\t\tobject:nil\n\t\t\t\t\t\t\t\t\t\t queue:nil\n\t\t\t\t\t\t\t\t\tusingBlock:^(NSNotification *note) {\n\t\t\t\t\t\t\t\t\t\t[self rebuildObservedClients];\n\t\t\t\t\t\t\t\t\t}];\n\n\t/* Plugins are loaded after clients have been setup which\n\t means we have to manually build observes in addition to\n\t observing the client list change notification. */\n\t[self rebuildObservedClients];\n}\n\n- (void)pluginWillBeUnloadedFromMemory\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\t[self enableSleepMode];\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn TPILocalizedString(@\"BasicLanguage[xqp-6g]\");\n}\n\n- (NSView *)pluginPreferencesPaneView\n{\n\treturn self.preferencesPaneView;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"xqp-6g\" = \"Sleep Mode Management\";\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.8</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2015 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPI_Caffeine</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Caffeine/Resources/User Interface/en.lproj/TPI_Caffeine.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPI_Caffeine\">\n            <connections>\n                <outlet property=\"preferencesPaneView\" destination=\"ARD-gu-kap\" id=\"vNH-fd-Ql6\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ARD-gu-kap\" userLabel=\"Incoming Data\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"114\"/>\n            <userGuides>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s7v-vd-1wt\">\n                    <rect key=\"frame\" x=\"148\" y=\"67\" width=\"270\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Disable sleep while Textual is connected\" bezelStyle=\"regularSquare\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"nPX-Su-uQG\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"toggledDisableSleepModeWhileConnected:\" target=\"-2\" id=\"sJm-nQ-3Ha\"/>\n                        <binding destination=\"QpH-vh-j7d\" name=\"value\" keyPath=\"values.Private Extension Store -&gt; Caffeine Extension -&gt; Prevent Sleep\" id=\"Yrx-aD-acl\"/>\n                    </connections>\n                </button>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bql-3Z-Voy\">\n                    <rect key=\"frame\" x=\"166\" y=\"30\" width=\"351\" height=\"30\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Do not allow your Mac to go to sleep, thus disconnecting the Internet, while Textual has at least one connection open.\" id=\"Qhn-Wh-BWO\">\n                        <font key=\"font\" metaFont=\"cellTitle\"/>\n                        <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"Bql-3Z-Voy\" firstAttribute=\"top\" secondItem=\"s7v-vd-1wt\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"7s5-kl-cI8\"/>\n                <constraint firstItem=\"s7v-vd-1wt\" firstAttribute=\"leading\" secondItem=\"ARD-gu-kap\" secondAttribute=\"leading\" constant=\"150\" id=\"MIl-tU-QVX\"/>\n                <constraint firstItem=\"s7v-vd-1wt\" firstAttribute=\"top\" secondItem=\"ARD-gu-kap\" secondAttribute=\"top\" constant=\"30\" id=\"SF2-qZ-ePs\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"Bql-3Z-Voy\" secondAttribute=\"bottom\" constant=\"30\" id=\"Ylc-ia-aXe\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"s7v-vd-1wt\" secondAttribute=\"trailing\" constant=\"20\" id=\"dnY-nG-uK0\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Bql-3Z-Voy\" secondAttribute=\"trailing\" constant=\"20\" id=\"fxu-9X-7sX\"/>\n                <constraint firstItem=\"Bql-3Z-Voy\" firstAttribute=\"leading\" secondItem=\"s7v-vd-1wt\" secondAttribute=\"leading\" constant=\"18\" id=\"jbZ-Nn-bp1\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"363.5\" y=\"-3953\"/>\n        </customView>\n        <userDefaultsController id=\"QpH-vh-j7d\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Chat Filter Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AAE920F27E05007CA939 /* TPI_ChatFilterEditFilterSheet.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAE320F27E05007CA939 /* TPI_ChatFilterEditFilterSheet.strings */; };\n\t\t4C36AAEA20F27E05007CA939 /* TPI_ChatFilterLogic.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAE520F27E05007CA939 /* TPI_ChatFilterLogic.strings */; };\n\t\t4C36AAEB20F27E05007CA939 /* TPI_ChatFilterExtension.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAE720F27E05007CA939 /* TPI_ChatFilterExtension.strings */; };\n\t\t4C36AAF020F27E10007CA939 /* TPI_ChatFilterEditFilterSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAEC20F27E10007CA939 /* TPI_ChatFilterEditFilterSheet.xib */; };\n\t\t4C36AAF120F27E10007CA939 /* TPI_ChatFilterExtension.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAEE20F27E10007CA939 /* TPI_ChatFilterExtension.xib */; };\n\t\t4C46A0AE20EC6B5A00094EA4 /* TPI_ChatFilterLogic.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0A320EC6B5A00094EA4 /* TPI_ChatFilterLogic.m */; };\n\t\t4C46A0AF20EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0A520EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.m */; };\n\t\t4C46A0B020EC6B5A00094EA4 /* TPI_ChatFilterExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0A620EC6B5A00094EA4 /* TPI_ChatFilterExtension.m */; };\n\t\t4C46A0B120EC6B5A00094EA4 /* TPI_ChatFilter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0A920EC6B5A00094EA4 /* TPI_ChatFilter.m */; };\n\t\t4C46A0B220EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0AB20EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C1D108820EBF3C000E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D108920EBF3C000E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D108D20EBF3C000E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D109B20EBF3C000E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D109C20EBF3C000E72D80 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D109D20EBF3C000E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D109F20EBF3C000E72D80 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D10A220EBF3C000E72D80 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10B020EBF3C000E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D10B120EBF3C000E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10B520EBF3C000E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C36AAE420F27E05007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TPI_ChatFilterEditFilterSheet.strings; sourceTree = \"<group>\"; };\n\t\t4C36AAE620F27E05007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TPI_ChatFilterLogic.strings; sourceTree = \"<group>\"; };\n\t\t4C36AAE820F27E05007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/TPI_ChatFilterExtension.strings; sourceTree = \"<group>\"; };\n\t\t4C36AAED20F27E10007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPI_ChatFilterEditFilterSheet.xib; sourceTree = \"<group>\"; };\n\t\t4C36AAEF20F27E10007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPI_ChatFilterExtension.xib; sourceTree = \"<group>\"; };\n\t\t4C46A0A320EC6B5A00094EA4 /* TPI_ChatFilterLogic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_ChatFilterLogic.m; sourceTree = \"<group>\"; };\n\t\t4C46A0A420EC6B5A00094EA4 /* TPI_ChatFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ChatFilter.h; sourceTree = \"<group>\"; };\n\t\t4C46A0A520EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_ChatFilterEditFilterSheet.m; sourceTree = \"<group>\"; };\n\t\t4C46A0A620EC6B5A00094EA4 /* TPI_ChatFilterExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_ChatFilterExtension.m; sourceTree = \"<group>\"; };\n\t\t4C46A0A720EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_NumberOnlyTextFieldFormatter.h; sourceTree = \"<group>\"; };\n\t\t4C46A0A820EC6B5A00094EA4 /* TPI_ChatFilterInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ChatFilterInternal.h; sourceTree = \"<group>\"; };\n\t\t4C46A0A920EC6B5A00094EA4 /* TPI_ChatFilter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_ChatFilter.m; sourceTree = \"<group>\"; };\n\t\t4C46A0AA20EC6B5A00094EA4 /* TPI_ChatFilterLogic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ChatFilterLogic.h; sourceTree = \"<group>\"; };\n\t\t4C46A0AB20EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_NumberOnlyTextFieldFormatter.m; sourceTree = \"<group>\"; };\n\t\t4C46A0AC20EC6B5A00094EA4 /* TPI_ChatFilterExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ChatFilterExtension.h; sourceTree = \"<group>\"; };\n\t\t4C46A0AD20EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ChatFilterEditFilterSheet.h; sourceTree = \"<group>\"; };\n\t\t4C46A0B420EC6B6A00094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* Chat Filters.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"Chat Filters.bundle\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* PreferencePaneExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0A220EC6B5A00094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = PreferencePaneExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CAA730C1BA9B06D00A38456 /* Configurations */,\n\t\t\t\t4C46A0B520EC6B6A00094EA4 /* Language Files */,\n\t\t\t\t4C46A0B320EC6B6A00094EA4 /* Property Lists */,\n\t\t\t\t4C46A0BC20EC6B6A00094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* Chat Filters.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D108420EBF3C000E72D80 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D109820EBF3C000E72D80 /* Common */,\n\t\t\t\t4C1D10AD20EBF3C000E72D80 /* Debug */,\n\t\t\t\t4C1D108520EBF3C000E72D80 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D108520EBF3C000E72D80 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D108D20EBF3C000E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D108920EBF3C000E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D108820EBF3C000E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D109820EBF3C000E72D80 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D10A220EBF3C000E72D80 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C1D109F20EBF3C000E72D80 /* Foundation.xcconfig */,\n\t\t\t\t4C1D109C20EBF3C000E72D80 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C1D109D20EBF3C000E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D109B20EBF3C000E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D10AD20EBF3C000E72D80 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D10B520EBF3C000E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D10B120EBF3C000E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D10B020EBF3C000E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0A220EC6B5A00094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0A420EC6B5A00094EA4 /* TPI_ChatFilter.h */,\n\t\t\t\t4C46A0A920EC6B5A00094EA4 /* TPI_ChatFilter.m */,\n\t\t\t\t4C46A0AD20EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.h */,\n\t\t\t\t4C46A0A520EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.m */,\n\t\t\t\t4C46A0AC20EC6B5A00094EA4 /* TPI_ChatFilterExtension.h */,\n\t\t\t\t4C46A0A620EC6B5A00094EA4 /* TPI_ChatFilterExtension.m */,\n\t\t\t\t4C46A0A820EC6B5A00094EA4 /* TPI_ChatFilterInternal.h */,\n\t\t\t\t4C46A0AA20EC6B5A00094EA4 /* TPI_ChatFilterLogic.h */,\n\t\t\t\t4C46A0A320EC6B5A00094EA4 /* TPI_ChatFilterLogic.m */,\n\t\t\t\t4C46A0A720EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.h */,\n\t\t\t\t4C46A0AB20EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0B320EC6B6A00094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0B420EC6B6A00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0B520EC6B6A00094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE320F27E05007CA939 /* TPI_ChatFilterEditFilterSheet.strings */,\n\t\t\t\t4C36AAE720F27E05007CA939 /* TPI_ChatFilterExtension.strings */,\n\t\t\t\t4C36AAE520F27E05007CA939 /* TPI_ChatFilterLogic.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0BC20EC6B6A00094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAEC20F27E10007CA939 /* TPI_ChatFilterEditFilterSheet.xib */,\n\t\t\t\t4C36AAEE20F27E10007CA939 /* TPI_ChatFilterExtension.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CAA730C1BA9B06D00A38456 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D108420EBF3C000E72D80 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* Chat Filter Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Chat Filter Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Chat Filter Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = PreferencePaneExample;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* Chat Filters.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Chat Filter Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* PreferencePaneExample */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* Chat Filter Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AAEB20F27E05007CA939 /* TPI_ChatFilterExtension.strings in Resources */,\n\t\t\t\t4C36AAF120F27E10007CA939 /* TPI_ChatFilterExtension.xib in Resources */,\n\t\t\t\t4C36AAE920F27E05007CA939 /* TPI_ChatFilterEditFilterSheet.strings in Resources */,\n\t\t\t\t4C36AAEA20F27E05007CA939 /* TPI_ChatFilterLogic.strings in Resources */,\n\t\t\t\t4C36AAF020F27E10007CA939 /* TPI_ChatFilterEditFilterSheet.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A0B220EC6B5A00094EA4 /* TPI_NumberOnlyTextFieldFormatter.m in Sources */,\n\t\t\t\t4C46A0AE20EC6B5A00094EA4 /* TPI_ChatFilterLogic.m in Sources */,\n\t\t\t\t4C46A0B120EC6B5A00094EA4 /* TPI_ChatFilter.m in Sources */,\n\t\t\t\t4C46A0AF20EC6B5A00094EA4 /* TPI_ChatFilterEditFilterSheet.m in Sources */,\n\t\t\t\t4C46A0B020EC6B5A00094EA4 /* TPI_ChatFilterExtension.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAE320F27E05007CA939 /* TPI_ChatFilterEditFilterSheet.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE420F27E05007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_ChatFilterEditFilterSheet.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAE520F27E05007CA939 /* TPI_ChatFilterLogic.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE620F27E05007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_ChatFilterLogic.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAE720F27E05007CA939 /* TPI_ChatFilterExtension.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE820F27E05007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_ChatFilterExtension.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAEC20F27E10007CA939 /* TPI_ChatFilterEditFilterSheet.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAED20F27E10007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_ChatFilterEditFilterSheet.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAEE20F27E10007CA939 /* TPI_ChatFilterExtension.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAEF20F27E10007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPI_ChatFilterExtension.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911C08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ChatFilterExtension\";\n\t\t\t\tPRODUCT_NAME = \"Chat Filters\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D10B120EBF3C000E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4CCD21EC1FA41E250056F5FE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D108920EBF3C000E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CCD21ED1FA41E250056F5FE /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ChatFilterExtension\";\n\t\t\t\tPRODUCT_NAME = \"Chat Filters\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CCD21EE1FA41E390056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4CCD21EF1FA41E390056F5FE /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ChatFilterExtension\";\n\t\t\t\tPRODUCT_NAME = \"Chat Filters\";\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Chat Filter Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911C08733D790010E9CD /* Debug */,\n\t\t\t\t4CCD21ED1FA41E250056F5FE /* Release */,\n\t\t\t\t4CCD21EF1FA41E390056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Debug;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Chat Filter Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB912008733D790010E9CD /* Debug */,\n\t\t\t\t4CCD21EC1FA41E250056F5FE /* Release */,\n\t\t\t\t4CCD21EE1FA41E390056F5FE /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Debug;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilter.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TPI_ChatFilterLimitToValue) {\n\tTPI_ChatFilterLimitToValueNoLimit\t\t\t\t= 0,\n\tTPI_ChatFilterLimitToValueChannels\t\t\t\t= 1,\n\tTPI_ChatFilterLimitToValuePrivateMessages\t\t= 2,\n\tTPI_ChatFilterLimitToValueSpecificItems\t\t\t= 3\n};\n\ntypedef NS_ENUM(NSUInteger, TPI_ChatFilterAgeComparator) {\n\tTPI_ChatFilterAgeComparatorNone\t\t\t\t= 0,\n\tTPI_ChatFilterAgeComparatorLessThan\t\t\t= 1, // Filter only executes if age of user is < limit\n\tTPI_ChatFilterAgeComparatorGreaterThan\t\t= 2 // Filter only executes if age of user is >= limit\n};\n\ntypedef NS_OPTIONS(NSUInteger, TPI_ChatFilterEventType) {\n\tTPI_ChatFilterEventTypeNumeric\t\t\t\t\t= 1 << 0,\n\tTPI_ChatFilterEventTypePlainTextMessage\t\t\t= 1 << 1,\n\tTPI_ChatFilterEventTypeActionMessage\t\t\t= 1 << 2,\n\tTPI_ChatFilterEventTypeNoticeMessage\t\t\t= 1 << 3,\n\tTPI_ChatFilterEventTypeUserJoinedChannel\t\t= 1 << 4,\n\tTPI_ChatFilterEventTypeUserLeftChannel\t\t\t= 1 << 5,\n\tTPI_ChatFilterEventTypeUserKickedFromChannel\t= 1 << 6,\n\tTPI_ChatFilterEventTypeUserDisconnected\t\t\t= 1 << 7,\n\tTPI_ChatFilterEventTypeUserChangedNickname\t\t= 1 << 8,\n\tTPI_ChatFilterEventTypeChannelTopicReceived\t\t= 1 << 9,\n\tTPI_ChatFilterEventTypeChannelTopicChanged\t\t= 1 << 10,\n\tTPI_ChatFilterEventTypeChannelModeReceived\t\t= 1 << 11,\n\tTPI_ChatFilterEventTypeChannelModeChanged\t\t= 1 << 12\n};\n\n@interface TPI_ChatFilter : XRPortablePropertyDict\n@property (readonly) BOOL filterIgnoreContent;\n@property (readonly) BOOL filterIgnoreOperators;\n@property (readonly) BOOL filterLogMatch;\n@property (readonly) BOOL filterLimitedToMyself;\n@property (readonly) TPI_ChatFilterEventType filterEvents;\n@property (readonly) TPI_ChatFilterLimitToValue filterLimitedToValue;\n@property (readonly) TPI_ChatFilterAgeComparator filterAgeComparator;\n@property (readonly) NSUInteger filterAgeLimit;\n@property (readonly) NSUInteger filterActionFloodControlInterval;\n@property (readonly, copy) NSArray<NSString *> *filterLimitedToChannelsIDs;\n@property (readonly, copy) NSArray<NSString *> *filterLimitedToClientsIDs;\n@property (readonly, copy) NSArray<NSString *> *filterEventsNumerics;\n@property (readonly, copy) NSString *filterAction;\n@property (readonly, copy) NSString *filterDescription;\n@property (readonly, copy) NSString *filterForwardToDestination;\n@property (readonly, copy) NSString *filterMatch;\n@property (readonly, copy) NSString *filterNotes;\n@property (readonly, copy) NSString *filterSenderMatch;\n@property (readonly, copy) NSString *filterTitle;\n@property (readonly, copy) NSString *uniqueIdentifier;\n\n- (BOOL)isEventTypeEnabled:(TPI_ChatFilterEventType)eventType;\n- (BOOL)isCommandEnabled:(NSString *)command;\n\n- (nullable instancetype)initWithContentsOfPath:(NSString *)path;\n- (nullable instancetype)initWithContentsOfURL:(NSURL *)url;\n\n- (BOOL)writeToPath:(NSString *)path;\n- (BOOL)writeToURL:(NSURL *)url;\n@end\n\n#pragma mark -\n\n@interface TPI_ChatFilterMutable : TPI_ChatFilter\n@property (nonatomic, assign, readwrite) BOOL filterIgnoreContent;\n@property (nonatomic, assign, readwrite) BOOL filterIgnoreOperators;\n@property (nonatomic, assign, readwrite) BOOL filterLogMatch;\n@property (nonatomic, assign, readwrite) BOOL filterLimitedToMyself;\n@property (nonatomic, assign, readwrite) TPI_ChatFilterEventType filterEvents;\n@property (nonatomic, assign, readwrite) TPI_ChatFilterLimitToValue filterLimitedToValue;\n@property (nonatomic, assign, readwrite) TPI_ChatFilterAgeComparator filterAgeComparator;\n@property (nonatomic, assign, readwrite) NSUInteger filterAgeLimit;\n@property (nonatomic, assign, readwrite) NSUInteger filterActionFloodControlInterval;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *filterLimitedToChannelsIDs;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *filterLimitedToClientsIDs;\n@property (nonatomic, copy, readwrite) NSArray<NSString *> *filterEventsNumerics;\n@property (nonatomic, copy, readwrite) NSString *filterAction;\n@property (nonatomic, copy, readwrite) NSString *filterForwardToDestination;\n@property (nonatomic, copy, readwrite) NSString *filterMatch;\n@property (nonatomic, copy, readwrite) NSString *filterNotes;\n@property (nonatomic, copy, readwrite) NSString *filterSenderMatch;\n@property (nonatomic, copy, readwrite) NSString *filterTitle;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilter.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_ChatFilter.h\"\n#import \"TPI_ChatFilterInternal.h\"\n\n#import \"NSObjectHelperPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPI_ChatFilter\n\n- (void)populateDefaultsPreflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tself->_defaults = @{\n\t\t@\"filterEvents\"\t\t\t\t\t: @(TPI_ChatFilterEventTypePlainTextMessage |\n\t\t\t\t\t\t\t\t\t\t\tTPI_ChatFilterEventTypeActionMessage),\n\n\t\t@\"filterIgnoreContent\"\t\t\t: @(NO),\n\t\t@\"filterIgnoresOperators\"\t\t: @(YES),\n\t\t@\"filterLimitedToMyself\"\t\t: @(NO),\n\t\t@\"filterLogMatch\"\t\t\t\t: @(NO),\n\n\t\t@\"filterLimitedToValue\"\t\t\t: @(TPI_ChatFilterLimitToValueNoLimit),\n\t\t@\"filterAgeComparator\"\t\t\t: @(TPI_ChatFilterAgeComparatorGreaterThan)\n\t};\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self.initializedAsCopy) {\n\t\treturn;\n\t}\n\n\tSetVariableIfNil(self->_filterLimitedToChannelsIDs, @[])\n\tSetVariableIfNil(self->_filterLimitedToClientsIDs, @[])\n\tSetVariableIfNil(self->_filterEventsNumerics, @[])\n\n\tSetVariableIfNil(self->_filterAction, @\"\")\n\tSetVariableIfNil(self->_filterForwardToDestination, @\"\")\n\tSetVariableIfNil(self->_filterMatch, @\"\")\n\tSetVariableIfNil(self->_filterNotes, @\"\")\n\tSetVariableIfNil(self->_filterSenderMatch, @\"\")\n\tSetVariableIfNil(self->_filterTitle, @\"\")\n\n\tSetVariableIfNil(self->_uniqueIdentifier, [NSString stringWithUUID])\n}\n\n- (instancetype)init\n{\n\treturn [self initWithDictionary:@{}];\n}\n\n- (nullable instancetype)initWithContentsOfPath:(NSString *)path\n{\n\tNSParameterAssert(path != nil);\n\n\tNSURL *url = [NSURL fileURLWithPath:path];\n\n\treturn [self initWithContentsOfURL:url];\n}\n\n- (nullable instancetype)initWithContentsOfURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSDictionary *dic = [NSDictionary dictionaryWithContentsOfURL:url];\n\n\tif (dic == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [self initWithDictionary:dic];\n}\n\n- (void)populateDictionaryValues:(NSDictionary<NSString *, id> *)dic\n{\n\tNSParameterAssert(dic != nil);\n\n\tNSMutableDictionary<NSString *, id> *defaultsMutable = [self->_defaults mutableCopy];\n\n\t[defaultsMutable addEntriesFromDictionary:dic];\n\n\t/* Set regular key names */\n\t[defaultsMutable assignArrayTo:&self->_filterLimitedToChannelsIDs forKey:@\"filterLimitedToChannelsIDs\"];\n\t[defaultsMutable assignArrayTo:&self->_filterLimitedToClientsIDs forKey:@\"filterLimitedToClientsIDs\"];\n\t[defaultsMutable assignArrayTo:&self->_filterEventsNumerics forKey:@\"filterEventsNumerics\"];\n\n\t[defaultsMutable assignBoolTo:&self->_filterIgnoreContent forKey:@\"filterIgnoreContent\"];\n\t[defaultsMutable assignBoolTo:&self->_filterIgnoreOperators forKey:@\"filterIgnoresOperators\"];\n\t[defaultsMutable assignBoolTo:&self->_filterLimitedToMyself forKey:@\"filterLimitedToMyself\"];\n\t[defaultsMutable assignBoolTo:&self->_filterLogMatch forKey:@\"filterLogMatch\"];\n\n\t[defaultsMutable assignStringTo:&self->_filterAction forKey:@\"filterAction\"];\n\t[defaultsMutable assignStringTo:&self->_filterForwardToDestination forKey:@\"filterForwardToDestination\"];\n\t[defaultsMutable assignStringTo:&self->_filterMatch forKey:@\"filterMatch\"];\n\t[defaultsMutable assignStringTo:&self->_filterNotes forKey:@\"filterNotes\"];\n\t[defaultsMutable assignStringTo:&self->_filterSenderMatch forKey:@\"filterSenderMatch\"];\n\t[defaultsMutable assignStringTo:&self->_filterTitle forKey:@\"filterTitle\"];\n\n\t[defaultsMutable assignStringTo:&self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_filterActionFloodControlInterval forKey:@\"filterActionFloodControlInterval\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_filterLimitedToValue forKey:@\"filterLimitedToValue\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_filterAgeComparator forKey:@\"filterAgeComparator\"];\n\t[defaultsMutable assignUnsignedIntegerTo:&self->_filterAgeLimit forKey:@\"filterAgeLimit\"];\n\n\t/* Maintain backwards compatibility by setting old key names */\n\t/* dic is accessed instead of defaultsMutable because filterEvents will always \n\t exist in defaultsMutable */\n\tid filterEvents = dic[@\"filterEvents\"];\n\n\tif (filterEvents && [filterEvents isKindOfClass:[NSNumber class]])\n\t{\n\t\tself->_filterEvents = [filterEvents unsignedIntegerValue];\n\t}\n\telse\n\t{\n\t\tTPI_ChatFilterEventType filterEventsMask = (TPI_ChatFilterEventTypePlainTextMessage | TPI_ChatFilterEventTypeActionMessage);\n\n\t\tid filterCommandPRIVMSG = defaultsMutable[@\"filterCommandPRIVMSG\"];\n\n\t\tif (filterCommandPRIVMSG && [filterCommandPRIVMSG boolValue] == NO) {\n\t\t\tfilterEventsMask &= ~TPI_ChatFilterEventTypePlainTextMessage;\n\t\t}\n\n\t\tid filterCommandPRIVMSG_ACTION = defaultsMutable[@\"filterCommandPRIVMSG_ACTION\"];\n\n\t\tif (filterCommandPRIVMSG_ACTION && [filterCommandPRIVMSG_ACTION boolValue] == NO) {\n\t\t\tfilterEventsMask &= ~TPI_ChatFilterEventTypeActionMessage;\n\t\t}\n\n\t\tif ([defaultsMutable boolForKey:@\"filterCommandNOTICE\"]) {\n\t\t\tfilterEventsMask |= TPI_ChatFilterEventTypeNoticeMessage;\n\t\t}\n\n\t\tself->_filterEvents = filterEventsMask;\n\t}\n}\n\n- (NSDictionary<NSString *, id> *)dictionaryValueForTarget:(XRPortablePropertyDictTarget)target\n{\n\tNSMutableDictionary<NSString *, id> *dic = [NSMutableDictionary dictionary];\n\n\t/* Maintain backwards compatibility by setting old key names */\n\t[dic setBool:[self isEventTypeEnabled:TPI_ChatFilterEventTypePlainTextMessage] forKey:@\"filterCommandPRIVMSG\"];\n\t[dic setBool:[self isEventTypeEnabled:TPI_ChatFilterEventTypeActionMessage]\tforKey:@\"filterCommandPRIVMSG_ACTION\"];\n\t[dic setBool:[self isEventTypeEnabled:TPI_ChatFilterEventTypeNoticeMessage]\tforKey:@\"filterCommandNOTICE\"];\n\n\t/* Set regular key names */\n\t[dic maybeSetObject:self.filterLimitedToChannelsIDs forKey:@\"filterLimitedToChannelsIDs\"];\n\t[dic maybeSetObject:self.filterLimitedToClientsIDs forKey:@\"filterLimitedToClientsIDs\"];\n\t[dic maybeSetObject:self.filterEventsNumerics forKey:@\"filterEventsNumerics\"];\n\n\t[dic maybeSetObject:self.filterAction forKey:@\"filterAction\"];\n\t[dic maybeSetObject:self.filterForwardToDestination forKey:@\"filterForwardToDestination\"];\n\t[dic maybeSetObject:self.filterMatch forKey:@\"filterMatch\"];\n\t[dic maybeSetObject:self.filterNotes forKey:@\"filterNotes\"];\n\t[dic maybeSetObject:self.filterSenderMatch forKey:@\"filterSenderMatch\"];\n\t[dic maybeSetObject:self.filterTitle forKey:@\"filterTitle\"];\n\t[dic maybeSetObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\n\t[dic setBool:self.filterIgnoreContent forKey:@\"filterIgnoreContent\"];\n\t[dic setBool:self.filterIgnoreOperators forKey:@\"filterIgnoresOperators\"];\n\t[dic setBool:self.filterLimitedToMyself forKey:@\"filterLimitedToMyself\"];\n\t[dic setBool:self.filterLogMatch forKey:@\"filterLogMatch\"];\n\n\t[dic setUnsignedInteger:self.filterActionFloodControlInterval forKey:@\"filterActionFloodControlInterval\"];\n\t[dic setUnsignedInteger:self.filterEvents forKey:@\"filterEvents\"];\n\t[dic setUnsignedInteger:self.filterLimitedToValue forKey:@\"filterLimitedToValue\"];\n\t[dic setUnsignedInteger:self.filterAgeComparator forKey:@\"filterAgeComparator\"];\n\t[dic setUnsignedInteger:self.filterAgeLimit forKey:@\"filterAgeLimit\"];\n\n\tif (target == XRPortablePropertyDictTargetCopy ||\n\t\ttarget == XRPortablePropertyDictTargetMutableCopy)\n\t{\n\t\treturn [dic copy];\n\t}\n\n\treturn [dic dictionaryByRemovingDefaults:self->_defaults];\n}\n\n- (BOOL)isEventTypeEnabled:(TPI_ChatFilterEventType)eventType\n{\n\treturn ((self->_filterEvents & eventType) == eventType);\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tTPI_ChatFilter *config = [self allocForCopyAsMutable:mutableCopy];\n\n\tconfig->_defaults = self->_defaults;\n\n\tconfig->_cachedIsCommandEnabledResponses = self->_cachedIsCommandEnabledResponses;\n\n\treturn [config initWithDictionary:self.dictionaryValueForCopy];\n}\n\n- (BOOL)isCommandEnabled:(NSString *)command\n{\n\tNSParameterAssert(command != nil);\n\n\tif (self->_cachedIsCommandEnabledResponses == nil) {\n\t\tself->_cachedIsCommandEnabledResponses = [NSCache new];\n\t}\n\n\tNSNumber *cachedResponse = [self->_cachedIsCommandEnabledResponses objectForKey:command];\n\n\tif (cachedResponse == nil) {\n\t\tTPI_ChatFilterEventType filterEvents = self.filterEvents;\n\n#define _commandMatchesEvent(_command_, _event_)\t\\\n\tif ([command isEqualToString:(_command_)]) {\t\\\n\t\tcachedResponse = @((filterEvents & _event_) == _event_);\t\\\n\t}\n\n\t\t_commandMatchesEvent(@\"JOIN\", TPI_ChatFilterEventTypeUserJoinedChannel)\n\t\telse _commandMatchesEvent(@\"PART\", TPI_ChatFilterEventTypeUserLeftChannel)\n\t\telse _commandMatchesEvent(@\"KICK\", TPI_ChatFilterEventTypeUserKickedFromChannel)\n\t\telse _commandMatchesEvent(@\"QUIT\", TPI_ChatFilterEventTypeUserDisconnected)\n\t\telse _commandMatchesEvent(@\"NICK\", TPI_ChatFilterEventTypeUserChangedNickname)\n\t\telse _commandMatchesEvent(@\"TOPIC\", TPI_ChatFilterEventTypeChannelTopicChanged)\n\t\telse _commandMatchesEvent(@\"MODE\", TPI_ChatFilterEventTypeChannelModeChanged)\n\t\telse _commandMatchesEvent(@\"332\", TPI_ChatFilterEventTypeChannelTopicReceived)\n\t\telse _commandMatchesEvent(@\"333\", TPI_ChatFilterEventTypeChannelTopicReceived)\n\t\telse _commandMatchesEvent(@\"324\", TPI_ChatFilterEventTypeChannelModeReceived)\n\t\telse\n\t\t{\n\t\t\tcachedResponse = @([self.filterEventsNumerics containsObject:command]);\n\t\t}\n\n\t\t[self->_cachedIsCommandEnabledResponses setObject:cachedResponse forKey:command];\n\t}\n\n\treturn cachedResponse.boolValue;\n\n#undef _commandMatchesEvent\n}\n\n- (void)purgeIsCommandEnabledResponses\n{\n\tif (self->_cachedIsCommandEnabledResponses == nil) {\n\t\treturn;\n\t}\n\n\t[self->_cachedIsCommandEnabledResponses removeAllObjects];\n}\n\n- (NSString *)filterDescription\n{\n\treturn TPILocalizedString(@\"TPI_ChatFilterExtension[dka-bx]\", self.filterTitle);\n}\n\n- (__kindof XRPortablePropertyDict *)mutableClass\n{\n\treturn [TPI_ChatFilterMutable self];\n}\n\n- (BOOL)writeToPath:(NSString *)path\n{\n\tNSParameterAssert(path != nil);\n\n\tNSURL *url = [NSURL fileURLWithPath:path];\n\n\treturn [self writeToURL:url];\n}\n\n- (BOOL)writeToURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSDictionary *dictionaryValue = self.dictionaryValue;\n\n\tNSError *parseError = nil;\n\n\tNSData *propertyList =\n\t[NSPropertyListSerialization dataWithPropertyList:dictionaryValue format:NSPropertyListBinaryFormat_v1_0 options:0 error:&parseError];\n\n\tif (propertyList == nil) {\n\t\tif (parseError) {\n\t\t\tLogToConsoleErrorWithSubsystem(THOPluginLoggingSubsystem(),\n\t\t\t\t\"Error Creating Property List: %@\",\n\t\t\t\tparseError.localizedDescription);\n\t\t}\n\n\t\treturn NO;\n\t}\n\n\tBOOL writeResult = [propertyList writeToURL:url atomically:YES];\n\n\tif (writeResult == NO) {\n\t\tLogToConsoleErrorWithSubsystem(THOPluginLoggingSubsystem(), \"Write failed\");\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n@end\n\n#pragma mark -\n\n@implementation TPI_ChatFilterMutable\n\n@dynamic filterAgeComparator;\n@dynamic filterAgeLimit;\n@dynamic filterIgnoreContent;\n@dynamic filterIgnoreOperators;\n@dynamic filterLogMatch;\n@dynamic filterLimitedToMyself;\n@dynamic filterEvents;\n@dynamic filterLimitedToValue;\n@dynamic filterLimitedToChannelsIDs;\n@dynamic filterLimitedToClientsIDs;\n@dynamic filterEventsNumerics;\n@dynamic filterActionFloodControlInterval;\n@dynamic filterAction;\n@dynamic filterForwardToDestination;\n@dynamic filterMatch;\n@dynamic filterNotes;\n@dynamic filterSenderMatch;\n@dynamic filterTitle;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyDict *)immutableClass\n{\n\treturn [TPI_ChatFilter self];\n}\n\n- (void)setFilterIgnoreContent:(BOOL)filterIgnoreContent\n{\n\tif (self->_filterIgnoreContent != filterIgnoreContent) {\n\t\tself->_filterIgnoreContent = filterIgnoreContent;\n\t}\n}\n\n- (void)setFilterIgnoreOperators:(BOOL)filterIgnoreOperators\n{\n\tif (self->_filterIgnoreOperators != filterIgnoreOperators) {\n\t\tself->_filterIgnoreOperators = filterIgnoreOperators;\n\t}\n}\n\n- (void)setFilterLogMatch:(BOOL)filterLogMatch\n{\n\tif (self->_filterLogMatch != filterLogMatch) {\n\t\tself->_filterLogMatch = filterLogMatch;\n\t}\n}\n\n- (void)setFilterLimitedToMyself:(BOOL)filterLimitedToMyself\n{\n\tif (self->_filterLimitedToMyself != filterLimitedToMyself) {\n\t\tself->_filterLimitedToMyself = filterLimitedToMyself;\n\t}\n}\n\n- (void)setFilterEvents:(TPI_ChatFilterEventType)filterEvents\n{\n\tif (self->_filterEvents != filterEvents) {\n\t\tself->_filterEvents = filterEvents;\n\n\t\t[self purgeIsCommandEnabledResponses];\n\t}\n}\n\n- (void)setFilterLimitedToValue:(TPI_ChatFilterLimitToValue)filterLimitedToValue\n{\n\tif (self->_filterLimitedToValue != filterLimitedToValue) {\n\t\tself->_filterLimitedToValue = filterLimitedToValue;\n\t}\n}\n\n- (void)setFilterLimitedToChannelsIDs:(NSArray<NSString *> *)filterLimitedToChannelsIDs\n{\n\tNSParameterAssert(filterLimitedToChannelsIDs != nil);\n\n\tif (self->_filterLimitedToChannelsIDs != filterLimitedToChannelsIDs) {\n\t\tself->_filterLimitedToChannelsIDs = [filterLimitedToChannelsIDs copy];\n\t}\n}\n\n- (void)setFilterLimitedToClientsIDs:(NSArray<NSString *> *)filterLimitedToClientsIDs\n{\n\tNSParameterAssert(filterLimitedToClientsIDs != nil);\n\n\tif (self->_filterLimitedToClientsIDs != filterLimitedToClientsIDs) {\n\t\tself->_filterLimitedToClientsIDs = [filterLimitedToClientsIDs copy];\n\t}\n}\n\n- (void)setFilterEventsNumerics:(NSArray<NSString *> *)filterEventsNumerics\n{\n\tNSParameterAssert(filterEventsNumerics != nil);\n\n\tif (self->_filterEventsNumerics != filterEventsNumerics) {\n\t\tself->_filterEventsNumerics = [filterEventsNumerics copy];\n\n\t\t[self purgeIsCommandEnabledResponses];\n\t}\n}\n\n- (void)setFilterAgeComparator:(TPI_ChatFilterAgeComparator)filterAgeComparator\n{\n\tif (self->_filterAgeComparator != filterAgeComparator) {\n\t\tself->_filterAgeComparator = filterAgeComparator;\n\t}\n}\n\n- (void)setFilterAgeLimit:(NSUInteger)filterAgeLimit\n{\n\tif (self->_filterAgeLimit != filterAgeLimit) {\n\t\tself->_filterAgeLimit = filterAgeLimit;\n\t}\n}\n\n- (void)setFilterActionFloodControlInterval:(NSUInteger)filterActionFloodControlInterval\n{\n\tif (self->_filterActionFloodControlInterval != filterActionFloodControlInterval) {\n\t\tself->_filterActionFloodControlInterval = filterActionFloodControlInterval;\n\t}\n}\n\n- (void)setFilterAction:(NSString *)filterAction\n{\n\tNSParameterAssert(filterAction != nil);\n\n\tif (self->_filterAction != filterAction) {\n\t\tself->_filterAction = [filterAction copy];\n\t}\n}\n\n- (void)setFilterForwardToDestination:(NSString *)filterForwardToDestination\n{\n\tNSParameterAssert(filterForwardToDestination != nil);\n\n\tif (self->_filterForwardToDestination != filterForwardToDestination) {\n\t\tself->_filterForwardToDestination = [filterForwardToDestination copy];\n\t}\n}\n\n- (void)setFilterMatch:(NSString *)filterMatch\n{\n\tNSParameterAssert(filterMatch != nil);\n\n\tif (self->_filterMatch != filterMatch) {\n\t\tself->_filterMatch = [filterMatch copy];\n\t}\n}\n\n- (void)setFilterNotes:(NSString *)filterNotes\n{\n\tNSParameterAssert(filterNotes != nil);\n\n\tif (self->_filterNotes != filterNotes) {\n\t\tself->_filterNotes = [filterNotes copy];\n\t}\n}\n\n- (void)setFilterSenderMatch:(NSString *)filterSenderMatch\n{\n\tNSParameterAssert(filterSenderMatch != nil);\n\n\tif (self->_filterSenderMatch != filterSenderMatch) {\n\t\tself->_filterSenderMatch = [filterSenderMatch copy];\n\t}\n}\n\n- (void)setFilterTitle:(NSString *)filterTitle\n{\n\tNSParameterAssert(filterTitle != nil);\n\n\tif (self->_filterTitle != filterTitle) {\n\t\tself->_filterTitle = [filterTitle copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterEditFilterSheet.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\n#import \"TPI_ChatFilter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TPI_ChatFilterActionTokenTag) {\n\tTPI_ChatFilterActionTokenTagChannelName = 1,\n\tTPI_ChatFilterActionTokenTagLocalNickname = 2,\n\tTPI_ChatFilterActionTokenTagNetworkName = 3,\n\tTPI_ChatFilterActionTokenOriginalMessage = 4,\n\tTPI_ChatFilterActionTokenTagSenderNickname = 5,\n\tTPI_ChatFilterActionTokenTagSenderAddress = 6,\n\tTPI_ChatFilterActionTokenTagSenderUsername = 7,\n\tTPI_ChatFilterActionTokenTagSenderHostmask = 8,\n\tTPI_ChatFilterActionTokenTagServerAddress = 9\n};\n\n@protocol TPI_ChatFilterEditFilterSheetDelegate;\n\n@interface TPI_ChatFilterEditFilterSheet : TDCSheetBase\n- (instancetype)initWithFilter:(nullable TPI_ChatFilter *)filter NS_DESIGNATED_INITIALIZER;\n\n- (void)start;\n@end\n\n@protocol TPI_ChatFilterEditFilterSheetDelegate <NSObject>\n@optional\n\n- (void)chatFilterEditFilterSheet:(TPI_ChatFilterEditFilterSheet *)sender onOk:(TPI_ChatFilter *)filter;\n- (void)chatFilterEditFilterSheetWillClose:(TPI_ChatFilterEditFilterSheet *)sender;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterEditFilterSheet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_ChatFilterEditFilterSheet.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, TPI_ChatFilterEditFilterSheetSelection)\n{\n\tTPI_ChatFilterEditFilterSheetSelectionGeneral = 0,\n\tTPI_ChatFilterEditFilterSheetSelectionChannels = 1,\n\tTPI_ChatFilterEditFilterSheetSelectionEvents = 2,\n\tTPI_ChatFilterEditFilterSheetSelectionSender = 3,\n\tTPI_ChatFilterEditFilterSheetSelectionNotes = 4,\n\tTPI_ChatFilterEditFilterSheetSelectionAdvanced = 5\n};\n\n@interface TPI_ChatFilterEditFilterSheet () <NSTokenFieldDelegate, NSOutlineViewDataSource, NSOutlineViewDelegate>\n@property (nonatomic, strong) TPI_ChatFilterMutable *filter;\n@property (nonatomic, weak) IBOutlet NSTabView *contentViewTabView;\n@property (nonatomic, weak) IBOutlet NSTextField *filterAgeLimitTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filterMatchTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filterSenderMatchTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filterTitleTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filterNotesTextField;\n@property (nonatomic, weak) IBOutlet NSTextField *filterActionFloodControlIntervalTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *filterEventNumericTextField;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *filterForwardToDestinationTextField;\n@property (nonatomic, weak) IBOutlet TVCAutoExpandingTokenField *filterActionTokenField;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenChannelName;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenLocalNickname;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenNetworkName;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenOriginalMessage;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenSenderAddress;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenSenderHostmask;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenSenderNickname;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenSenderUsername;\n@property (nonatomic, weak) IBOutlet NSTokenField *filterActionTokenServerAddress;\n@property (nonatomic, weak) IBOutlet NSView *filterLimitedToHostView;\n@property (nonatomic, weak) IBOutlet NSView *filterLimitedToSelectionHostView;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *filterAgeLimitComparatorButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterLimitToNoLimitButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterLimitToOnlyChannelsButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterLimitToOnlyPrivateMessagesButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterLimitToSpecificItemsButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterIgnoreContentCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterIgnoreOperatorsCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterLogMatchCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventPlainTextMessageCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventActionMessageCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventNoticeMessageCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventUserJoinedChannelCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventUserLeftChannelCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventUserKickedFromChannelCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventUserDisconnectedCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventUserChangedNicknameCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventChannelTopicReceivedCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventChannelTopicChangedCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventChannelModeReceivedCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterEventChannelModeChangedCheck;\n@property (nonatomic, weak) IBOutlet NSButton *filterLimitedToMyselfCheck;\n@property (nonatomic, assign) BOOL filterIgnoreOperatorsCheckEnabled;\n@property (nonatomic, copy) NSArray<NSString *> *filterActionAutoCompletedTokens;\n@property (nonatomic, strong) IBOutlet TVCChannelSelectionViewController *filterLimitToSelectionOutlineView;\n\n- (IBAction)viewFilterMatchHelpText:(id)sender;\n- (IBAction)viewFilterActionHelpText:(id)sender;\n- (IBAction)viewFilterSenderMatchHelpText:(id)sender;\n- (IBAction)viewFilterForwardToDestinationHelpText:(id)sender;\n\n- (IBAction)filterLimitedToMatrixChanged:(id)sender;\n- (IBAction)filterIgnoreContentCheckChanged:(id)sender;\n- (IBAction)filterEventTypeChanged:(id)sender;\n- (IBAction)filterLimitedToMyselfChanged:(id)sender;\n@end\n\n#pragma mark -\n\n@interface TPI_ChatFilterFilterActionToken : NSObject\n@property (nonatomic, copy) NSString *token;\n@property (nonatomic, copy, readonly, nullable) NSString *tokenTitle;\n\n+ (TPI_ChatFilterFilterActionToken *)tokenWithToken:(NSString *)token;\n+ (nullable TPI_ChatFilterFilterActionToken *)tokenWithTokenTitle:(NSString *)tokenTitle;\n\n+ (NSArray *)tokens;\n+ (NSArray *)tokenTitles;\n\n+ (nullable NSString *)titleForToken:(NSString *)token;\n\n+ (BOOL)isToken:(NSString *)token;\n@end\n\n#pragma mark -\n\n@implementation TPI_ChatFilterEditFilterSheet\n\n#pragma mark -\n#pragma mark Primary Sheet Structure\n\n- (instancetype)initWithFilter:(nullable TPI_ChatFilter *)filter\n{\n\tif ((self = [super initWithWindow:nil])) {\n\t\tif (filter == nil) {\n\t\t\tself.filter = [TPI_ChatFilterMutable new];\n\t\t} else {\n\t\t\tself.filter = [filter mutableCopy];\n\t\t}\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[TPIBundleFromClass() loadNibNamed:@\"TPI_ChatFilterEditFilterSheet\" owner:self topLevelObjects:nil];\n\n\t[self populateTokenFieldStringValues];\n\n\t[self setupTextFieldRules];\n\n\t[self loadFilter];\n\n\t[self updateEnabledStateOfSenderMatch];\n\t[self updateEnabledStateOfFilterEvents];\n\t[self updateEnableStateOfFilterActionTokenField];\n\t[self updateEnabledStateOfComponentsConstrainedByFilterEvents];\n\t[self updateFilterLimitedToMatrix];\n\t[self updateVisibilityOfLimitedToTableHostView];\n\n\t[self toggleOkButton];\n\n\t[self.filterLimitToSelectionOutlineView attachToView:self.filterLimitedToSelectionHostView];\n}\n\n- (void)start\n{\n\t[self startSheet];\n}\n\n- (void)loadFilter\n{\n\tself.filterMatchTextField.stringValue = self.filter.filterMatch;\n\n\t[self setTokens:self.filter.filterAction inTokenField:self.filterActionTokenField];\n\n\t[self.filterAgeLimitComparatorButton selectItemWithTag:self.filter.filterAgeComparator];\n\tself.filterAgeLimitTextField.integerValue = self.filter.filterAgeLimit;\n\n\tself.filterActionFloodControlIntervalTextField.integerValue = self.filter.filterActionFloodControlInterval;\n\n\tself.filterTitleTextField.stringValue = self.filter.filterTitle;\n\tself.filterNotesTextField.stringValue = self.filter.filterNotes;\n\n\tself.filterSenderMatchTextField.stringValue = self.filter.filterSenderMatch;\n\n\tself.filterForwardToDestinationTextField.stringValue = self.filter.filterForwardToDestination;\n\n\tself.filterIgnoreContentCheck.state = self.filter.filterIgnoreContent;\n\n\tself.filterLogMatchCheck.state = self.filter.filterLogMatch;\n\n\tself.filterLimitedToMyselfCheck.state = self.filter.filterLimitedToMyself;\n\n\tself.filterEventPlainTextMessageCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypePlainTextMessage];\n\tself.filterEventActionMessageCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeActionMessage];\n\tself.filterEventNoticeMessageCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeNoticeMessage];\n\tself.filterEventUserJoinedChannelCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeUserJoinedChannel];\n\tself.filterEventUserLeftChannelCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeUserLeftChannel];\n\tself.filterEventUserKickedFromChannelCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeUserKickedFromChannel];\n\tself.filterEventUserDisconnectedCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeUserDisconnected];\n\tself.filterEventUserChangedNicknameCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeUserChangedNickname];\n\tself.filterEventChannelTopicReceivedCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeChannelTopicReceived];\n\tself.filterEventChannelTopicChangedCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeChannelTopicChanged];\n\tself.filterEventChannelModeReceivedCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeChannelModeReceived];\n\tself.filterEventChannelModeChangedCheck.state = [self.filter isEventTypeEnabled:TPI_ChatFilterEventTypeChannelModeChanged];\n\n\tNSArray *filterEventsNumerics = self.filter.filterEventsNumerics;\n\n\tif (filterEventsNumerics) {\n\t\tNSString *filterEventsNumericsJoined = [filterEventsNumerics componentsJoinedByString:@\", \"];\n\n\t\tself.filterEventNumericTextField.stringValue = filterEventsNumericsJoined;\n\t} else {\n\t\t[self.filterEventNumericTextField performValidation];\n\t}\n\n\tNSArray *filterLimitedToClientsIDs = self.filter.filterLimitedToClientsIDs;\n\tNSArray *filterLimitedToChannelsIDs = self.filter.filterLimitedToChannelsIDs;\n\n\tself.filterLimitToSelectionOutlineView.selectedClientIds = filterLimitedToClientsIDs;\n\tself.filterLimitToSelectionOutlineView.selectedChannelIds = filterLimitedToChannelsIDs;\n}\n\n- (void)saveFilter\n{\n\tself.filter.filterMatch = self.filterMatchTextField.stringValue;\n\n\tNSString *filterActionStringValue = [self stringValueForTokenField:self.filterActionTokenField];\n\n\tself.filter.filterAction = filterActionStringValue;\n\n\tself.filter.filterAgeComparator = self.filterAgeLimitComparatorButton.selectedTag;\n\n\tNSInteger filterAgeLimit = self.filterAgeLimitTextField.integerValue;\n\n\tif (filterAgeLimit < 0) {\n\t\tfilterAgeLimit = 0;\n\t}\n\n\tself.filter.filterAgeLimit = filterAgeLimit;\n\n\tNSInteger filterActionFloodControlInterval = self.filterActionFloodControlIntervalTextField.integerValue;\n\n\tif (filterActionFloodControlInterval < 0) {\n\t\tfilterActionFloodControlInterval = 0;\n\t}\n\n\tself.filter.filterActionFloodControlInterval = filterActionFloodControlInterval;\n\n\tself.filter.filterTitle = self.filterTitleTextField.stringValue;\n\tself.filter.filterNotes = self.filterNotesTextField.stringValue;\n\n\tself.filter.filterSenderMatch = self.filterSenderMatchTextField.stringValue;\n\n\tself.filter.filterForwardToDestination = self.filterForwardToDestinationTextField.stringValue;\n\n\tself.filter.filterIgnoreOperators = (self.filterIgnoreOperatorsCheck.state == NSControlStateValueOn);\n\n\tself.filter.filterIgnoreContent = (self.filterIgnoreContentCheck.state == NSControlStateValueOn);\n\n\tself.filter.filterLogMatch = (self.filterLogMatchCheck.state == NSControlStateValueOn);\n\n\tself.filter.filterLimitedToMyself = (self.filterLimitedToMyselfCheck.state == NSControlStateValueOn);\n\n\tself.filter.filterEvents = [self compileFilterEvents];\n\n\tself.filter.filterEventsNumerics = [self compileFilterEventsNumericsOrReturnEmptyArray];\n\n\tself.filter.filterLimitedToClientsIDs = self.filterLimitToSelectionOutlineView.selectedClientIds;\n\tself.filter.filterLimitedToChannelsIDs = self.filterLimitToSelectionOutlineView.selectedChannelIds;\n}\n\n- (BOOL)filterIgnoreOperatorsCheckValue\n{\n\tif (self.filterIgnoreOperatorsCheckEnabled == NO) {\n\t\treturn NO;\n\t}\n\n\treturn self.filter.filterIgnoreOperators;\n}\n\n- (void)setFilterIgnoreOperatorsCheckValue:(BOOL)filterIgnoreOperatorsCheckValue\n{\n\tself.filter.filterIgnoreOperators = filterIgnoreOperatorsCheckValue;\n}\n\n- (NSArray<NSString *> *)compileFilterEventsNumericsOrReturnEmptyArray\n{\n\tNSArray *filterEventNumerics = [self compileFilterEventsNumerics];\n\n\tif (filterEventNumerics == nil) {\n\t\treturn @[];\n\t}\n\n\treturn filterEventNumerics;\n}\n\n- (nullable NSArray<NSString *> *)compileFilterEventsNumerics\n{\n\tNSString *numericsString = self.filterEventNumericTextField.value;\n\n\tNSArray *numerics = [numericsString componentsSeparatedByString:@\",\"];\n\n\tNSMutableArray *filterEventsNumerics = nil; // Create later so we don't waste memory if error.\n\n\tfor (__strong NSString *numeric in numerics) {\n\t\tnumeric = numeric.trim;\n\n\t\tif (numeric.length == 0) {\n\t\t\tcontinue; // Empty segment. We can ignore.\n\t\t}\n\n\t\tif (numeric.numericOnly) {\n\t\t\tif (numeric.length > 3) {\n\t\t\t\treturn nil; // Bad value, fail completely\n\t\t\t}\n\n\t\t\t// Convert to integer and back to remove leading zeros\n\t\t\tnumeric = [NSString stringWithFormat:@\"%ld\", numeric.integerValue];\n\t\t} else if (numeric.alphabeticNumericOnly) {\n\t\t\tif (numeric.length > 20) {\n\t\t\t\treturn nil; // Bad value, fail completely\n\t\t\t}\n\n\t\t\tnumeric = numeric.uppercaseString;\n\t\t} else {\n\t\t\treturn nil; // Bad value, fail completely\n\t\t}\n\n\t\tif (filterEventsNumerics == nil) {\n\t\t\tfilterEventsNumerics = [NSMutableArray array];\n\t\t}\n\n\t\tif ([filterEventsNumerics containsObject:numeric] == NO) {\n\t\t\t[filterEventsNumerics addObject:numeric];\n\t\t}\n\t}\n\n\treturn [filterEventsNumerics copy];\n}\n\n- (TPI_ChatFilterEventType)compileFilterEvents\n{\n\tTPI_ChatFilterEventType filterEvents = 0;\n\n\tif (self.filterEventPlainTextMessageCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypePlainTextMessage;\n\n\tif (self.filterEventActionMessageCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeActionMessage;\n\n\tif (self.filterEventNoticeMessageCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeNoticeMessage;\n\n\tif (self.filterEventUserJoinedChannelCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeUserJoinedChannel;\n\n\tif (self.filterEventUserLeftChannelCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeUserLeftChannel;\n\n\tif (self.filterEventUserKickedFromChannelCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeUserKickedFromChannel;\n\n\tif (self.filterEventUserDisconnectedCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeUserDisconnected;\n\n\tif (self.filterEventUserChangedNicknameCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeUserChangedNickname;\n\n\tif (self.filterEventChannelTopicReceivedCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeChannelTopicReceived;\n\n\tif (self.filterEventChannelTopicChangedCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeChannelTopicChanged;\n\n\tif (self.filterEventChannelModeReceivedCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeChannelModeReceived;\n\n\tif (self.filterEventChannelModeChangedCheck.state == NSControlStateValueOn)\n\t\tfilterEvents |= TPI_ChatFilterEventTypeChannelModeChanged;\n\n\treturn filterEvents;\n}\n\n- (void)ok:(id)sender\n{\n\tif ([self okOrError] == NO) {\n\t\treturn;\n\t}\n\n\t[self saveFilter];\n\n\tif ([self.delegate respondsToSelector:@selector(chatFilterEditFilterSheet:onOk:)]) {\n\t\t[self.delegate chatFilterEditFilterSheet:self onOk:[self.filter copy]];\n\t}\n\n\t[super ok:nil];\n}\n\n- (BOOL)okOrError\n{\n\tif ([self okOrErrorForTextField:self.filterEventNumericTextField inSelection:TPI_ChatFilterEditFilterSheetSelectionEvents] == NO) {\n\t\treturn NO;\n\t}\n\n\tif ([self okOrErrorForTextField:self.filterForwardToDestinationTextField inSelection:TPI_ChatFilterEditFilterSheetSelectionAdvanced] == NO) {\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)okOrErrorForTextField:(TVCValidatedTextField *)textField inSelection:(TPI_ChatFilterEditFilterSheetSelection)selection\n{\n\tif (textField.valueIsValid) {\n\t\treturn YES;\n\t}\n\n\t[self navigateToSelection:selection];\n\n\t/* Give navigation time to settle before trying to attach popover */\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[textField showValidationErrorPopover];\n\t});\n\n\treturn NO;\n}\n\n- (void)navigateToSelection:(TPI_ChatFilterEditFilterSheetSelection)selection\n{\n\tif (self.contentViewTabView.indexOfSelectedItem == selection) {\n\t\treturn;\n\t}\n\n\t[self.contentViewTabView selectTabViewItemAtIndex:selection];\n}\n\n- (void)windowWillClose:(NSNotification *)note\n{\n\t[RZNotificationCenter() removeObserver:self];\n\n\tif ([self.delegate respondsToSelector:@selector(chatFilterEditFilterSheetWillClose:)]) {\n\t\t[self.delegate chatFilterEditFilterSheetWillClose:self];\n\t}\n}\n\n#pragma mark -\n#pragma mark Token Field Delegate\n\n- (void)populateTokenFieldStringValues\n{\n\tNSCharacterSet *emptyCharacterSet = [NSCharacterSet characterSetWithCharactersInString:@\"\"];\n\n\tself.filterActionTokenField.tokenizingCharacterSet = emptyCharacterSet;\n\n\tself.filterActionTokenField.completionDelay = 0.2;\n\n\t[self setToken:@\"%_channelName_%\" inTokenField:self.filterActionTokenChannelName];\n\t[self setToken:@\"%_localNickname_%\" inTokenField:self.filterActionTokenLocalNickname];\n\t[self setToken:@\"%_networkName_%\" inTokenField:self.filterActionTokenNetworkName];\n\t[self setToken:@\"%_originalMessage_%\" inTokenField:self.filterActionTokenOriginalMessage];\n\t[self setToken:@\"%_senderNickname_%\" inTokenField:self.filterActionTokenSenderNickname];\n\t[self setToken:@\"%_senderUsername_%\" inTokenField:self.filterActionTokenSenderUsername];\n\t[self setToken:@\"%_senderAddress_%\" inTokenField:self.filterActionTokenSenderAddress];\n\t[self setToken:@\"%_senderHostmask_%\" inTokenField:self.filterActionTokenSenderHostmask];\n\t[self setToken:@\"%_serverAddress_%\" inTokenField:self.filterActionTokenServerAddress];\n}\n\n- (nullable NSArray *)tokenField:(NSTokenField *)tokenField readFromPasteboard:(NSPasteboard *)pboard\n{\n\tNSString *stringContent = pboard.stringContent;\n\n\treturn [self tokensFromString:stringContent];\n}\n\n- (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard\n{\n\tNSString *stringContent = [objects componentsJoinedByString:@\"\"];\n\n\tpboard.stringContent = stringContent;\n\n\treturn YES;\n}\n\n- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject\n{\n\tif ([representedObject isKindOfClass:[TPI_ChatFilterFilterActionToken class]]) {\n\t\treturn NSTokenStyleRounded;\n\t}\n\n\treturn NSTokenStyleNone;\n}\n\n- (nullable NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject\n{\n\tif ([representedObject isKindOfClass:[TPI_ChatFilterFilterActionToken class]]) {\n\t\treturn [representedObject tokenTitle];\n\t}\n\n\treturn representedObject;\n}\n\n- (nullable id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString\n{\n\tif (tokenField == self.filterActionTokenField) {\n\t\tNSArray *tokenTitles = [self.filterActionAutoCompletedTokens filteredArrayUsingPredicate:\n\t\t\t\t[NSPredicate predicateWithFormat:@\"SELF beginswith[cd] %@\", editingString]];\n\n\t\tif (tokenTitles.count > 0) {\n\t\t\tNSString *tokenTitle = tokenTitles.firstObject;\n\n\t\t\treturn [TPI_ChatFilterFilterActionToken tokenWithTokenTitle:tokenTitle];\n\t\t}\n\t}\n\n\treturn editingString;\n}\n\n- (nullable NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex indexOfSelectedItem:(nullable NSInteger *)selectedIndex\n{\n\tif (tokenField == self.filterActionTokenField) {\n\t\tNSArray *tokenTitles = [TPI_ChatFilterFilterActionToken tokenTitles];\n\n\t\tNSArray *tokenTitlesFiltered = [tokenTitles filteredArrayUsingPredicate:\n\t\t\t\t[NSPredicate predicateWithFormat:@\"SELF beginswith[cd] %@\", substring]];\n\n\t\tself.filterActionAutoCompletedTokens = tokenTitlesFiltered;\n\n\t\treturn tokenTitlesFiltered;\n\t}\n\n\treturn nil;\n}\n\n- (void)performFilterActionTokenCompletion\n{\n\n}\n\n- (NSString *)stringValueForTokenField:(NSTokenField *)tokenField\n{\n\treturn [tokenField.objectValue componentsJoinedByString:@\"\"];\n}\n\n- (void)setTokens:(NSString *)tokens inTokenField:(NSTokenField *)tokenField\n{\n\tNSArray *tokenObjects = [self tokensFromString:tokens];\n\n\ttokenField.objectValue = tokenObjects;\n}\n\n- (void)setToken:(NSString *)token inTokenField:(NSTokenField *)tokenField\n{\n\t TPI_ChatFilterFilterActionToken *tokenObject =\n\t[TPI_ChatFilterFilterActionToken tokenWithToken:token];\n\n\ttokenField.objectValue = @[tokenObject];\n}\n\n- (NSArray *)tokensFromString:(nullable NSString *)string\n{\n\tNSString *tokenString = string;\n\n\tif (tokenString == nil) {\n\t\treturn @[];\n\t}\n\n\tNSMutableArray *tokens = [NSMutableArray array];\n\n\tNSInteger currentPosition = 0;\n\n\tNSInteger tokenStringLength = tokenString.length;\n\n\twhile (currentPosition < tokenStringLength) {\n\t\tNSRange searchRange = NSMakeRange(currentPosition, (tokenStringLength - currentPosition));\n\n\t\tNSRange range = [tokenString rangeOfString:@\"%_([a-zA-Z0-9_]+)_%\"\n\t\t\t\t\t\t\t\t\t\t   options:NSRegularExpressionSearch\n\t\t\t\t\t\t\t\t\t\t\t range:searchRange];\n\n\t\tif (range.location == NSNotFound) {\n\t\t\tNSString *tokenStringPrefix = [tokenString substringWithRange:searchRange];\n\n\t\t\t[tokens addObject:tokenStringPrefix];\n\n\t\t\tbreak;\n\t\t}\n\n\t\tNSRange tokenStringPrefixRange = NSMakeRange(currentPosition, (range.location - currentPosition));\n\n\t\tif (tokenStringPrefixRange.length > 0) {\n\t\t\tNSString *tokenStringPrefix = [tokenString substringWithRange:tokenStringPrefixRange];\n\n\t\t\t[tokens addObject:tokenStringPrefix];\n\t\t}\n\n\t\tNSString *tokenStringToken = [tokenString substringWithRange:range];\n\n\t\tif ([TPI_ChatFilterFilterActionToken isToken:tokenStringToken]) {\n\t\t\t TPI_ChatFilterFilterActionToken *token =\n\t\t\t[TPI_ChatFilterFilterActionToken tokenWithToken:tokenStringToken];\n\n\t\t\t[tokens addObject:token];\n\t\t} else {\n\t\t\t[tokens addObject:tokenStringToken];\n\t\t}\n\n\t\tcurrentPosition = NSMaxRange(range);\n\t}\n\n\tif (tokens.count == 0) {\n\t\t[tokens addObject:tokenString];\n\t}\n\n\treturn tokens;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (BOOL)control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)commandSelector\n{\n\tif (control != self.filterActionTokenField && control != self.filterNotesTextField) {\n\t\treturn NO;\n\t}\n\n\tNSRange selectedRange = [textView selectedRange];\n\n\tif (selectedRange.length > 0) {\n\t\treturn NO;\n\t}\n\n\tif (commandSelector == @selector(insertNewline:))\n\t{\n\t\tNSRange editedRange = textView.textStorage.editedRange;\n\n\t\tif (editedRange.length > 1) {\n\t\t\treturn NO;\n\t\t}\n\n\t\t[textView insertNewlineIgnoringFieldEditor:self];\n\n\t\treturn YES;\n\t}\n\n\treturn NO;\n}\n\n- (void)controlTextDidChange:(NSNotification *)notification\n{\n\t[self toggleOkButton];\n}\n\n- (void)validatedTextFieldTextDidChange:(id)sender\n{\n\t[self toggleOkButton];\n}\n\n- (void)toggleOkButton\n{\n\tBOOL disabled = NO;\n\n\tif (self.filterTitleTextField.stringValue.length == 0) {\n\t\tdisabled = YES;\n\t}\n\n\tif (disabled == NO) {\n\t\tif (self.filterIgnoreContentCheck.state == NSControlStateValueOff &&\n\t\t\tself.filterForwardToDestinationTextField.stringValue.length == 0)\n\t\t{\n\t\t\tif (self.filterActionTokenField.stringValue.length == 0) {\n\t\t\t\tdisabled = YES;\n\t\t\t}\n\t\t}\n\t}\n\n\tself.okButton.enabled = (disabled == NO);\n}\n\n- (void)setupTextFieldRules\n{\n\t/* \"Forward To\" text field */\n\tself.filterForwardToDestinationTextField.textDidChangeCallback = self;\n\n\tself.filterForwardToDestinationTextField.performValidationWhenEmpty = NO;\n\n\tself.filterForwardToDestinationTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.filterForwardToDestinationTextField.stringValueIsTrimmed = YES;\n\tself.filterForwardToDestinationTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.filterForwardToDestinationTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif (currentValue.length > 125) {\n\t\t\treturn TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[m0u-tw]\");\n\t\t}\n\n\t\tif ([XRRegularExpression string:currentValue isMatchedByRegex:@\"^([a-zA-Z0-9\\\\-\\\\_\\\\s]+)$\"] == NO) {\n\t\t\treturn TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[5kd-jt]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n\n\t/* \"Numerics\" text field */\n\tself.filterEventNumericTextField.textDidChangeCallback = self;\n\n\tself.filterEventNumericTextField.performValidationWhenEmpty = NO;\n\n\tself.filterEventNumericTextField.stringValueIsInvalidOnEmpty = NO;\n\tself.filterEventNumericTextField.stringValueIsTrimmed = NO;\n\tself.filterEventNumericTextField.stringValueUsesOnlyFirstToken = NO;\n\n\tself.filterEventNumericTextField.validationBlock = ^NSString *(NSString *currentValue) {\n\t\tif ([self compileFilterEventsNumerics] == nil) {\n\t\t\treturn TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[9ri-sd]\");\n\t\t}\n\n\t\treturn nil;\n\t};\n}\n\n- (void)updateVisibilityOfLimitedToTableHostView\n{\n\tif (self.filter.filterLimitedToValue == TPI_ChatFilterLimitToValueSpecificItems) {\n\t\tself.filterLimitedToHostView.hidden = NO;\n\t} else {\n\t\tself.filterLimitedToHostView.hidden = YES;\n\t}\n}\n\n- (void)updateEnableStateOfFilterActionTokenField\n{\n\n}\n\n- (void)updateEnabledStateOfFilterEvents\n{\n\tBOOL enabled = (self.filter.filterLimitedToValue != TPI_ChatFilterLimitToValuePrivateMessages);\n\n\tself.filterEventUserJoinedChannelCheck.enabled = enabled;\n\tself.filterEventUserLeftChannelCheck.enabled = enabled;\n\tself.filterEventUserKickedFromChannelCheck.enabled = enabled;\n\tself.filterEventUserDisconnectedCheck.enabled = enabled;\n\tself.filterEventUserChangedNicknameCheck.enabled = enabled;\n\tself.filterEventChannelTopicReceivedCheck.enabled = enabled;\n\tself.filterEventChannelTopicChangedCheck.enabled = enabled;\n\tself.filterEventChannelModeReceivedCheck.enabled = enabled;\n\tself.filterEventChannelModeChangedCheck.enabled = enabled;\n}\n\n- (void)updateEnabledStateOfComponentsConstrainedByFilterEvents\n{\n\tBOOL enabled = (self.filterEventPlainTextMessageCheck.state == NSControlStateValueOn ||\n\t\t\t\t\tself.filterEventActionMessageCheck.state == NSControlStateValueOn ||\n\t\t\t\t\tself.filterEventNoticeMessageCheck.state == NSControlStateValueOn);\n\n\tself.filterIgnoreOperatorsCheckEnabled = enabled;\n\n\t[self willChangeValueForKey:@\"filterIgnoreOperatorsCheckValue\"];\n\t[self didChangeValueForKey:@\"filterIgnoreOperatorsCheckValue\"];\n}\n\n- (void)updateEnabledStateOfSenderMatch\n{\n\tBOOL enabled = (self.filterLimitedToMyselfCheck.state == NSControlStateValueOff);\n\n\tself.filterSenderMatchTextField.enabled = enabled;\n}\n\n- (void)updateFilterLimitedToMatrix\n{\n\tTPI_ChatFilterLimitToValue limitedTo = self.filter.filterLimitedToValue;\n\n\tself.filterLimitToNoLimitButton.state = (limitedTo == TPI_ChatFilterLimitToValueNoLimit);\n\tself.filterLimitToOnlyChannelsButton.state = (limitedTo == TPI_ChatFilterLimitToValueChannels);\n\tself.filterLimitToOnlyPrivateMessagesButton.state = (limitedTo == TPI_ChatFilterLimitToValuePrivateMessages);\n\tself.filterLimitToSpecificItemsButton.state = (limitedTo == TPI_ChatFilterLimitToValueSpecificItems);\n}\n\n- (void)filterLimitedToMyselfChanged:(id)sender\n{\n\t[self updateEnabledStateOfSenderMatch];\n}\n\n- (void)filterEventTypeChanged:(id)sender\n{\n\t[self updateEnabledStateOfComponentsConstrainedByFilterEvents];\n}\n\n- (void)viewFilterMatchHelpText:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Introduction-to-the-Chat-Filter-Addon.kb#faq-entry-1\" inBackground:NO];\n}\n\n- (void)viewFilterActionHelpText:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Introduction-to-the-Chat-Filter-Addon.kb#faq-entry-2\" inBackground:NO];\n}\n\n- (void)viewFilterSenderMatchHelpText:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Introduction-to-the-Chat-Filter-Addon.kb#faq-entry-3\" inBackground:NO];\n}\n\n- (void)viewFilterForwardToDestinationHelpText:(id)sender\n{\n\t[TLOpenLink openWithString:@\"https://help.codeux.com/textual/Introduction-to-the-Chat-Filter-Addon.kb#faq-entry-4\" inBackground:NO];\n}\n\n- (void)filterLimitedToMatrixChanged:(id)sender\n{\n\tself.filter.filterLimitedToValue = [sender tag];\n\n\t[self updateVisibilityOfLimitedToTableHostView];\n\n\t[self updateEnabledStateOfFilterEvents];\n}\n\n- (void)filterIgnoreContentCheckChanged:(id)sender\n{\n\t[self updateEnableStateOfFilterActionTokenField];\n\n\t[self toggleOkButton];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Token Object\n\n@implementation TPI_ChatFilterFilterActionToken\n\n+ (TPI_ChatFilterFilterActionToken *)tokenWithToken:(NSString *)token\n{\n\tTPI_ChatFilterFilterActionToken *tokenField = [TPI_ChatFilterFilterActionToken new];\n\n\ttokenField.token = token;\n\n\treturn tokenField;\n}\n\n+ (nullable TPI_ChatFilterFilterActionToken *)tokenWithTokenTitle:(NSString *)tokenTitle\n{\n\tNSArray *tokenTitles = [TPI_ChatFilterFilterActionToken tokenTitles];\n\n\tNSInteger tokenTitleIndex = [tokenTitles indexOfObject:tokenTitle];\n\n\tif (tokenTitleIndex == NSNotFound) {\n\t\treturn nil;\n\t}\n\n\tNSArray *tokens = [TPI_ChatFilterFilterActionToken tokens];\n\n\tNSString *token = tokens[tokenTitleIndex];\n\n\treturn [TPI_ChatFilterFilterActionToken tokenWithToken:token];\n}\n\n+ (BOOL)isToken:(NSString *)token\n{\n\tNSArray *tokens = [TPI_ChatFilterFilterActionToken tokens];\n\n\treturn ([tokens indexOfObject:token] != NSNotFound);\n}\n\n+ (NSArray<NSString *> *)tokens\n{\n\t/* The index of this array should match the index of -tokenTitles */\n\tstatic NSArray *tokens = nil;\n\n\tif (tokens == nil) {\n\t\ttokens = @[\n\t\t   @\"%_channelName_%\",\n\t\t   @\"%_localNickname_%\",\n\t\t   @\"%_networkName_%\",\n\t\t   @\"%_originalMessage_%\",\n\t\t   @\"%_senderNickname_%\",\n\t\t   @\"%_senderUsername_%\",\n\t\t   @\"%_senderAddress_%\",\n\t\t   @\"%_senderHostmask_%\",\n\t\t   @\"%_serverAddress_%\",\n\t\t   @\"%_Parameter_0_%\",\n\t\t   @\"%_Parameter_1_%\",\n\t\t   @\"%_Parameter_2_%\",\n\t\t   @\"%_Parameter_3_%\",\n\t\t   @\"%_Parameter_4_%\",\n\t\t   @\"%_Parameter_5_%\",\n\t\t   @\"%_Parameter_6_%\",\n\t\t   @\"%_Parameter_7_%\",\n\t\t   @\"%_Parameter_8_%\"\n\t\t];\n\t}\n\n\treturn tokens;\n}\n\n+ (NSArray<NSString *> *)tokenTitles\n{\n\t/* The index of this array should match the index of -tokens */\n\tstatic NSArray *tokens = nil;\n\n\tif (tokens == nil) {\n\t\ttokens = @[\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[90e-tj]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[tbc-wc]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[840-f9]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[sch-hi]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[k82-6i]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[2sk-ui]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[xt2-bv]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[je5-u2]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[9xy-vf]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[kph-dc]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[8bd-nt]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[4vk-v8]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[kvz-ej]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[2pa-ju]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[jen-7o]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[t5v-4o]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[vyf-el]\"),\n\t\t   TPILocalizedString(@\"TPI_ChatFilterEditFilterSheet[0x4-ib]\")\n\t\t];\n\t}\n\n\treturn tokens;\n}\n\n+ (nullable NSString *)titleForToken:(NSString *)token\n{\n\tNSArray *tokens = [TPI_ChatFilterFilterActionToken tokens];\n\n\tNSInteger tokenIndex = [tokens indexOfObject:token];\n\n\tif (tokenIndex == NSNotFound) {\n\t\treturn nil;\n\t}\n\n\tNSArray *tokenTitles = [TPI_ChatFilterFilterActionToken tokenTitles];\n\n\treturn tokenTitles[tokenIndex];\n}\n\n- (nullable NSString *)tokenTitle\n{\n\treturn [TPI_ChatFilterFilterActionToken titleForToken:self.token];\n}\n\n- (NSString *)description\n{\n\treturn self.token;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterExtension.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_ChatFilterExtension : NSObject <THOPluginProtocol>\n@property (readonly) NSArrayController *filterArrayController;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterExtension.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_ChatFilterExtension.h\"\n#import \"TPI_ChatFilterEditFilterSheet.h\"\n#import \"TPI_ChatFilterLogic.h\"\n\n#import \"THOPluginProtocolPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _filterTableDragToken\t\t\t@\"filterTableDragToken\"\n\n#define _filterListUserDefaultsKey\t\t@\"Textual Chat Filter Extension -> Filters\"\n\n@interface TPI_ChatFilterExtension () <NSTableViewDataSource, NSTableViewDelegate>\n@property (nonatomic, strong) IBOutlet NSView *preferencesPaneView;\n@property (nonatomic, strong) IBOutlet NSMenu *filterAddMenu;\n@property (nonatomic, weak) IBOutlet NSButton *filterAddButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterRemoveButton;\n@property (nonatomic, weak) IBOutlet NSButton *filterEditButton;\n@property (nonatomic, weak) IBOutlet TVCBasicTableView *filterTable;\n@property (nonatomic, strong, readwrite) IBOutlet NSArrayController *filterArrayController;\n@property (nonatomic, assign) BOOL atleastOneFilterExists;\n@property (nonatomic, assign) NSInteger activeChatFilterIndex;\n@property (nonatomic, strong) TPI_ChatFilterEditFilterSheet *activeChatFilterEditSheet;\n@property (nonatomic, strong) TPI_ChatFilterLogic *filterLogicController;\n@property (nonatomic, assign) BOOL savingFilters;\n\n- (IBAction)filterTableDoubleClicked:(id)sender;\n\n- (IBAction)presentFilterAddMenu:(id)sender;\n\n- (IBAction)filterAdd:(id)sender;\n- (IBAction)filterRemove:(id)sender;\n- (IBAction)filterEdit:(id)sender;\n- (IBAction)filterDuplicate:(id)sender;\n- (IBAction)filterExport:(id)sender;\n- (IBAction)filterImport:(id)sender;\n@end\n\n@implementation TPI_ChatFilterExtension\n\n#pragma mark -\n#pragma mark Filter Logic\n\n- (BOOL)receivedCommand:(NSString *)command withText:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt referenceMessage:(nullable IRCMessage *)referenceMessage\n{\n\treturn [self.filterLogicController receivedCommand:command withText:text authoredBy:textAuthor destinedFor:textDestination onClient:client receivedAt:receivedAt referenceMessage:referenceMessage];\n}\n\n- (BOOL)receivedText:(NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination asLineType:(TVCLogLineType)lineType onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt wasEncrypted:(BOOL)wasEncrypted\n{\n\treturn [self.filterLogicController receivedText:text authoredBy:textAuthor destinedFor:textDestination asLineType:lineType onClient:client receivedAt:receivedAt wasEncrypted:wasEncrypted];\n}\n\n#pragma mark -\n#pragma mark Internal Filter List Storage\n\n- (void)reloadFilters\n{\n\t[self.filterArrayController removeAllArrangedObjects];\n\n\t[self loadFilters];\n\n\t[self.filterLogicController reloadFilterActionPerforms];\n}\n\n- (void)loadFilters\n{\n\tNSArray *filterConfigurations = [RZUserDefaults() arrayForKey:_filterListUserDefaultsKey];\n\n\tfor (id filterConfiguration in filterConfigurations) {\n\t\tif ([filterConfiguration isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tTPI_ChatFilter *filter = [[TPI_ChatFilter alloc] initWithDictionary:filterConfiguration];\n\n\t\t[self.filterArrayController addObject:filter];\n\t}\n\n\t[self reloadFilterCount];\n}\n\n- (void)saveFilters\n{\n\tself.savingFilters = YES;\n\n\tNSArray *filters = self.filterArrayController.arrangedObjects;\n\n\tNSMutableArray *filterConfigurations = [NSMutableArray arrayWithCapacity:filters.count];\n\n\tfor (TPI_ChatFilter *filter in filters) {\n\t\t[filterConfigurations addObject:filter.dictionaryValue];\n\t}\n\n\t[RZUserDefaults() setObject:[filterConfigurations copy] forKey:_filterListUserDefaultsKey];\n\n\t[self reloadFilterCount];\n}\n\n- (void)reloadFilterCount\n{\n\tNSArray *arrangedObjects = self.filterArrayController.arrangedObjects;\n\n\tself.atleastOneFilterExists = (arrangedObjects.count > 0);\n}\n\n- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString *, id> *)change context:(nullable void *)context\n{\n\tif ([keyPath isEqualToString:_filterListUserDefaultsKey]) {\n\t\tif (self.savingFilters) {\n\t\t\tself.savingFilters = NO;\n\n\t\t\treturn;\n\t\t}\n\n\t\t[self reloadFilters];\n\t}\n}\n\n#pragma mark -\n#pragma mark Preference Pane\n\n- (void)pluginLoadedIntoMemory\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\tNSAssert([TPIBundleFromClass() loadNibNamed:@\"TPI_ChatFilterExtension\" owner:self topLevelObjects:nil],\n\t\t\t@\"Failed to load user interface\");\n\t});\n\n\tself.activeChatFilterIndex = (-1);\n\n\tself.atleastOneFilterExists = NO;\n\n\tself.filterLogicController = [[TPI_ChatFilterLogic alloc] initWithParentObject:self];\n\n\t[self loadFilters];\n\n\t[RZUserDefaults() addObserver:self forKeyPath:_filterListUserDefaultsKey options:NSKeyValueObservingOptionNew context:NULL];\n}\n\n- (void)pluginWillBeUnloadedFromMemory\n{\n\tself.filterLogicController = nil;\n\n\t[RZUserDefaults() removeObserver:self forKeyPath:_filterListUserDefaultsKey];\n}\n\n- (NSView *)pluginPreferencesPaneView\n{\n\treturn self.preferencesPaneView;\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn TPILocalizedString(@\"TPI_ChatFilterExtension[jq1-6r]\");\n}\n\n- (void)awakeFromNib\n{\n\t[self.filterTable registerForDraggedTypes:@[_filterTableDragToken]];\n}\n\n- (void)filterTableDoubleClicked:(id)sender\n{\n\t[self filterEdit:sender];\n}\n\n- (void)filterAdd:(id)sender\n{\n\t[self editFilter:nil];\n}\n\n- (void)filterRemove:(id)sender\n{\n\tBOOL performRemove = [TDCAlert modalAlertWithMessage:TPILocalizedString(@\"TPI_ChatFilterExtension[dj6-fn]\")\n\t\t\t\t\t\t\t\t\t\t\t\t   title:TPILocalizedString(@\"TPI_ChatFilterExtension[c0k-xj]\")\n\t\t\t\t\t\t\t\t\t\t   defaultButton:TPILocalizedString(@\"TPI_ChatFilterExtension[jvu-m7]\")\n\t\t\t\t\t\t\t\t\t\t alternateButton:TPILocalizedString(@\"TPI_ChatFilterExtension[p5s-ff]\")];\n\n\tif (performRemove == NO) {\n\t\treturn;\n\t}\n\n\tNSInteger selectedRow = self.filterTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\t[self.filterArrayController removeObjectAtArrangedObjectIndex:selectedRow];\n\n\t[self saveFilters];\n}\n\n- (void)filterEdit:(id)sender\n{\n\tNSInteger selectedRow = self.filterTable.selectedRow;\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\tTPI_ChatFilter *filter = self.filterArrayController.arrangedObjects[selectedRow];\n\n\t[self editFilter:filter atIndex:selectedRow];\n}\n\n- (void)editFilter:(id)filter\n{\n\t[self editFilter:filter atIndex:(-1)];\n}\n\n- (void)editFilter:(id)filter atIndex:(NSInteger)filterIndex\n{\n\tself.activeChatFilterIndex = filterIndex;\n\n\tTPI_ChatFilterEditFilterSheet *sheet =\n\t[[TPI_ChatFilterEditFilterSheet alloc] initWithFilter:filter];\n\n\tsheet.delegate = self;\n\n\tsheet.window = [NSApp keyWindow];\n\n\t[sheet start];\n\n\tself.activeChatFilterEditSheet = sheet;\n}\n\n- (void)chatFilterEditFilterSheet:(TPI_ChatFilterEditFilterSheet *)sender onOk:(TPI_ChatFilter *)filter\n{\n\tif ([filter isKindOfClass:[TPI_ChatFilterMutable class]]) {\n\t\tfilter = [filter copy];\n\t}\n\n\tif (self.activeChatFilterIndex < 0) {\n\t\t[self.filterArrayController addObject:filter];\n\t} else {\n\t\t[self.filterArrayController replaceObjectAtArrangedObjectIndex:self.activeChatFilterIndex withObject:filter];\n\t}\n\n\t[self saveFilters];\n\n\t[self.filterLogicController reloadFilterActionPerforms];\n}\n\n- (void)chatFilterEditFilterSheetWillClose:(TPI_ChatFilterEditFilterSheet *)sender\n{\n\tself.activeChatFilterIndex = (-1);\n\n\tself.activeChatFilterEditSheet = nil;\n}\n\n- (void)filterDuplicate:(id)sender\n{\n\tNSInteger selectedRow = self.filterTable.selectedRow;\n\n\tTPI_ChatFilter *filter = self.filterArrayController.arrangedObjects[selectedRow];\n\n\tTPI_ChatFilterMutable *filterNew = [filter mutableCopy];\n\n\tfilterNew.filterTitle = [filterNew.filterTitle stringByAppendingString:@\" (Duplicate)\"];\n\n\t[self editFilter:[filterNew copy] atIndex:(-1)];\n}\n\n- (void)filterExport:(id)sender\n{\n\tNSInteger selectedRow = self.filterTable.selectedRow;\n\n\tTPI_ChatFilter *filter = self.filterArrayController.arrangedObjects[selectedRow];\n\n\tNSSavePanel *saveDialog = [NSSavePanel savePanel];\n\n\tsaveDialog.canCreateDirectories = YES;\n\n\tsaveDialog.nameFieldStringValue = TXLocalizationNotNeeded(@\"filter.plist\");\n\n\t[saveDialog beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode != NSModalResponseOK) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSURL *pathURL = saveDialog.URL;\n\n\t\t[filter writeToURL:pathURL];\n\t}];\n}\n\n- (void)filterImport:(id)sender\n{\n\tNSOpenPanel *openDialog = [NSOpenPanel openPanel];\n\n\topenDialog.allowsMultipleSelection = NO;\n\topenDialog.canChooseDirectories = NO;\n\topenDialog.canChooseFiles = YES;\n\topenDialog.canCreateDirectories = NO;\n\topenDialog.resolvesAliases = YES;\n\n\topenDialog.message = TPILocalizedString(@\"TPI_ChatFilterExtension[i9c-s3]\");\n\n\topenDialog.prompt = TPILocalizedString(@\"TPI_ChatFilterExtension[2tc-m7]\");\n\n\t[openDialog beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSInteger returnCode) {\n\t\tif (returnCode != NSModalResponseOK) {\n\t\t\treturn;\n\t\t}\n\n\t\t[openDialog orderOut:nil];\n\n\t\tNSURL *pathURL = openDialog.URL;\n\n\t\tTPI_ChatFilter *filter = [[TPI_ChatFilter alloc] initWithContentsOfURL:pathURL];\n\n\t\tif (filter == nil) {\n\t\t\t[TDCAlert modalAlertWithMessage:@\"\"\n\t\t\t\t\t\t\t\t\t  title:TPILocalizedString(@\"TPI_ChatFilterExtension[eqr-7t]\")\n\t\t\t\t\t\t\t  defaultButton:TPILocalizedString(@\"TPI_ChatFilterExtension[ybz-7i]\")\n\t\t\t\t\t\t\talternateButton:nil];\n\n\t\t\treturn;\n\t\t}\n\n\t\t[self editFilter:filter];\n\t}];\n}\n\n- (void)presentFilterAddMenu:(id)sender\n{\n\t[self.filterAddMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(0, 0) inView:sender];\n}\n\n#pragma mark -\n#pragma mark Table View Delegate\n\n- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard\n{\n\tNSData *draggedData = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];\n\n\t[pasteboard declareTypes:@[_filterTableDragToken] owner:self];\n\n\t[pasteboard setData:draggedData forType:_filterTableDragToken];\n\n\treturn YES;\n}\n\n- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation\n{\n\treturn NSDragOperationGeneric;\n}\n\n- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation\n{\n\tNSPasteboard *pasteboard = [info draggingPasteboard];\n\n\tNSData *draggedData = [pasteboard dataForType:_filterTableDragToken];\n\n\tNSIndexSet *draggedRowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:draggedData];\n\n\tNSUInteger draggedRowIndex = draggedRowIndexes.firstIndex;\n\n\t[self.filterArrayController moveObjectAtArrangedObjectIndex:draggedRowIndex toIndex:row];\n\n\t[self saveFilters];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_ChatFilter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_ChatFilter ()\n{\n@protected\n\tBOOL _filterIgnoreContent;\n\tBOOL _filterIgnoreOperators;\n\tBOOL _filterLogMatch;\n\tBOOL _filterLimitedToMyself;\n\tTPI_ChatFilterEventType _filterEvents;\n\tTPI_ChatFilterLimitToValue _filterLimitedToValue;\n\tTPI_ChatFilterAgeComparator _filterAgeComparator;\n\tNSUInteger _filterAgeLimit;\n\tNSUInteger _filterActionFloodControlInterval;\n\tNSArray<NSString *> *_filterLimitedToChannelsIDs;\n\tNSArray<NSString *> *_filterLimitedToClientsIDs;\n\tNSArray<NSString *> *_filterEventsNumerics;\n\tNSString *_filterAction;\n\tNSString *_filterForwardToDestination;\n\tNSString *_filterMatch;\n\tNSString *_filterNotes;\n\tNSString *_filterSenderMatch;\n\tNSString *_filterTitle;\n\n@private\n\tNSString *_uniqueIdentifier;\n\tNSDictionary *_defaults;\n\tNSCache *_cachedIsCommandEnabledResponses;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterLogic.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\n#import \"TPI_ChatFilter.h\"\n#import \"TPI_ChatFilterExtension.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_ChatFilterLogic : NSObject <THOPluginProtocol>\n- (instancetype)initWithParentObject:(TPI_ChatFilterExtension *)parentObject;\n\n- (void)reloadFilterActionPerforms;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_ChatFilterLogic.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_ChatFilterLogic.h\"\n\n#import \"IRCClientPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_ChatFilterLogic ()\n@property (nonatomic, weak) TPI_ChatFilterExtension *parentObject;\n@property (nonatomic, strong) NSMutableDictionary<NSString *, NSNumber *> *filterActionLastPerforms;\n@end\n\n@implementation TPI_ChatFilterLogic\n\n- (instancetype)initWithParentObject:(TPI_ChatFilterExtension *)parentObject\n{\n\tNSParameterAssert(parentObject != nil);\n\n\tif ((self = [super init])) {\n\t\tself.parentObject = parentObject;\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.filterActionLastPerforms = [NSMutableDictionary dictionary];\n}\n\n- (BOOL)testFilterDestination:(TPI_ChatFilter *)filter authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client\n{\n\t/* Try to resolve destination channel now that we\n\t know that there is a filter that will need it. */\n\tTPI_ChatFilterLimitToValue filterLimitedToValue = filter.filterLimitedToValue;\n\n\tif (filterLimitedToValue != TPI_ChatFilterLimitToValueNoLimit || filter.filterIgnoreOperators) {\n\t\tif (textDestination == nil && textAuthor.isServer == NO) {\n\t\t\tLogToConsoleDebugWithSubsystem(THOPluginLoggingSubsystem(),\n\t\t\t\t\"textDestination == nil — Returning input instead of continuing with filter\");\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\tif (filterLimitedToValue == TPI_ChatFilterLimitToValueChannels) {\n\t\tif (textDestination.isChannel == NO) {\n\t\t\t/* Filter is limited to a channel but the destination\n\t\t\t is not a channel. */\n\n\t\t\treturn NO;\n\t\t}\n\t} else if (filterLimitedToValue == TPI_ChatFilterLimitToValuePrivateMessages) {\n\t\tif (textDestination.isPrivateMessage == NO) {\n\t\t\t/* Filter is limited to a private message but the destination\n\t\t\t is not a private message. */\n\n\t\t\treturn NO;\n\t\t}\n\t} else if (filterLimitedToValue == TPI_ChatFilterLimitToValueSpecificItems) {\n\t\tNSArray *filterLimitedToClientsIDs = filter.filterLimitedToClientsIDs;\n\t\tNSArray *filterLimitedToChannelsIDs = filter.filterLimitedToChannelsIDs;\n\n\t\tif ([filterLimitedToClientsIDs containsObject:client.uniqueIdentifier] == NO &&\n\t\t\t[filterLimitedToChannelsIDs containsObject:textDestination.uniqueIdentifier] == NO)\n\t\t{\n\t\t\t/* Target channel is not covered by current filter. */\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)testFilterSender:(TPI_ChatFilter *)filter authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client\n{\n\t/* Check whether the sender is myself */\n\tif (filter.filterLimitedToMyself) {\n\t\tNSString *comparisonValue1 = client.userNickname;\n\n\t\tNSString *comparisonValue2 = textAuthor.nickname;\n\n\t\tif ([comparisonValue1 isEqualToStringIgnoringCase:comparisonValue2] == NO) {\n\t\t\treturn NO;\n\t\t}\n\n\t\treturn YES;\n\t}\n\n\t/* Maybe perform filter action on sender hostmask */\n\tNSString *filterSenderMatch = filter.filterSenderMatch;\n\n\tif (filterSenderMatch.length > 0) {\n\t\tNSString *comparisonHostmask = nil;\n\n\t\tif (textAuthor.isServer) {\n\t\t\tcomparisonHostmask = textAuthor.nickname; // Server address\n\t\t} else {\n\t\t\tcomparisonHostmask = textAuthor.hostmask;\n\t\t}\n\n\t\tif ([XRRegularExpression string:comparisonHostmask isMatchedByRegex:filterSenderMatch withoutCase:YES] == NO) {\n\t\t\t/* If a filter specifies a sender match and the match for\n\t\t\t this particular filter fails, then skip this filter. */\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\t/* For the next few checks we can ignore them if destination is not a channel. */\n\tif (textDestination.isChannel == NO || textAuthor.isServer) {\n\t\treturn YES;\n\t}\n\n\tIRCChannelUser *senderUser = [textDestination findMember:textAuthor.nickname];\n\n\t/* Check age of sender */\n\tNSInteger filterAgeLimit = filter.filterAgeLimit;\n\n\tif (filterAgeLimit > 0) {\n\t\t/* The value of senderUser is checked here and not where it is\n\t\t declared so that filters that do not rely on the value of this\n\t\t object are passed over. */\n\t\tif (senderUser == nil) {\n\t\t\treturn NO;\n\t\t}\n\n\t\tNSInteger ageLimitDelta = [NSDate timeIntervalSinceNow:senderUser.creationTime];\n\n\t\tswitch (filter.filterAgeComparator) {\n\t\t\tcase TPI_ChatFilterAgeComparatorLessThan:\n\t\t\t{\n\t\t\t\tif (ageLimitDelta < filterAgeLimit) {\n\t\t\t\t\treturn NO; // ignore this filter\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase TPI_ChatFilterAgeComparatorGreaterThan:\n\t\t\t{\n\t\t\t\tif (ageLimitDelta >= filterAgeLimit) {\n\t\t\t\t\treturn NO; // ignore this filter\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} // switch()\n\t}\n\n\t/* Is sender an operator? */\n\tif (filter.filterIgnoreOperators) {\n\t\tif (senderUser == nil) {\n\t\t\treturn NO;\n\t\t}\n\n\t\tif (senderUser.halfOp) {\n\t\t\t/* User is at least a Half-op, ignore this filter. */\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)testFilterMatch:(TPI_ChatFilter *)filter againstText:(nullable NSString *)text allowingNilText:(BOOL)allowingNilText\n{\n\t/* Filter text */\n\tif (text == nil) {\n\t\tif (allowingNilText) {\n\t\t\treturn YES;\n\t\t} else {\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\tNSString *filterMatch = filter.filterMatch;\n\n\tif (filterMatch.length > 0) {\n\t\tif ([TPCPreferences removeAllFormatting] == NO) {\n\t\t\ttext = text.stripIRCEffects;\n\t\t}\n\n\t\tif ([XRRegularExpression string:text isMatchedByRegex:filterMatch withoutCase:YES] == NO) {\n\t\t\t/* The input text is not matched by the filter match.\n\t\t\t Continue to the next filter to try again. */\n\n\t\t\treturn NO;\n\t\t}\n\t}\n\n\treturn YES;\n}\n\n- (BOOL)receivedCommand:(NSString *)command withText:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt referenceMessage:(nullable IRCMessage *)referenceMessage\n{\n\t/* Begin processing filters */\n\tNSArray *filters = self.parentObject.filterArrayController.content;\n\n\tfor (TPI_ChatFilter *filter in filters) {\n\t\t@autoreleasepool {\n\t\t\tif ([filter isCommandEnabled:command] == NO) {\n\t\t\t\t/* Continue to next filter. This filter is not interested\n\t\t\t\t in the line type of the input. */\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Perform common filter checks */\n\t\t\tif ([self testFilterDestination:filter authoredBy:textAuthor destinedFor:textDestination onClient:client] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([self testFilterSender:filter authoredBy:textAuthor destinedFor:textDestination onClient:client] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([self testFilterMatch:filter againstText:text allowingNilText:YES] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Perform actions defined by filter */\n\t\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t\t[self performActionForFilter:filter\n\t\t\t\t\t\t withOriginalMessage:text\n\t\t\t\t\t\t\t\t  authoredBy:textAuthor\n\t\t\t\t\t\t\t\t destinedFor:textDestination\n\t\t\t\t\t\t\t\t\tonClient:client\n\t\t\t\t\t\t\treferenceMessage:referenceMessage];\n\t\t\t});\n\n\t\t\t/* Forward a copy of the message to a query? */\n\t\t\tNSString *filterForwardToDestination = filter.filterForwardToDestination;\n\n\t\t\tif (filterForwardToDestination.length > 0 && text.length > 0) {\n\t\t\t\tIRCChannel *destinationChannel = [client findChannelOrCreate:filterForwardToDestination isPrivateMessage:YES];\n\n\t\t\t\tNSString *message = TPILocalizedString(@\"TPI_ChatFilterLogic[dct-7h]\", command, text);\n\n\t\t\t\t[client print:message\n\t\t\t\t\t\t   by:nil\n\t\t\t\t\tinChannel:destinationChannel\n\t\t\t\t\t   asType:TVCLogLineTypeDebug\n\t\t\t\t\t  command:TVCLogLineDefaultCommandValue\n\t\t\t\t   receivedAt:receivedAt\n\t\t\t\t  isEncrypted:NO\n\t\t\t referenceMessage:nil\n\t\t\t\t completionBlock:^(TVCLogControllerPrintOperationContext *context) {\n\t\t\t\t\t [client setUnreadStateForChannel:destinationChannel];\n\t\t\t\t }];\n\t\t\t}\n\n\t\t\tif (filter.filterIgnoreContent) {\n\t\t\t\treturn NO; // Ignore original content\n\t\t\t}\n\n\t\t\t/* Return once the first filter matches */\n\t\t\treturn YES;\n\t\t} // @autorelease\n\t} // for\n\n\treturn YES;\n}\n\n- (BOOL)receivedText:(NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(nullable IRCChannel *)textDestination asLineType:(TVCLogLineType)lineType onClient:(IRCClient *)client receivedAt:(NSDate *)receivedAt wasEncrypted:(BOOL)wasEncrypted\n{\n\t/* Begin processing filters */\n\tNSArray *filters = self.parentObject.filterArrayController.content;\n\n\tfor (TPI_ChatFilter *filter in filters) {\n\t\t@autoreleasepool {\n\t\t\tif (((lineType == TVCLogLineTypePrivateMessage || lineType == TVCLogLineTypePrivateMessageNoHighlight) &&\n\t\t\t\t [filter isEventTypeEnabled:TPI_ChatFilterEventTypePlainTextMessage] == NO) ||\n\n\t\t\t\t((lineType == TVCLogLineTypeAction || lineType == TVCLogLineTypeActionNoHighlight) &&\n\t\t\t\t [filter isEventTypeEnabled:TPI_ChatFilterEventTypeActionMessage] == NO) ||\n\n\t\t\t\t(lineType == TVCLogLineTypeNotice &&\n\t\t\t\t [filter isEventTypeEnabled:TPI_ChatFilterEventTypeNoticeMessage] == NO))\n\t\t\t{\n\t\t\t\t/* Continue to next filter. This filter is not interested\n\t\t\t\t in the line type of the input. */\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Perform common filter checks */\n\t\t\tif ([self testFilterDestination:filter authoredBy:textAuthor destinedFor:textDestination onClient:client] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([self testFilterSender:filter authoredBy:textAuthor destinedFor:textDestination onClient:client] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ([self testFilterMatch:filter againstText:text allowingNilText:NO] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Perform actions defined by filter */\n\t\t\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t\t\t[self performActionForFilter:filter\n\t\t\t\t\t\t withOriginalMessage:text\n\t\t\t\t\t\t\t\t  authoredBy:textAuthor\n\t\t\t\t\t\t\t\t destinedFor:textDestination\n\t\t\t\t\t\t\t\t\tonClient:client\n\t\t\t\t\t\t\treferenceMessage:nil];\n\t\t\t});\n\n\t\t\t/* Forward a copy of the message to a query? */\n\t\t\tNSString *filterForwardToDestination = filter.filterForwardToDestination;\n\n\t\t\tif (filterForwardToDestination.length > 0 && text.length > 0) {\n\t\t\t\tIRCChannel *destinationChannel = [client findChannelOrCreate:filterForwardToDestination isPrivateMessage:YES];\n\n\t\t\t\tNSString *fakeMessageCommand = nil;\n\n\t\t\t\tif (lineType == TVCLogLineTypePrivateMessage ||\n\t\t\t\t\tlineType == TVCLogLineTypePrivateMessageNoHighlight ||\n\t\t\t\t\tlineType == TVCLogLineTypeAction ||\n\t\t\t\t\tlineType == TVCLogLineTypeActionNoHighlight)\n\t\t\t\t{\n\t\t\t\t\tfakeMessageCommand = @\"PRIVMSG\";\n\t\t\t\t} else if (lineType == TVCLogLineTypeNotice) {\n\t\t\t\t\tfakeMessageCommand = @\"NOTICE\";\n\t\t\t\t}\n\n\t\t\t\t[client print:text\n\t\t\t\t\t\t   by:textAuthor.nickname\n\t\t\t\t\tinChannel:destinationChannel\n\t\t\t\t\t   asType:lineType\n\t\t\t\t\t  command:fakeMessageCommand\n\t\t\t\t   receivedAt:receivedAt\n\t\t\t\t  isEncrypted:wasEncrypted\n\t\t\t referenceMessage:nil\n\t\t\t\t completionBlock:^(TVCLogControllerPrintOperationContext *context) {\n\t\t\t\t\t if (lineType == TVCLogLineTypeNotice) {\n\t\t\t\t\t\t [client setUnreadStateForChannel:destinationChannel];\n\t\t\t\t\t } else {\n\t\t\t\t\t\t BOOL isHighlight = context.highlight;\n\n\t\t\t\t\t\t if (isHighlight) {\n\t\t\t\t\t\t\t [client setHighlightStateForChannel:destinationChannel];\n\t\t\t\t\t\t }\n\n\t\t\t\t\t\t [client setUnreadStateForChannel:destinationChannel isHighlight:isHighlight];\n\t\t\t\t\t }\n\t\t\t\t }];\n\t\t\t}\n\n\t\t\tif (filter.filterIgnoreContent) {\n\t\t\t\treturn NO; // Ignore original content\n\t\t\t}\n\n\t\t\t/* Return once the first filter matches */\n\t\t\treturn YES;\n\t\t} // @autorelease\n\t} // for\n\n\treturn YES;\n}\n\n- (void)performActionForFilter:(TPI_ChatFilter *)filter withOriginalMessage:(nullable NSString *)text authoredBy:(IRCPrefix *)textAuthor destinedFor:(IRCChannel *)textDestination onClient:(IRCClient *)client referenceMessage:(nullable IRCMessage *)referenceMessage\n{\n\tif ([self isItSafeToPerformActionForFilter:filter] == NO) {\n\t\treturn;\n\t}\n\n\tif (text == nil) {\n\t\ttext = @\"\";\n\t}\n\n\t/* Perform action */\n\tNSString *filterAction = filter.filterAction;\n\n\tif (filterAction.length == 0) {\n\t\treturn;\n\t}\n\n\t#define _maybeReplaceValue(key, value)\t\\\n\t\tif (value == nil) {\t\t\\\n\t\t\tfilterAction = [filterAction stringByReplacingOccurrencesOfString:(key) withString:@\"\"];\t\\\n\t\t} else {\t\\\n\t\t\tfilterAction = [filterAction stringByReplacingOccurrencesOfString:(key) withString:(value)];\t\\\n\t\t}\n\n\t#define _maybeReplaceParam(paramIndex, paramIndexString)\t\t\\\n\t\tif (paramIndex >= paramsCount) {\t\\\n\t\t\tfilterAction = [filterAction stringByReplacingOccurrencesOfString:@paramIndexString withString:@\"\"];\t\t\\\n\t\t} else {\t\\\n\t\t\tfilterAction = [filterAction stringByReplacingOccurrencesOfString:@paramIndexString withString:params[paramIndex]];\t\t\\\n\t\t}\n\n\t_maybeReplaceValue(@\"%_channelName_%\", textDestination.name)\n\t_maybeReplaceValue(@\"%_localNickname_%\", client.userNickname)\n\t_maybeReplaceValue(@\"%_networkName_%\", client.networkName)\n\t_maybeReplaceValue(@\"%_originalMessage_%\", text)\n\t_maybeReplaceValue(@\"%_senderNickname_%\", textAuthor.nickname)\n\t_maybeReplaceValue(@\"%_senderUsername_%\", textAuthor.username)\n\t_maybeReplaceValue(@\"%_senderAddress_%\", textAuthor.address)\n\t_maybeReplaceValue(@\"%_senderHostmask_%\", textAuthor.hostmask)\n\t_maybeReplaceValue(@\"%_serverAddress_%\", client.serverAddress)\n\n\tNSArray *params = referenceMessage.params;\n\n\tNSUInteger paramsCount = params.count;\n\n\t_maybeReplaceParam(0, \"%_Parameter_0_%\")\n\t_maybeReplaceParam(1, \"%_Parameter_1_%\")\n\t_maybeReplaceParam(2, \"%_Parameter_2_%\")\n\t_maybeReplaceParam(3, \"%_Parameter_3_%\")\n\t_maybeReplaceParam(4, \"%_Parameter_4_%\")\n\t_maybeReplaceParam(5, \"%_Parameter_5_%\")\n\t_maybeReplaceParam(6, \"%_Parameter_6_%\")\n\t_maybeReplaceParam(7, \"%_Parameter_7_%\")\n\t_maybeReplaceParam(8, \"%_Parameter_8_%\")\n\t_maybeReplaceParam(9, \"%_Parameter_9_%\")\n\n#undef _maybeReplaceParam\n\n#undef _maybeReplaceValue\n\n\tNSArray *filterActions = [filterAction componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];\n\n\tfor (__strong NSString *actionCommand in filterActions) {\n\t\tif (actionCommand.length > 1 &&\n\t\t\t[actionCommand hasPrefix:@\"/\"] &&\n\t\t\t[actionCommand hasPrefix:@\"//\"] == NO)\n\t\t{\n\t\t\tactionCommand = [actionCommand substringFromIndex:1];\n\n\t\t\t[client sendCommand:actionCommand];\n\t\t}\n\t}\n\n\t/* Log action to a private message */\n\tif (filter.filterLogMatch) {\n\t\tIRCChannel *filterActionReportQuery = [client findChannelOrCreate:@\"Filter Actions\" isUtility:YES];\n\n\t\tNSString *formattedMessage = nil;\n\n\t\tif (textDestination == nil) {\n\t\t\tformattedMessage = TPILocalizedString(@\"TPI_ChatFilterExtension[yla-he]\", filter.filterTitle, textAuthor.nickname);\n\t\t} else {\n\t\t\tformattedMessage = TPILocalizedString(@\"TPI_ChatFilterExtension[jcm-xj]\", filter.filterTitle, textAuthor.nickname, textDestination.name);\n\t\t}\n\n\t\t[client print:formattedMessage\n\t\t\t\t   by:nil\n\t\t\tinChannel:filterActionReportQuery\n\t\t\t   asType:TVCLogLineTypePrivateMessage\n\t\t\t  command:@\"PRIVMSG\"];\n\n\t\t[client setUnreadStateForChannel:filterActionReportQuery];\n\t}\n}\n\n- (BOOL)isItSafeToPerformActionForFilter:(TPI_ChatFilter *)filter\n{\n\tNSUInteger floodControlInterval = filter.filterActionFloodControlInterval;\n\n\tif (floodControlInterval == 0) {\n\t\treturn YES;\n\t}\n\n\tNSTimeInterval now = [NSDate timeIntervalSince1970];\n\n\t@synchronized (self.filterActionLastPerforms) {\n\t\tNSString *filterIdentifier = filter.uniqueIdentifier;\n\n\t\tNSTimeInterval filterLastPerform = [self.filterActionLastPerforms doubleForKey:filterIdentifier];\n\n\t\tif ((now - filterLastPerform) <= floodControlInterval) {\n\t\t\tLogToConsoleDebugWithSubsystem(THOPluginLoggingSubsystem(),\n\t\t\t\t\"Not performing action because of flood control: %{public}.2f %{public}.2f\",\n\t\t\t\t  now, filterLastPerform);\n\n\t\t\treturn NO;\n\t\t}\n\n\t\tself.filterActionLastPerforms[filterIdentifier] = @(now);\n\t}\n\n\treturn YES;\n}\n\n- (void)reloadFilterActionPerforms\n{\n\t/* This rebuilds the -filterActionLastPerforms so that the only entries that\n\t exist are 1) filters that still exist 2) filters that require a timer */\n\t@synchronized (self.filterActionLastPerforms) {\n\t\tNSMutableDictionary *filterLastPerformsOld = self.filterActionLastPerforms;\n\n\t\tNSMutableDictionary *filterLastPerformsNew = [NSMutableDictionary dictionary];\n\n\t\tNSArray *filters = self.parentObject.filterArrayController.content;\n\n\t\tfor (TPI_ChatFilter *filter in filters) {\n\t\t\t@autoreleasepool {\n\t\t\t\tif (filter.filterActionFloodControlInterval == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tNSString *filterIdentifier = filter.uniqueIdentifier;\n\n\t\t\t\tNSNumber *filterLastPerform = filterLastPerformsOld[filterIdentifier];\n\n\t\t\t\tif (filterLastPerform == nil) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfilterLastPerformsNew[filterIdentifier] = filterLastPerform;\n\t\t\t}\n\t\t}\n\n\t\tself.filterActionLastPerforms = filterLastPerformsNew;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_NumberOnlyTextFieldFormatter.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_NumberOnlyTextFieldFormatter : NSNumberFormatter\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Classes/TPI_NumberOnlyTextFieldFormatter.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPI_NumberOnlyTextFieldFormatter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPI_NumberOnlyTextFieldFormatter\n\n- (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error\n{\n\tif (partialString.length == 0) {\n\t\treturn YES;\n\t}\n\n\tif (partialString.numericOnly == NO) {\n\t\tNSBeep();\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/Language Files/en.lproj/TPI_ChatFilterEditFilterSheet.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Next unused key: 1014 */\n\n\"90e-tj\" = \"Channel Name\";\n\"tbc-wc\" = \"My Nickname\";\n\"840-f9\" = \"Network Name\";\n\"sch-hi\" = \"Original Message\";\n\"xt2-bv\" = \"Sender Address\";\n\"je5-u2\" = \"Sender Hostmask\";\n\"k82-6i\" = \"Sender Nickname\";\n\"2sk-ui\" = \"Sender Username\";\n\"9xy-vf\" = \"Server Address\";\n\n\"kph-dc\" = \"Parameter #1\";\n\"8bd-nt\" = \"Parameter #2\";\n\"4vk-v8\" = \"Parameter #3\";\n\"kvz-ej\" = \"Parameter #4\";\n\"2pa-ju\" = \"Parameter #5\";\n\"jen-7o\" = \"Parameter #6\";\n\"t5v-4o\" = \"Parameter #7\";\n\"vyf-el\" = \"Parameter #8\";\n\"0x4-ib\" = \"Parameter #9\";\n\n\"m0u-tw\" = \"Please enter a shorter destination\";\n\"5kd-jt\" = \"Please enter a properly formatted destination.\n\nAccepted characters: a-z, A-Z, 0-9, dashes (-), underscores (_), and spaces.\";\n\n\"9ri-sd\" = \"Please enter a properly formatted list of commands.\n\n• Commands must be a comma (,) separated list.\\n• Commands must only contain the characters: a-z, A-Z, 0-9\n• Numerics must be whole numbers that are greater than zero (0) and less than or equal to 999.\";\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/Language Files/en.lproj/TPI_ChatFilterExtension.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"jq1-6r\" = \"Chat Filter\";\n\n\"yla-he\" = \"Performing action defined by the filter “%1$@“ against the user “%2$@“\";\n\"jcm-xj\" = \"Performing action defined by the filter “%1$@“ against the user “%2$@“ in the channel “%3$@“\";\n\n\"dka-bx\" = \"Filter “%@“\";\n\n\"c0k-xj\" = \"Are you sure that you want to delete this filter?\";\n\"dj6-fn\" = \"There is no undo and all data related to this filter will be erased.\";\n\"jvu-m7\" = \"Yes\";\n\"p5s-ff\" = \"No\";\n\n\"i9c-s3\" = \"Select filter configuration file to import\";\n\"2tc-m7\" = \"Select\";\n\n\"eqr-7t\" = \"Configuration file is in format that cannot be read\";\n\"ybz-7i\" = \"OK\";\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/Language Files/en.lproj/TPI_ChatFilterLogic.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"dct-7h\" = \"Message(%1$@): %2$@\";\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2015 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPI_ChatFilterExtension</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/User Interface/en.lproj/TPI_ChatFilterEditFilterSheet.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"18122\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"18122\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPI_ChatFilterEditFilterSheet\">\n            <connections>\n                <outlet property=\"cancelButton\" destination=\"dLf-X5-R1o\" id=\"fzG-QP-wnn\"/>\n                <outlet property=\"contentViewTabView\" destination=\"T01-Nx-QhV\" id=\"Ele-u7-gVH\"/>\n                <outlet property=\"filterActionFloodControlIntervalTextField\" destination=\"jAQ-A0-0fz\" id=\"YzK-Du-rLx\"/>\n                <outlet property=\"filterActionTokenChannelName\" destination=\"xNC-RA-OVo\" id=\"Ond-3l-FcE\"/>\n                <outlet property=\"filterActionTokenField\" destination=\"wGy-N2-oQL\" id=\"iLb-xy-pZz\"/>\n                <outlet property=\"filterActionTokenLocalNickname\" destination=\"Dbl-MS-g0g\" id=\"bfG-TE-h5U\"/>\n                <outlet property=\"filterActionTokenNetworkName\" destination=\"hub-7d-YOP\" id=\"on2-YH-67W\"/>\n                <outlet property=\"filterActionTokenOriginalMessage\" destination=\"hTf-Zo-2fg\" id=\"ZPW-wS-DAQ\"/>\n                <outlet property=\"filterActionTokenSenderAddress\" destination=\"k3G-9I-Qxd\" id=\"eI5-SU-FkO\"/>\n                <outlet property=\"filterActionTokenSenderHostmask\" destination=\"IC3-dU-HTg\" id=\"7ut-yl-oRq\"/>\n                <outlet property=\"filterActionTokenSenderNickname\" destination=\"hz3-ib-naL\" id=\"lTr-TP-eWR\"/>\n                <outlet property=\"filterActionTokenSenderUsername\" destination=\"bEr-mb-T5p\" id=\"2Cf-jr-JUh\"/>\n                <outlet property=\"filterActionTokenServerAddress\" destination=\"Jah-Fc-rje\" id=\"oPJ-5V-cvy\"/>\n                <outlet property=\"filterAgeLimitComparatorButton\" destination=\"Xr8-gb-6HM\" id=\"b2W-B3-Flz\"/>\n                <outlet property=\"filterAgeLimitTextField\" destination=\"I4P-3t-P4o\" id=\"pjZ-La-jTo\"/>\n                <outlet property=\"filterEventActionMessageCheck\" destination=\"hzt-Z8-IHO\" id=\"vhl-IU-eHs\"/>\n                <outlet property=\"filterEventChannelModeChangedCheck\" destination=\"OCm-2d-5iT\" id=\"9u7-xF-6cs\"/>\n                <outlet property=\"filterEventChannelModeReceivedCheck\" destination=\"gIz-IY-KJJ\" id=\"D7m-7T-DVF\"/>\n                <outlet property=\"filterEventChannelTopicChangedCheck\" destination=\"qMR-Qk-TTO\" id=\"Fuf-Sz-Qwn\"/>\n                <outlet property=\"filterEventChannelTopicReceivedCheck\" destination=\"pwj-AW-O7i\" id=\"UCP-62-6vB\"/>\n                <outlet property=\"filterEventNoticeMessageCheck\" destination=\"xne-lV-wM3\" id=\"9Ku-Qd-nvN\"/>\n                <outlet property=\"filterEventNumericTextField\" destination=\"qe2-po-Vne\" id=\"Sfj-VH-LNV\"/>\n                <outlet property=\"filterEventPlainTextMessageCheck\" destination=\"Q49-5O-3FE\" id=\"7zM-aP-c4Y\"/>\n                <outlet property=\"filterEventUserChangedNicknameCheck\" destination=\"Gsz-VT-x8W\" id=\"5fu-VG-WOm\"/>\n                <outlet property=\"filterEventUserDisconnectedCheck\" destination=\"HN3-2G-7vP\" id=\"YMo-l4-NP8\"/>\n                <outlet property=\"filterEventUserJoinedChannelCheck\" destination=\"HPO-EK-Lr9\" id=\"oHg-N7-q9n\"/>\n                <outlet property=\"filterEventUserKickedFromChannelCheck\" destination=\"3ux-y8-g4s\" id=\"Njo-DE-Qsf\"/>\n                <outlet property=\"filterEventUserLeftChannelCheck\" destination=\"UPV-bN-hrr\" id=\"hha-BK-CO7\"/>\n                <outlet property=\"filterForwardToDestinationTextField\" destination=\"muN-88-pns\" id=\"bY7-q6-27g\"/>\n                <outlet property=\"filterIgnoreContentCheck\" destination=\"vdu-cW-fcy\" id=\"1fS-BW-6xG\"/>\n                <outlet property=\"filterIgnoreOperatorsCheck\" destination=\"1Ft-El-Wak\" id=\"Rh1-xw-ueF\"/>\n                <outlet property=\"filterLimitToNoLimitButton\" destination=\"9q9-HZ-VJB\" id=\"z3I-Y3-WPX\"/>\n                <outlet property=\"filterLimitToOnlyChannelsButton\" destination=\"FHv-4p-uKe\" id=\"hNk-YZ-sGm\"/>\n                <outlet property=\"filterLimitToOnlyPrivateMessagesButton\" destination=\"oUe-SK-peo\" id=\"dS5-Wm-fZV\"/>\n                <outlet property=\"filterLimitToSelectionOutlineView\" destination=\"TdM-lk-raw\" id=\"6z7-P1-1qV\"/>\n                <outlet property=\"filterLimitToSpecificItemsButton\" destination=\"E3h-aN-eRj\" id=\"Geu-UE-xEI\"/>\n                <outlet property=\"filterLimitedToHostView\" destination=\"gTG-wG-y2s\" id=\"zee-bm-f1M\"/>\n                <outlet property=\"filterLimitedToMyselfCheck\" destination=\"X5X-m4-re0\" id=\"9Zk-xV-VDm\"/>\n                <outlet property=\"filterLimitedToSelectionHostView\" destination=\"akH-fU-k99\" id=\"E06-30-IMS\"/>\n                <outlet property=\"filterLogMatchCheck\" destination=\"A8t-L5-qUs\" id=\"ER5-sB-xJw\"/>\n                <outlet property=\"filterMatchTextField\" destination=\"TYu-Qh-WKq\" id=\"ODf-sf-0P0\"/>\n                <outlet property=\"filterNotesTextField\" destination=\"Poo-f2-StF\" id=\"gsx-YB-cca\"/>\n                <outlet property=\"filterSenderMatchTextField\" destination=\"ovl-ei-0Qj\" id=\"xra-9z-BwJ\"/>\n                <outlet property=\"filterTitleTextField\" destination=\"sfN-Ws-FW8\" id=\"W3i-Cc-LIn\"/>\n                <outlet property=\"okButton\" destination=\"wmA-Wb-Jwj\" id=\"Xn6-UY-DCw\"/>\n                <outlet property=\"sheet\" destination=\"cNB-Gy-yOO\" id=\"vsT-Zd-n7H\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <window title=\"Window\" allowsToolTipsWhenApplicationIsInactive=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" frameAutosaveName=\"\" animationBehavior=\"default\" id=\"cNB-Gy-yOO\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"589\" height=\"590\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1415\"/>\n            <view key=\"contentView\" id=\"alB-sv-LJa\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"589\" height=\"590\"/>\n                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                <subviews>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dLf-X5-R1o\">\n                        <rect key=\"frame\" x=\"438\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ofk-Rz-A9m\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancel:\" target=\"-2\" id=\"iX6-mZ-zZE\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wmA-Wb-Jwj\">\n                        <rect key=\"frame\" x=\"512\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ZKg-ju-c87\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"ok:\" target=\"-2\" id=\"Zbw-JL-fJv\"/>\n                        </connections>\n                    </button>\n                    <tabView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"T01-Nx-QhV\">\n                        <rect key=\"frame\" x=\"13\" y=\"50\" width=\"563\" height=\"534\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <tabViewItems>\n                            <tabViewItem label=\"Filter\" identifier=\"0\" id=\"Rvw-xI-QhN\">\n                                <view key=\"view\" id=\"8Ux-sm-Alm\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vBs-bR-T5n\">\n                                            <rect key=\"frame\" x=\"28\" y=\"410\" width=\"80\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Filter Match:\" id=\"a2n-La-LMB\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TYu-Qh-WKq\">\n                                            <rect key=\"frame\" x=\"30\" y=\"295\" width=\"479\" height=\"107\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"107\" id=\"azT-zN-ABr\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"0BP-Zx-Fdt\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"vBs-bR-T5n\" id=\"CKZ-DF-hYr\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"Ao8-VB-zQk\"/>\n                                            </connections>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CsT-6O-3Gc\">\n                                            <rect key=\"frame\" x=\"28\" y=\"258\" width=\"81\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Filter Action:\" id=\"3HI-Ry-Pmd\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ahe-EZ-5US\">\n                                            <rect key=\"frame\" x=\"486\" y=\"404\" width=\"25\" height=\"25\"/>\n                                            <buttonCell key=\"cell\" type=\"help\" bezelStyle=\"helpButton\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"SoU-I7-Ehd\">\n                                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"viewFilterMatchHelpText:\" target=\"-2\" id=\"PHY-Vd-fiz\"/>\n                                            </connections>\n                                        </button>\n                                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"b1E-IB-AAD\">\n                                            <rect key=\"frame\" x=\"490\" y=\"252\" width=\"25\" height=\"25\"/>\n                                            <buttonCell key=\"cell\" type=\"help\" bezelStyle=\"helpButton\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"ebt-DO-KSD\">\n                                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"viewFilterActionHelpText:\" target=\"-2\" id=\"f8o-6s-571\"/>\n                                            </connections>\n                                        </button>\n                                        <box autoresizesSubviews=\"NO\" borderType=\"line\" title=\"Filter Action Tokens\" titlePosition=\"noTitle\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4wE-6t-SLO\">\n                                            <rect key=\"frame\" x=\"27\" y=\"16\" width=\"489\" height=\"121\"/>\n                                            <view key=\"contentView\" id=\"aRg-yo-qrI\">\n                                                <rect key=\"frame\" x=\"3\" y=\"3\" width=\"483\" height=\"115\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                                <subviews>\n                                                    <gridView xPlacement=\"fill\" yPlacement=\"top\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s69-Bd-dZB\">\n                                                        <rect key=\"frame\" x=\"20\" y=\"26\" width=\"443\" height=\"64\"/>\n                                                        <rows>\n                                                            <gridRow id=\"t8C-7k-iRy\"/>\n                                                            <gridRow id=\"mlw-5d-0dV\"/>\n                                                            <gridRow id=\"TZ7-by-KGH\"/>\n                                                        </rows>\n                                                        <columns>\n                                                            <gridColumn xPlacement=\"fill\" id=\"1uQ-h7-mXT\"/>\n                                                            <gridColumn xPlacement=\"leading\" id=\"Q0v-NZ-bGm\"/>\n                                                            <gridColumn xPlacement=\"fill\" width=\"147\" id=\"oBh-mb-LOH\"/>\n                                                        </columns>\n                                                        <gridCells>\n                                                            <gridCell row=\"t8C-7k-iRy\" column=\"1uQ-h7-mXT\" id=\"bsa-HQ-Rkl\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"1\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hub-7d-YOP\">\n                                                                    <rect key=\"frame\" x=\"-2\" y=\"48\" width=\"135\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" tag=\"1\" title=\"Network Name\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"9By-pk-GTz\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"XZo-9D-aLw\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"t8C-7k-iRy\" column=\"Q0v-NZ-bGm\" id=\"5K8-eX-gGj\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"7\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hz3-ib-naL\">\n                                                                    <rect key=\"frame\" x=\"137\" y=\"48\" width=\"149\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Sender Nickname\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"WZD-Zm-lha\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"4UZ-RT-pV5\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"t8C-7k-iRy\" column=\"oBh-mb-LOH\" id=\"dKC-33-KOe\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bEr-mb-T5p\">\n                                                                    <rect key=\"frame\" x=\"294\" y=\"48\" width=\"151\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Sender Username\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"Swn-qj-488\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"8c9-NF-Gzk\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"mlw-5d-0dV\" column=\"1uQ-h7-mXT\" id=\"cp3-2a-cgr\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"1\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xNC-RA-OVo\">\n                                                                    <rect key=\"frame\" x=\"-2\" y=\"24\" width=\"135\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Channel Name\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"w2K-np-UI4\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"hKw-OS-GnF\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"mlw-5d-0dV\" column=\"Q0v-NZ-bGm\" id=\"n8v-Av-Jco\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"5\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"k3G-9I-Qxd\">\n                                                                    <rect key=\"frame\" x=\"137\" y=\"24\" width=\"139\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Sender Address\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"IWY-vb-65R\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"Fds-uP-HQi\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"mlw-5d-0dV\" column=\"oBh-mb-LOH\" id=\"oYb-Of-YzG\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"6\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IC3-dU-HTg\">\n                                                                    <rect key=\"frame\" x=\"294\" y=\"24\" width=\"151\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Sender Hostmask\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"Foq-12-BzJ\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"1gt-x9-jgg\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"TZ7-by-KGH\" column=\"1uQ-h7-mXT\" id=\"F6e-ww-EiK\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"9\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jah-Fc-rje\">\n                                                                    <rect key=\"frame\" x=\"-2\" y=\"0.0\" width=\"135\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Server Address\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"Xrk-zW-D9B\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"Uaf-TL-z5i\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"TZ7-by-KGH\" column=\"Q0v-NZ-bGm\" id=\"dUM-Pc-Yer\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"2\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dbl-MS-g0g\">\n                                                                    <rect key=\"frame\" x=\"137\" y=\"0.0\" width=\"124\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"My Nickname\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"8op-NH-aty\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"cKE-0n-7Ye\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                            <gridCell row=\"TZ7-by-KGH\" column=\"oBh-mb-LOH\" id=\"0jc-7t-Vlv\">\n                                                                <tokenField key=\"contentView\" verticalHuggingPriority=\"750\" tag=\"4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hTf-Zo-2fg\">\n                                                                    <rect key=\"frame\" x=\"294\" y=\"0.0\" width=\"151\" height=\"16\"/>\n                                                                    <tokenFieldCell key=\"cell\" selectable=\"YES\" allowsUndo=\"NO\" alignment=\"left\" title=\"Original Message\" placeholderString=\"\" allowsEditingTextAttributes=\"YES\" tokenStyle=\"rounded\" id=\"Lw0-nm-IeG\">\n                                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                    </tokenFieldCell>\n                                                                    <connections>\n                                                                        <outlet property=\"delegate\" destination=\"-2\" id=\"QrD-No-KuO\"/>\n                                                                    </connections>\n                                                                </tokenField>\n                                                            </gridCell>\n                                                        </gridCells>\n                                                    </gridView>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"s69-Bd-dZB\" firstAttribute=\"leading\" secondItem=\"aRg-yo-qrI\" secondAttribute=\"leading\" constant=\"20\" id=\"05o-p0-0BI\"/>\n                                                    <constraint firstItem=\"s69-Bd-dZB\" firstAttribute=\"top\" relation=\"greaterThanOrEqual\" secondItem=\"aRg-yo-qrI\" secondAttribute=\"top\" id=\"1Sx-am-PKf\"/>\n                                                    <constraint firstItem=\"s69-Bd-dZB\" firstAttribute=\"centerX\" secondItem=\"aRg-yo-qrI\" secondAttribute=\"centerX\" id=\"sTD-xF-yv9\"/>\n                                                    <constraint firstItem=\"s69-Bd-dZB\" firstAttribute=\"centerY\" secondItem=\"aRg-yo-qrI\" secondAttribute=\"centerY\" id=\"ycp-Bk-RRq\"/>\n                                                </constraints>\n                                            </view>\n                                        </box>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IBT-nM-IFM\">\n                                            <rect key=\"frame\" x=\"28\" y=\"450\" width=\"69\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Filter Title:\" id=\"GOZ-2v-y7k\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sfN-Ws-FW8\">\n                                            <rect key=\"frame\" x=\"103\" y=\"446\" width=\"410\" height=\"22\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"Qlp-r9-yb2\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" usesSingleLineMode=\"YES\" id=\"5yS-lv-oc5\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"IBT-nM-IFM\" id=\"qe3-cj-Gt4\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"7xK-Su-NFa\"/>\n                                            </connections>\n                                        </textField>\n                                        <tokenField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wGy-N2-oQL\" customClass=\"TVCAutoExpandingTokenField\">\n                                            <rect key=\"frame\" x=\"30\" y=\"143\" width=\"483\" height=\"107\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"107\" id=\"74Q-sx-msC\"/>\n                                            </constraints>\n                                            <tokenFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" borderStyle=\"bezel\" alignment=\"left\" drawsBackground=\"YES\" allowsEditingTextAttributes=\"YES\" completionDelay=\"1\" id=\"ZM6-8W-zE6\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </tokenFieldCell>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"CsT-6O-3Gc\" id=\"BwP-NQ-JFX\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"7fD-At-YYx\"/>\n                                            </connections>\n                                        </tokenField>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"sfN-Ws-FW8\" secondAttribute=\"trailing\" constant=\"30\" id=\"0ls-yY-Ykh\"/>\n                                        <constraint firstItem=\"vBs-bR-T5n\" firstAttribute=\"leading\" secondItem=\"TYu-Qh-WKq\" secondAttribute=\"leading\" id=\"3wO-t2-aME\"/>\n                                        <constraint firstItem=\"4wE-6t-SLO\" firstAttribute=\"trailing\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"trailing\" id=\"5xH-ll-bkW\"/>\n                                        <constraint firstItem=\"sfN-Ws-FW8\" firstAttribute=\"top\" secondItem=\"8Ux-sm-Alm\" secondAttribute=\"top\" constant=\"20\" id=\"60s-J4-QOT\"/>\n                                        <constraint firstItem=\"wGy-N2-oQL\" firstAttribute=\"top\" secondItem=\"CsT-6O-3Gc\" secondAttribute=\"bottom\" constant=\"8\" id=\"78a-4y-slF\"/>\n                                        <constraint firstItem=\"b1E-IB-AAD\" firstAttribute=\"trailing\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"trailing\" id=\"AIP-Do-42R\"/>\n                                        <constraint firstItem=\"ahe-EZ-5US\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"vBs-bR-T5n\" secondAttribute=\"trailing\" constant=\"20\" id=\"S8g-3K-5yr\"/>\n                                        <constraint firstItem=\"CsT-6O-3Gc\" firstAttribute=\"top\" secondItem=\"TYu-Qh-WKq\" secondAttribute=\"bottom\" constant=\"21\" id=\"VXC-4m-cK5\"/>\n                                        <constraint firstItem=\"b1E-IB-AAD\" firstAttribute=\"centerY\" secondItem=\"CsT-6O-3Gc\" secondAttribute=\"centerY\" id=\"Vb8-4f-n7k\"/>\n                                        <constraint firstItem=\"ahe-EZ-5US\" firstAttribute=\"trailing\" secondItem=\"TYu-Qh-WKq\" secondAttribute=\"trailing\" id=\"Wpc-hI-476\"/>\n                                        <constraint firstItem=\"sfN-Ws-FW8\" firstAttribute=\"leading\" secondItem=\"IBT-nM-IFM\" secondAttribute=\"trailing\" constant=\"8\" id=\"bUd-YZ-T36\"/>\n                                        <constraint firstItem=\"IBT-nM-IFM\" firstAttribute=\"firstBaseline\" secondItem=\"sfN-Ws-FW8\" secondAttribute=\"firstBaseline\" id=\"dX9-RR-dma\"/>\n                                        <constraint firstItem=\"IBT-nM-IFM\" firstAttribute=\"leading\" secondItem=\"8Ux-sm-Alm\" secondAttribute=\"leading\" constant=\"30\" id=\"eYP-8D-7RG\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"trailing\" constant=\"30\" id=\"eaM-WM-N3n\"/>\n                                        <constraint firstItem=\"4wE-6t-SLO\" firstAttribute=\"leading\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"leading\" id=\"fTa-TE-fSg\"/>\n                                        <constraint firstItem=\"TYu-Qh-WKq\" firstAttribute=\"leading\" secondItem=\"8Ux-sm-Alm\" secondAttribute=\"leading\" constant=\"30\" id=\"gq9-mQ-3v1\"/>\n                                        <constraint firstItem=\"b1E-IB-AAD\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"CsT-6O-3Gc\" secondAttribute=\"trailing\" constant=\"20\" id=\"h2o-iU-GnS\"/>\n                                        <constraint firstAttribute=\"bottom\" secondItem=\"4wE-6t-SLO\" secondAttribute=\"bottom\" constant=\"20\" id=\"hPm-fc-6Ds\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"TYu-Qh-WKq\" secondAttribute=\"trailing\" constant=\"34\" id=\"hj1-MQ-CDy\"/>\n                                        <constraint firstItem=\"ahe-EZ-5US\" firstAttribute=\"centerY\" secondItem=\"vBs-bR-T5n\" secondAttribute=\"centerY\" id=\"iIi-c3-jb4\"/>\n                                        <constraint firstItem=\"TYu-Qh-WKq\" firstAttribute=\"top\" secondItem=\"vBs-bR-T5n\" secondAttribute=\"bottom\" constant=\"8\" id=\"j1O-Xo-MDh\"/>\n                                        <constraint firstItem=\"vBs-bR-T5n\" firstAttribute=\"top\" secondItem=\"sfN-Ws-FW8\" secondAttribute=\"bottom\" constant=\"20\" id=\"qJC-UH-vFT\"/>\n                                        <constraint firstItem=\"CsT-6O-3Gc\" firstAttribute=\"leading\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"leading\" id=\"tWy-Gb-x5s\"/>\n                                        <constraint firstItem=\"wGy-N2-oQL\" firstAttribute=\"leading\" secondItem=\"8Ux-sm-Alm\" secondAttribute=\"leading\" constant=\"30\" id=\"wX9-lX-WKO\"/>\n                                        <constraint firstItem=\"4wE-6t-SLO\" firstAttribute=\"top\" secondItem=\"wGy-N2-oQL\" secondAttribute=\"bottom\" constant=\"8\" id=\"wpP-K2-mjD\"/>\n                                    </constraints>\n                                </view>\n                            </tabViewItem>\n                            <tabViewItem label=\"Channels\" identifier=\"1\" id=\"8ZK-wU-gg2\">\n                                <view key=\"view\" id=\"oIh-tI-HKB\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u00-83-eYs\">\n                                            <rect key=\"frame\" x=\"106\" y=\"447\" width=\"88\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Limit Filter to:\" id=\"ewY-OS-bvC\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gTG-wG-y2s\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"543\" height=\"368\"/>\n                                            <subviews>\n                                                <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UY2-pC-A0V\">\n                                                    <rect key=\"frame\" x=\"40\" y=\"365\" width=\"463\" height=\"5\"/>\n                                                </box>\n                                                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ogw-Wl-ucj\">\n                                                    <rect key=\"frame\" x=\"40\" y=\"333\" width=\"251\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Select one or more items to limit filter to:\" id=\"xeZ-GM-gcw\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                                <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"akH-fU-k99\">\n                                                    <rect key=\"frame\" x=\"42\" y=\"20\" width=\"459\" height=\"305\"/>\n                                                </customView>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"UY2-pC-A0V\" firstAttribute=\"centerX\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"centerX\" id=\"7C1-0Y-8Qq\"/>\n                                                <constraint firstItem=\"akH-fU-k99\" firstAttribute=\"leading\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"leading\" constant=\"42\" id=\"AJg-We-quL\"/>\n                                                <constraint firstItem=\"ogw-Wl-ucj\" firstAttribute=\"top\" secondItem=\"UY2-pC-A0V\" secondAttribute=\"bottom\" constant=\"18\" id=\"BlE-cF-VJm\"/>\n                                                <constraint firstItem=\"akH-fU-k99\" firstAttribute=\"centerX\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"centerX\" id=\"COG-MH-t5M\"/>\n                                                <constraint firstItem=\"ogw-Wl-ucj\" firstAttribute=\"leading\" secondItem=\"akH-fU-k99\" secondAttribute=\"leading\" id=\"Lnb-2x-0L2\"/>\n                                                <constraint firstItem=\"UY2-pC-A0V\" firstAttribute=\"top\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"top\" id=\"anM-CS-HPX\"/>\n                                                <constraint firstItem=\"UY2-pC-A0V\" firstAttribute=\"leading\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"leading\" constant=\"40\" id=\"pYY-ea-b0j\"/>\n                                                <constraint firstAttribute=\"bottom\" secondItem=\"akH-fU-k99\" secondAttribute=\"bottom\" constant=\"20\" id=\"weM-Hh-Ebw\"/>\n                                                <constraint firstItem=\"akH-fU-k99\" firstAttribute=\"top\" secondItem=\"ogw-Wl-ucj\" secondAttribute=\"bottom\" constant=\"8\" id=\"wzM-tU-XSg\"/>\n                                                <constraint firstItem=\"ogw-Wl-ucj\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"akH-fU-k99\" secondAttribute=\"trailing\" id=\"yJe-cp-CHC\"/>\n                                            </constraints>\n                                        </customView>\n                                        <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"4\" verticalStackHuggingPriority=\"750\" verticalHuggingPriority=\"750\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LKc-x8-6lo\">\n                                            <rect key=\"frame\" x=\"202\" y=\"387\" width=\"222\" height=\"76\"/>\n                                            <subviews>\n                                                <button tag=\"1\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FHv-4p-uKe\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"114\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"radio\" title=\"Only Channels\" imagePosition=\"left\" alignment=\"left\" state=\"on\" tag=\"1\" inset=\"2\" id=\"ICX-1r-s75\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <accessibility description=\"Limit filter to only channels\"/>\n                                                        <connections>\n                                                            <action selector=\"filterLimitedToMatrixChanged:\" target=\"-2\" id=\"j7l-Vv-eVD\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                                <button tag=\"2\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oUe-SK-peo\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"39\" width=\"224\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"radio\" title=\"Only Queries (Private Messages)\" imagePosition=\"left\" alignment=\"left\" tag=\"2\" inset=\"2\" id=\"Q2E-uO-tiy\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <accessibility description=\"Limit filter to only queries\"/>\n                                                        <connections>\n                                                            <action selector=\"filterLimitedToMatrixChanged:\" target=\"-2\" id=\"fny-qx-vln\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                                <button tag=\"3\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"E3h-aN-eRj\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"19\" width=\"112\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"radio\" title=\"Specific Items\" imagePosition=\"left\" alignment=\"left\" tag=\"3\" inset=\"2\" id=\"DUz-zW-Mca\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <accessibility description=\"Limit filter to specific items\"/>\n                                                        <connections>\n                                                            <action selector=\"filterLimitedToMatrixChanged:\" target=\"-2\" id=\"yKu-8x-mVS\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9q9-HZ-VJB\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"102\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"radio\" title=\"Do Not Limit\" imagePosition=\"left\" alignment=\"left\" inset=\"2\" id=\"6UK-tM-xg2\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <accessibility description=\"Do not limit filter\"/>\n                                                        <connections>\n                                                            <action selector=\"filterLimitedToMatrixChanged:\" target=\"-2\" id=\"fjs-Cm-Kkz\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                            </subviews>\n                                            <visibilityPriorities>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                            </visibilityPriorities>\n                                            <customSpacing>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                            </customSpacing>\n                                        </stackView>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"u00-83-eYs\" firstAttribute=\"centerY\" secondItem=\"FHv-4p-uKe\" secondAttribute=\"centerY\" id=\"7QU-5O-2Iy\"/>\n                                        <constraint firstItem=\"FHv-4p-uKe\" firstAttribute=\"leading\" secondItem=\"u00-83-eYs\" secondAttribute=\"trailing\" constant=\"10\" id=\"XPP-6Q-asR\"/>\n                                        <constraint firstItem=\"LKc-x8-6lo\" firstAttribute=\"top\" secondItem=\"oIh-tI-HKB\" secondAttribute=\"top\" constant=\"25\" id=\"fXR-QL-EQv\"/>\n                                        <constraint firstItem=\"gTG-wG-y2s\" firstAttribute=\"top\" secondItem=\"LKc-x8-6lo\" secondAttribute=\"bottom\" constant=\"19\" id=\"lPI-Yf-ZRA\"/>\n                                        <constraint firstAttribute=\"bottom\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"bottom\" id=\"oHi-up-1Pv\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"gTG-wG-y2s\" secondAttribute=\"trailing\" id=\"t1C-Pk-18A\"/>\n                                        <constraint firstItem=\"gTG-wG-y2s\" firstAttribute=\"leading\" secondItem=\"oIh-tI-HKB\" secondAttribute=\"leading\" id=\"ws1-Kd-Xx8\"/>\n                                        <constraint firstItem=\"u00-83-eYs\" firstAttribute=\"leading\" secondItem=\"oIh-tI-HKB\" secondAttribute=\"leading\" constant=\"108\" id=\"z13-jd-j5k\"/>\n                                    </constraints>\n                                </view>\n                            </tabViewItem>\n                            <tabViewItem label=\"Events\" identifier=\"2\" id=\"Wmc-xM-y3O\">\n                                <view key=\"view\" id=\"g73-Zu-4Qw\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"i3Y-vE-Mwp\">\n                                            <rect key=\"frame\" x=\"18\" y=\"436\" width=\"507\" height=\"32\"/>\n                                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"mDU-Qi-dI8\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <string key=\"title\">Select the event(s) that this filter will respond to. Some events are matched based on sender information and do not contain text. See documentation for examples.</string>\n                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SWQ-7s-2jI\">\n                                            <rect key=\"frame\" x=\"49\" y=\"177\" width=\"49\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Others:\" id=\"hII-je-7Zh\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <gridView xPlacement=\"leading\" yPlacement=\"top\" rowAlignment=\"firstBaseline\" rowSpacing=\"8\" columnSpacing=\"30\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LKj-pX-fVV\">\n                                            <rect key=\"frame\" x=\"84\" y=\"230\" width=\"376\" height=\"188\"/>\n                                            <rows>\n                                                <gridRow id=\"8yt-Sa-HhN\"/>\n                                                <gridRow height=\"30\" id=\"8db-Xv-Tfg\"/>\n                                                <gridRow yPlacement=\"fill\" id=\"cWl-lx-QR8\"/>\n                                                <gridRow yPlacement=\"fill\" id=\"IU8-mA-DDK\"/>\n                                                <gridRow height=\"30\" id=\"pLB-H2-8hm\"/>\n                                                <gridRow yPlacement=\"fill\" id=\"yee-Xv-GYg\"/>\n                                                <gridRow yPlacement=\"fill\" id=\"YI6-Xu-Ov2\"/>\n                                            </rows>\n                                            <columns>\n                                                <gridColumn id=\"pDn-Eo-7Qh\"/>\n                                                <gridColumn id=\"Pzv-gy-qqg\"/>\n                                            </columns>\n                                            <gridCells>\n                                                <gridCell row=\"8yt-Sa-HhN\" column=\"pDn-Eo-7Qh\" id=\"3dP-qj-nea\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Q49-5O-3FE\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"171\" width=\"140\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Plain text message\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"0oI-wq-byP\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter plain text messages\"/>\n                                                        <connections>\n                                                            <accessibilityConnection property=\"title\" destination=\"i3Y-vE-Mwp\" id=\"HSC-31-08g\"/>\n                                                            <action selector=\"filterEventTypeChanged:\" target=\"-2\" id=\"5pW-Mg-rGT\"/>\n                                                        </connections>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"8yt-Sa-HhN\" column=\"Pzv-gy-qqg\" id=\"RdB-GQ-Tr0\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hzt-Z8-IHO\">\n                                                        <rect key=\"frame\" x=\"195\" y=\"171\" width=\"123\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Action message\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"aRj-zZ-lw0\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter action messages\"/>\n                                                        <connections>\n                                                            <action selector=\"filterEventTypeChanged:\" target=\"-2\" id=\"bDF-lQ-FGK\"/>\n                                                        </connections>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"8db-Xv-Tfg\" column=\"pDn-Eo-7Qh\" id=\"oay-V5-oyH\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xne-lV-wM3\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"147\" width=\"124\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Notice message\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"hTv-Ss-VTI\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter notice messages\"/>\n                                                        <connections>\n                                                            <action selector=\"filterEventTypeChanged:\" target=\"-2\" id=\"8tW-a0-7Wx\"/>\n                                                        </connections>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"8db-Xv-Tfg\" column=\"Pzv-gy-qqg\" id=\"OJI-l0-SOn\"/>\n                                                <gridCell row=\"cWl-lx-QR8\" column=\"pDn-Eo-7Qh\" id=\"S3h-o0-CYc\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HPO-EK-Lr9\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"109\" width=\"146\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"User joined channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"CgI-jj-k1U\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;User joined channel&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"cWl-lx-QR8\" column=\"Pzv-gy-qqg\" id=\"BNg-cu-2Wh\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gsz-VT-x8W\">\n                                                        <rect key=\"frame\" x=\"195\" y=\"109\" width=\"173\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"User changed nickname\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"vR5-nX-6DC\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;User changed nickname&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"IU8-mA-DDK\" column=\"pDn-Eo-7Qh\" id=\"ekd-dW-r7t\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UPV-bN-hrr\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"85\" width=\"129\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"User left channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"0HK-qP-DKb\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;User left channel&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"IU8-mA-DDK\" column=\"Pzv-gy-qqg\" id=\"lcE-wW-afW\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3ux-y8-g4s\">\n                                                        <rect key=\"frame\" x=\"195\" y=\"85\" width=\"181\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"User kicked from channel\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"Y4O-Oc-VRk\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;User kicked from channel&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"pLB-H2-8hm\" column=\"pDn-Eo-7Qh\" id=\"VPX-MY-cTe\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HN3-2G-7vP\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"61\" width=\"141\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"User disconnected\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"qMk-U1-f0a\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;User disconnected&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"pLB-H2-8hm\" column=\"Pzv-gy-qqg\" id=\"5Zi-zH-v6X\"/>\n                                                <gridCell row=\"yee-Xv-GYg\" column=\"pDn-Eo-7Qh\" id=\"eY6-eh-XPV\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pwj-AW-O7i\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"23\" width=\"165\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Channel topic received\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"3cs-JT-M9S\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;Channel topic received&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"yee-Xv-GYg\" column=\"Pzv-gy-qqg\" id=\"2Jx-uP-Fcq\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qMR-Qk-TTO\">\n                                                        <rect key=\"frame\" x=\"195\" y=\"23\" width=\"166\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Channel topic changed\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"FMM-bN-tPd\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;Channel topic changed&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"YI6-Xu-Ov2\" column=\"pDn-Eo-7Qh\" id=\"f2c-HN-qzI\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gIz-IY-KJJ\">\n                                                        <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"169\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Channel mode received\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"ltZ-rm-A1R\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;Channel mode received&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                                <gridCell row=\"YI6-Xu-Ov2\" column=\"Pzv-gy-qqg\" id=\"Hkd-eA-ZOA\">\n                                                    <button key=\"contentView\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OCm-2d-5iT\">\n                                                        <rect key=\"frame\" x=\"195\" y=\"-1\" width=\"170\" height=\"18\"/>\n                                                        <buttonCell key=\"cell\" type=\"check\" title=\"Channel mode changed\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"diO-yQ-tF1\">\n                                                            <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                        </buttonCell>\n                                                        <accessibility description=\"Filter &quot;Channel mode changed&quot; event\"/>\n                                                    </button>\n                                                </gridCell>\n                                            </gridCells>\n                                        </gridView>\n                                        <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fJz-XV-6oT\">\n                                            <rect key=\"frame\" x=\"20\" y=\"209\" width=\"503\" height=\"5\"/>\n                                        </box>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qe2-po-Vne\" customClass=\"TVCValidatedTextField\">\n                                            <rect key=\"frame\" x=\"51\" y=\"113\" width=\"444\" height=\"56\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"56\" id=\"iMP-AJ-ctu\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"INVITE, 001, 002, 003, …\" id=\"xLg-Zy-ggt\" customClass=\"TVCValidatedTextFieldCell\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <accessibility description=\"List of Numerics\"/>\n                                            <connections>\n                                                <accessibilityConnection property=\"link\" destination=\"Vry-Tf-Odq\" id=\"4OY-ZS-8hU\"/>\n                                                <accessibilityConnection property=\"title\" destination=\"SWQ-7s-2jI\" id=\"a8T-p8-Soy\"/>\n                                            </connections>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vry-Tf-Odq\">\n                                            <rect key=\"frame\" x=\"49\" y=\"75\" width=\"448\" height=\"30\"/>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Comma-separated list of named commands and/or numerics (1 through 999) which are not defined as a checkbox up above.\" id=\"gqg-Wn-ped\">\n                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"Vry-Tf-Odq\" firstAttribute=\"top\" secondItem=\"qe2-po-Vne\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"2rY-JV-SAd\"/>\n                                        <constraint firstItem=\"SWQ-7s-2jI\" firstAttribute=\"top\" secondItem=\"fJz-XV-6oT\" secondAttribute=\"bottom\" constant=\"18\" id=\"56b-3T-g07\"/>\n                                        <constraint firstItem=\"fJz-XV-6oT\" firstAttribute=\"centerX\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"centerX\" id=\"6Ca-Gb-c7V\"/>\n                                        <constraint firstItem=\"LKj-pX-fVV\" firstAttribute=\"top\" secondItem=\"i3Y-vE-Mwp\" secondAttribute=\"bottom\" constant=\"18\" id=\"C7v-kX-QeI\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"i3Y-vE-Mwp\" secondAttribute=\"trailing\" constant=\"20\" id=\"ONx-RB-pjA\"/>\n                                        <constraint firstItem=\"SWQ-7s-2jI\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"qe2-po-Vne\" secondAttribute=\"trailing\" id=\"PGf-Qy-Bbt\"/>\n                                        <constraint firstItem=\"i3Y-vE-Mwp\" firstAttribute=\"top\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"top\" constant=\"20\" id=\"PpD-yw-efO\"/>\n                                        <constraint firstItem=\"i3Y-vE-Mwp\" firstAttribute=\"leading\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"leading\" constant=\"20\" id=\"RUN-tY-Zo0\"/>\n                                        <constraint firstItem=\"qe2-po-Vne\" firstAttribute=\"leading\" secondItem=\"Vry-Tf-Odq\" secondAttribute=\"leading\" id=\"VK9-zX-Ugx\"/>\n                                        <constraint firstItem=\"qe2-po-Vne\" firstAttribute=\"leading\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"leading\" constant=\"51\" id=\"g20-vh-aCw\"/>\n                                        <constraint firstItem=\"fJz-XV-6oT\" firstAttribute=\"leading\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"leading\" constant=\"20\" id=\"iOi-BJ-hYA\"/>\n                                        <constraint firstItem=\"qe2-po-Vne\" firstAttribute=\"leading\" secondItem=\"SWQ-7s-2jI\" secondAttribute=\"leading\" id=\"jtS-kl-fbb\"/>\n                                        <constraint firstItem=\"qe2-po-Vne\" firstAttribute=\"top\" secondItem=\"SWQ-7s-2jI\" secondAttribute=\"bottom\" constant=\"8\" id=\"l6G-iw-JEG\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"qe2-po-Vne\" secondAttribute=\"trailing\" constant=\"48\" id=\"mnG-Dy-K6C\"/>\n                                        <constraint firstItem=\"Vry-Tf-Odq\" firstAttribute=\"trailing\" secondItem=\"qe2-po-Vne\" secondAttribute=\"trailing\" id=\"okk-GW-K3q\"/>\n                                        <constraint firstItem=\"fJz-XV-6oT\" firstAttribute=\"top\" secondItem=\"LKj-pX-fVV\" secondAttribute=\"bottom\" constant=\"18\" id=\"qU6-le-QwS\"/>\n                                        <constraint firstItem=\"LKj-pX-fVV\" firstAttribute=\"centerX\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"centerX\" id=\"skD-L6-kvs\"/>\n                                        <constraint firstItem=\"fJz-XV-6oT\" firstAttribute=\"centerX\" secondItem=\"g73-Zu-4Qw\" secondAttribute=\"centerX\" id=\"wYH-OC-98D\"/>\n                                    </constraints>\n                                </view>\n                            </tabViewItem>\n                            <tabViewItem label=\"Sender\" identifier=\"3\" id=\"zzu-Mn-V6O\">\n                                <view key=\"view\" id=\"Sbg-tS-i4H\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vGk-i7-DUZ\">\n                                            <rect key=\"frame\" x=\"62\" y=\"422\" width=\"288\" height=\"46\"/>\n                                            <subviews>\n                                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Ft-El-Wak\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"279\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"check\" title=\"Filter does not apply to channel operators\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"8eG-ng-a2k\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <connections>\n                                                            <action selector=\"filterIgnoreContentCheckChanged:\" target=\"-2\" id=\"gW3-0c-wwF\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                    <connections>\n                                                        <binding destination=\"-2\" name=\"enabled\" keyPath=\"self.filterIgnoreOperatorsCheckEnabled\" id=\"WKq-zT-NrI\"/>\n                                                        <binding destination=\"-2\" name=\"value\" keyPath=\"self.filterIgnoreOperatorsCheckValue\" id=\"3xc-oz-LtS\"/>\n                                                    </connections>\n                                                </button>\n                                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"X5X-m4-re0\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"290\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"check\" title=\"Filter does not apply unless I am the sender\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"6fP-9P-bTo\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                    </buttonCell>\n                                                    <connections>\n                                                        <action selector=\"filterLimitedToMyselfChanged:\" target=\"-2\" id=\"Drt-fq-99d\"/>\n                                                    </connections>\n                                                </button>\n                                            </subviews>\n                                            <visibilityPriorities>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                            </visibilityPriorities>\n                                            <customSpacing>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                            </customSpacing>\n                                        </stackView>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"k4d-KT-PP4\">\n                                            <rect key=\"frame\" x=\"56\" y=\"316\" width=\"93\" height=\"16\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Sender Match:\" id=\"efZ-aQ-jSL\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Vj-YR-p2q\">\n                                            <rect key=\"frame\" x=\"102\" y=\"305\" width=\"47\" height=\"11\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"(optional)\" id=\"uMI-RE-rQe\">\n                                                <font key=\"font\" metaFont=\"miniSystem\"/>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ovl-ei-0Qj\">\n                                            <rect key=\"frame\" x=\"155\" y=\"310\" width=\"302\" height=\"22\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"P2o-Td-oSZ\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"3UV-cQ-6XT\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <connections>\n                                                <accessibilityConnection property=\"title\" destination=\"k4d-KT-PP4\" id=\"z3m-dT-TcP\"/>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"qWG-FW-1Ad\"/>\n                                            </connections>\n                                        </textField>\n                                        <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"U3o-oI-ojF\">\n                                            <rect key=\"frame\" x=\"40\" y=\"348\" width=\"463\" height=\"5\"/>\n                                        </box>\n                                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gFi-Zi-mq8\">\n                                            <rect key=\"frame\" x=\"462\" y=\"307\" width=\"25\" height=\"25\"/>\n                                            <buttonCell key=\"cell\" type=\"help\" bezelStyle=\"helpButton\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"W0h-79-O1n\">\n                                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"viewFilterSenderMatchHelpText:\" target=\"-2\" id=\"yKh-Vf-d1t\"/>\n                                            </connections>\n                                        </button>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gvj-AU-dTW\">\n                                            <rect key=\"frame\" x=\"78\" y=\"369\" width=\"363\" height=\"45\"/>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"tBf-Xx-fOd\">\n                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                <string key=\"title\">Not all events can be narrowed to only you. Filters act on incoming data. You wont be able to use this option to self-bot. The most common event this option is used for is Channel Join.</string>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PKp-Xg-xep\">\n                                            <rect key=\"frame\" x=\"40\" y=\"289\" width=\"463\" height=\"5\"/>\n                                        </box>\n                                        <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"7\" horizontalStackHuggingPriority=\"249.99998474121094\" verticalStackHuggingPriority=\"249.99998474121094\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lpB-Zj-mN2\">\n                                            <rect key=\"frame\" x=\"58\" y=\"228\" width=\"346\" height=\"45\"/>\n                                            <subviews>\n                                                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zst-8r-iIf\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"350\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"Filter does not apply to users that have been in a channel\" id=\"HeF-bg-gNR\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                                <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"centerY\" horizontalStackHuggingPriority=\"249.99998474121094\" verticalStackHuggingPriority=\"249.99998474121094\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2wE-BB-IEK\">\n                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"257\" height=\"22\"/>\n                                                    <subviews>\n                                                        <popUpButton verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Xr8-gb-6HM\">\n                                                            <rect key=\"frame\" x=\"-3\" y=\"-3\" width=\"119\" height=\"25\"/>\n                                                            <popUpButtonCell key=\"cell\" type=\"push\" title=\"Less Than\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"borderAndBezel\" tag=\"1\" imageScaling=\"proportionallyDown\" inset=\"2\" selectedItem=\"zqM-dB-S3H\" id=\"UdZ-L1-s8b\">\n                                                                <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                                <font key=\"font\" metaFont=\"menu\"/>\n                                                                <menu key=\"menu\" id=\"Lf6-ga-yf7\">\n                                                                    <items>\n                                                                        <menuItem title=\"Less Than\" state=\"on\" tag=\"1\" id=\"zqM-dB-S3H\"/>\n                                                                        <menuItem title=\"Greater Than\" tag=\"2\" id=\"qXs-Ny-a3z\"/>\n                                                                    </items>\n                                                                </menu>\n                                                            </popUpButtonCell>\n                                                        </popUpButton>\n                                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I4P-3t-P4o\">\n                                                            <rect key=\"frame\" x=\"120\" y=\"0.0\" width=\"77\" height=\"22\"/>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"Kzl-6X-ufl\"/>\n                                                            </constraints>\n                                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" title=\"0\" drawsBackground=\"YES\" id=\"BXS-Xv-xW5\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                            <connections>\n                                                                <accessibilityConnection property=\"title\" destination=\"zst-8r-iIf\" id=\"5o9-EV-FUe\"/>\n                                                                <outlet property=\"delegate\" destination=\"-2\" id=\"PhL-bM-B3R\"/>\n                                                            </connections>\n                                                        </textField>\n                                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1MO-Ig-foo\">\n                                                            <rect key=\"frame\" x=\"203\" y=\"3\" width=\"56\" height=\"16\"/>\n                                                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"seconds\" id=\"tsb-Vd-Lzv\">\n                                                                <font key=\"font\" metaFont=\"system\"/>\n                                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            </textFieldCell>\n                                                        </textField>\n                                                    </subviews>\n                                                    <visibilityPriorities>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                        <integer value=\"1000\"/>\n                                                    </visibilityPriorities>\n                                                    <customSpacing>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                        <real value=\"3.4028234663852886e+38\"/>\n                                                    </customSpacing>\n                                                </stackView>\n                                            </subviews>\n                                            <visibilityPriorities>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                            </visibilityPriorities>\n                                            <customSpacing>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                            </customSpacing>\n                                        </stackView>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dTa-NJ-Hl9\">\n                                            <rect key=\"frame\" x=\"74\" y=\"205\" width=\"268\" height=\"15\"/>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Change value to zero (0) to disable limitations.\" id=\"oM0-ZH-E1b\">\n                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"Gvj-AU-dTW\" firstAttribute=\"top\" secondItem=\"X5X-m4-re0\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"2au-nN-M3b\"/>\n                                        <constraint firstItem=\"PKp-Xg-xep\" firstAttribute=\"top\" secondItem=\"ovl-ei-0Qj\" secondAttribute=\"bottom\" constant=\"18\" id=\"3sY-Ub-Wz9\"/>\n                                        <constraint firstItem=\"lpB-Zj-mN2\" firstAttribute=\"leading\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"leading\" constant=\"58\" id=\"4En-mT-O4X\"/>\n                                        <constraint firstItem=\"vGk-i7-DUZ\" firstAttribute=\"leading\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"leading\" constant=\"62\" id=\"6c4-6q-zS4\"/>\n                                        <constraint firstItem=\"0Vj-YR-p2q\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"leading\" constant=\"20\" id=\"AN6-Er-35o\"/>\n                                        <constraint firstItem=\"0Vj-YR-p2q\" firstAttribute=\"trailing\" secondItem=\"k4d-KT-PP4\" secondAttribute=\"trailing\" id=\"BG4-5N-5zL\"/>\n                                        <constraint firstItem=\"Gvj-AU-dTW\" firstAttribute=\"leading\" secondItem=\"X5X-m4-re0\" secondAttribute=\"leading\" constant=\"18\" id=\"BhM-We-cF1\"/>\n                                        <constraint firstItem=\"PKp-Xg-xep\" firstAttribute=\"trailing\" secondItem=\"U3o-oI-ojF\" secondAttribute=\"trailing\" id=\"E5h-yo-2hg\"/>\n                                        <constraint firstItem=\"dTa-NJ-Hl9\" firstAttribute=\"leading\" secondItem=\"lpB-Zj-mN2\" secondAttribute=\"leading\" constant=\"18\" id=\"GL2-qY-EzT\"/>\n                                        <constraint firstItem=\"ovl-ei-0Qj\" firstAttribute=\"leading\" secondItem=\"k4d-KT-PP4\" secondAttribute=\"trailing\" constant=\"8\" id=\"JcA-AY-bmQ\"/>\n                                        <constraint firstItem=\"0Vj-YR-p2q\" firstAttribute=\"top\" secondItem=\"k4d-KT-PP4\" secondAttribute=\"bottom\" id=\"T5A-Wm-b9Z\"/>\n                                        <constraint firstItem=\"k4d-KT-PP4\" firstAttribute=\"top\" secondItem=\"ovl-ei-0Qj\" secondAttribute=\"top\" id=\"Usw-w6-Oyr\"/>\n                                        <constraint firstItem=\"U3o-oI-ojF\" firstAttribute=\"leading\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"leading\" constant=\"40\" id=\"VsR-Z3-W0Y\"/>\n                                        <constraint firstItem=\"U3o-oI-ojF\" firstAttribute=\"top\" secondItem=\"Gvj-AU-dTW\" secondAttribute=\"bottom\" constant=\"18\" id=\"ZUm-q4-kBk\"/>\n                                        <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Gvj-AU-dTW\" secondAttribute=\"trailing\" constant=\"20\" id=\"bix-b2-pEJ\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"gFi-Zi-mq8\" secondAttribute=\"trailing\" constant=\"58\" id=\"d0Q-98-fkW\"/>\n                                        <constraint firstItem=\"U3o-oI-ojF\" firstAttribute=\"centerX\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"centerX\" id=\"dlQ-cJ-LQZ\"/>\n                                        <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"dTa-NJ-Hl9\" secondAttribute=\"trailing\" constant=\"20\" id=\"gOc-f6-iDW\"/>\n                                        <constraint firstItem=\"ovl-ei-0Qj\" firstAttribute=\"top\" secondItem=\"U3o-oI-ojF\" secondAttribute=\"bottom\" constant=\"18\" id=\"j5j-iC-JlJ\"/>\n                                        <constraint firstItem=\"U3o-oI-ojF\" firstAttribute=\"centerX\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"centerX\" id=\"oPB-1B-70H\"/>\n                                        <constraint firstItem=\"lpB-Zj-mN2\" firstAttribute=\"top\" secondItem=\"PKp-Xg-xep\" secondAttribute=\"bottom\" constant=\"18\" id=\"p4y-g1-eUJ\"/>\n                                        <constraint firstItem=\"k4d-KT-PP4\" firstAttribute=\"leading\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"leading\" constant=\"58\" id=\"pYh-vh-LHX\"/>\n                                        <constraint firstItem=\"dTa-NJ-Hl9\" firstAttribute=\"top\" secondItem=\"lpB-Zj-mN2\" secondAttribute=\"bottom\" constant=\"8\" id=\"rdt-rO-u8O\"/>\n                                        <constraint firstItem=\"gFi-Zi-mq8\" firstAttribute=\"centerY\" secondItem=\"ovl-ei-0Qj\" secondAttribute=\"centerY\" id=\"sOp-7n-imY\"/>\n                                        <constraint firstItem=\"PKp-Xg-xep\" firstAttribute=\"leading\" secondItem=\"U3o-oI-ojF\" secondAttribute=\"leading\" id=\"uc3-Sc-neH\"/>\n                                        <constraint firstItem=\"gFi-Zi-mq8\" firstAttribute=\"leading\" secondItem=\"ovl-ei-0Qj\" secondAttribute=\"trailing\" constant=\"8\" id=\"w3d-TM-7cv\"/>\n                                        <constraint firstItem=\"vGk-i7-DUZ\" firstAttribute=\"top\" secondItem=\"Sbg-tS-i4H\" secondAttribute=\"top\" constant=\"20\" id=\"w9D-9e-zzK\"/>\n                                    </constraints>\n                                </view>\n                            </tabViewItem>\n                            <tabViewItem label=\"Notes\" identifier=\"4\" id=\"G3J-4c-NKh\">\n                                <view key=\"view\" id=\"EWz-Am-gtB\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gXn-wi-BH2\">\n                                            <rect key=\"frame\" x=\"18\" y=\"404\" width=\"507\" height=\"64\"/>\n                                            <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" id=\"JCT-z8-69i\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <string key=\"title\">Use the box presented below to keep notes specific to this filter such as examples of messages that will trigger it.\n\nThis information is for your records and does not alter the behavior of the filter.</string>\n                                                <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Poo-f2-StF\">\n                                            <rect key=\"frame\" x=\"20\" y=\"20\" width=\"503\" height=\"376\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" relation=\"greaterThanOrEqual\" constant=\"300\" id=\"Urh-Tg-dZo\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" drawsBackground=\"YES\" id=\"AxR-JW-tjB\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                            <accessibility description=\"Description of filter (optional)\"/>\n                                            <connections>\n                                                <outlet property=\"delegate\" destination=\"-2\" id=\"7Wu-Sl-dt9\"/>\n                                            </connections>\n                                        </textField>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstItem=\"gXn-wi-BH2\" firstAttribute=\"leading\" secondItem=\"Poo-f2-StF\" secondAttribute=\"leading\" id=\"0c4-hq-Cmo\"/>\n                                        <constraint firstAttribute=\"bottom\" secondItem=\"Poo-f2-StF\" secondAttribute=\"bottom\" constant=\"20\" id=\"Jbh-h4-OdV\"/>\n                                        <constraint firstItem=\"gXn-wi-BH2\" firstAttribute=\"top\" secondItem=\"EWz-Am-gtB\" secondAttribute=\"top\" constant=\"20\" id=\"Mhq-un-DrX\"/>\n                                        <constraint firstItem=\"gXn-wi-BH2\" firstAttribute=\"trailing\" secondItem=\"Poo-f2-StF\" secondAttribute=\"trailing\" id=\"n79-Pz-L2O\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"Poo-f2-StF\" secondAttribute=\"trailing\" constant=\"20\" id=\"rXW-BL-WBS\"/>\n                                        <constraint firstItem=\"Poo-f2-StF\" firstAttribute=\"leading\" secondItem=\"EWz-Am-gtB\" secondAttribute=\"leading\" constant=\"20\" id=\"vrf-o9-n91\"/>\n                                        <constraint firstItem=\"Poo-f2-StF\" firstAttribute=\"top\" secondItem=\"gXn-wi-BH2\" secondAttribute=\"bottom\" constant=\"8\" id=\"zwB-fj-66k\"/>\n                                    </constraints>\n                                </view>\n                            </tabViewItem>\n                            <tabViewItem label=\"Advanced\" identifier=\"5\" id=\"qOp-7g-85h\">\n                                <view key=\"view\" id=\"hsJ-a5-uAO\">\n                                    <rect key=\"frame\" x=\"10\" y=\"33\" width=\"543\" height=\"488\"/>\n                                    <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                    <subviews>\n                                        <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RDw-Uz-qQG\">\n                                            <rect key=\"frame\" x=\"47\" y=\"422\" width=\"449\" height=\"46\"/>\n                                            <subviews>\n                                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vdu-cW-fcy\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"160\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"check\" title=\"Hide original message\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"EeO-VK-V0E\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <connections>\n                                                            <action selector=\"filterIgnoreContentCheckChanged:\" target=\"-2\" id=\"CLM-sz-f8T\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A8t-L5-qUs\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"451\" height=\"18\"/>\n                                                    <buttonCell key=\"cell\" type=\"check\" title=\"Log to a query when a filter match is found and an action is performed\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"EgQ-6a-Tdo\">\n                                                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <connections>\n                                                            <action selector=\"filterIgnoreContentCheckChanged:\" target=\"-2\" id=\"jep-SV-FC5\"/>\n                                                        </connections>\n                                                    </buttonCell>\n                                                </button>\n                                            </subviews>\n                                            <visibilityPriorities>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                            </visibilityPriorities>\n                                            <customSpacing>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                            </customSpacing>\n                                        </stackView>\n                                        <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FeH-nM-2Zz\">\n                                            <rect key=\"frame\" x=\"40\" y=\"401\" width=\"463\" height=\"5\"/>\n                                        </box>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Dp-RH-HQY\">\n                                            <rect key=\"frame\" x=\"66\" y=\"369\" width=\"73\" height=\"16\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"16\" id=\"hvZ-fQ-3Pi\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" alignment=\"right\" title=\"Forward to:\" id=\"rsF-qW-N0y\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZVP-ho-Ddx\">\n                                            <rect key=\"frame\" x=\"92\" y=\"358\" width=\"47\" height=\"11\"/>\n                                            <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"(optional)\" id=\"60g-lP-t8x\">\n                                                <font key=\"font\" metaFont=\"miniSystem\"/>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"muN-88-pns\" customClass=\"TVCValidatedTextField\">\n                                            <rect key=\"frame\" x=\"145\" y=\"363\" width=\"302\" height=\"22\"/>\n                                            <constraints>\n                                                <constraint firstAttribute=\"height\" constant=\"22\" id=\"f6r-Lf-gam\"/>\n                                            </constraints>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" id=\"Vqv-i7-xCm\" customClass=\"TVCValidatedTextFieldCell\">\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                                <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                        <button horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CCU-H7-ovf\">\n                                            <rect key=\"frame\" x=\"452\" y=\"360\" width=\"25\" height=\"25\"/>\n                                            <buttonCell key=\"cell\" type=\"help\" bezelStyle=\"helpButton\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"bqh-Kx-AHH\">\n                                                <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                                <font key=\"font\" metaFont=\"system\"/>\n                                            </buttonCell>\n                                            <connections>\n                                                <action selector=\"viewFilterForwardToDestinationHelpText:\" target=\"-2\" id=\"LrC-Sd-sXV\"/>\n                                            </connections>\n                                        </button>\n                                        <box verticalHuggingPriority=\"750\" boxType=\"separator\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"x0Z-6b-fhh\">\n                                            <rect key=\"frame\" x=\"40\" y=\"342\" width=\"463\" height=\"5\"/>\n                                        </box>\n                                        <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"250\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uPY-hj-XMJ\">\n                                            <rect key=\"frame\" x=\"56\" y=\"304\" width=\"432\" height=\"22\"/>\n                                            <subviews>\n                                                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KgF-yt-KDi\">\n                                                    <rect key=\"frame\" x=\"-2\" y=\"4\" width=\"308\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"Do not perform Filter Action more than once every\" id=\"y97-oT-WNv\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jAQ-A0-0fz\">\n                                                    <rect key=\"frame\" x=\"312\" y=\"0.0\" width=\"60\" height=\"22\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"60\" id=\"bFM-BS-mIy\"/>\n                                                        <constraint firstAttribute=\"height\" constant=\"22\" id=\"cKg-rZ-EQn\"/>\n                                                    </constraints>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" title=\"1\" drawsBackground=\"YES\" id=\"4gr-RI-ABh\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                    <connections>\n                                                        <outlet property=\"formatter\" destination=\"vGQ-Aw-wDg\" id=\"fgR-HD-NFG\"/>\n                                                    </connections>\n                                                </textField>\n                                                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZUu-lu-9qu\">\n                                                    <rect key=\"frame\" x=\"378\" y=\"4\" width=\"56\" height=\"16\"/>\n                                                    <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" sendsActionOnEndEditing=\"YES\" title=\"seconds\" id=\"4O9-2v-odd\">\n                                                        <font key=\"font\" metaFont=\"system\"/>\n                                                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                    </textFieldCell>\n                                                </textField>\n                                            </subviews>\n                                            <visibilityPriorities>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                                <integer value=\"1000\"/>\n                                            </visibilityPriorities>\n                                            <customSpacing>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                                <real value=\"3.4028234663852886e+38\"/>\n                                            </customSpacing>\n                                        </stackView>\n                                        <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1cG-xA-EzB\">\n                                            <rect key=\"frame\" x=\"72\" y=\"281\" width=\"268\" height=\"15\"/>\n                                            <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" title=\"Change value to zero (0) to disable limitations.\" id=\"cvx-mI-PZ4\">\n                                                <font key=\"font\" metaFont=\"cellTitle\"/>\n                                                <color key=\"textColor\" name=\"secondaryLabelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            </textFieldCell>\n                                        </textField>\n                                    </subviews>\n                                    <constraints>\n                                        <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"1cG-xA-EzB\" secondAttribute=\"trailing\" constant=\"20\" id=\"1c6-mz-jMI\"/>\n                                        <constraint firstItem=\"muN-88-pns\" firstAttribute=\"leading\" secondItem=\"1Dp-RH-HQY\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"2dV-qu-GA0\"/>\n                                        <constraint firstItem=\"1Dp-RH-HQY\" firstAttribute=\"leading\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"leading\" constant=\"68\" id=\"5FQ-9w-ilQ\"/>\n                                        <constraint firstItem=\"1cG-xA-EzB\" firstAttribute=\"top\" secondItem=\"uPY-hj-XMJ\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"8hG-ls-tyW\"/>\n                                        <constraint firstItem=\"FeH-nM-2Zz\" firstAttribute=\"centerX\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"centerX\" id=\"8ns-fi-qk0\"/>\n                                        <constraint firstItem=\"CCU-H7-ovf\" firstAttribute=\"centerY\" secondItem=\"muN-88-pns\" secondAttribute=\"centerY\" id=\"HS8-Js-fkv\"/>\n                                        <constraint firstItem=\"CCU-H7-ovf\" firstAttribute=\"leading\" secondItem=\"muN-88-pns\" secondAttribute=\"trailing\" constant=\"8\" symbolic=\"YES\" id=\"L18-G1-B1D\"/>\n                                        <constraint firstItem=\"ZVP-ho-Ddx\" firstAttribute=\"trailing\" secondItem=\"1Dp-RH-HQY\" secondAttribute=\"trailing\" id=\"LEG-jQ-J6K\"/>\n                                        <constraint firstItem=\"1cG-xA-EzB\" firstAttribute=\"leading\" secondItem=\"uPY-hj-XMJ\" secondAttribute=\"leading\" constant=\"18\" id=\"N3T-bA-mzw\"/>\n                                        <constraint firstItem=\"muN-88-pns\" firstAttribute=\"top\" secondItem=\"FeH-nM-2Zz\" secondAttribute=\"bottom\" constant=\"18\" id=\"RBe-oV-HsK\"/>\n                                        <constraint firstItem=\"x0Z-6b-fhh\" firstAttribute=\"trailing\" secondItem=\"FeH-nM-2Zz\" secondAttribute=\"trailing\" id=\"Src-Wd-Xcj\"/>\n                                        <constraint firstItem=\"FeH-nM-2Zz\" firstAttribute=\"top\" secondItem=\"RDw-Uz-qQG\" secondAttribute=\"bottom\" constant=\"18\" id=\"UFh-tb-Myu\"/>\n                                        <constraint firstItem=\"1Dp-RH-HQY\" firstAttribute=\"top\" secondItem=\"muN-88-pns\" secondAttribute=\"top\" id=\"eXz-Kg-SUo\"/>\n                                        <constraint firstItem=\"x0Z-6b-fhh\" firstAttribute=\"leading\" secondItem=\"FeH-nM-2Zz\" secondAttribute=\"leading\" id=\"ea7-9z-kos\"/>\n                                        <constraint firstItem=\"RDw-Uz-qQG\" firstAttribute=\"top\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"top\" constant=\"20\" id=\"ffL-o5-ThR\"/>\n                                        <constraint firstItem=\"ZVP-ho-Ddx\" firstAttribute=\"top\" secondItem=\"1Dp-RH-HQY\" secondAttribute=\"bottom\" id=\"jal-lM-72v\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"CCU-H7-ovf\" secondAttribute=\"trailing\" constant=\"68\" id=\"oEd-kO-GLM\"/>\n                                        <constraint firstItem=\"x0Z-6b-fhh\" firstAttribute=\"top\" secondItem=\"muN-88-pns\" secondAttribute=\"bottom\" constant=\"18\" id=\"pqg-DL-RAN\"/>\n                                        <constraint firstItem=\"uPY-hj-XMJ\" firstAttribute=\"centerX\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"centerX\" id=\"saF-XN-Pou\"/>\n                                        <constraint firstItem=\"RDw-Uz-qQG\" firstAttribute=\"centerX\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"centerX\" id=\"t3r-Ea-PjA\"/>\n                                        <constraint firstItem=\"FeH-nM-2Zz\" firstAttribute=\"leading\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"leading\" constant=\"40\" id=\"uOR-yb-JfU\"/>\n                                        <constraint firstItem=\"FeH-nM-2Zz\" firstAttribute=\"centerX\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"centerX\" id=\"vZp-JS-nIF\"/>\n                                        <constraint firstItem=\"uPY-hj-XMJ\" firstAttribute=\"top\" secondItem=\"x0Z-6b-fhh\" secondAttribute=\"bottom\" constant=\"18\" id=\"xrB-AH-kRx\"/>\n                                        <constraint firstItem=\"ZVP-ho-Ddx\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"hsJ-a5-uAO\" secondAttribute=\"leading\" constant=\"20\" id=\"yxC-L7-Ula\"/>\n                                    </constraints>\n                                    <connections>\n                                        <accessibilityConnection property=\"title\" destination=\"1Dp-RH-HQY\" id=\"jkj-QM-QCY\"/>\n                                    </connections>\n                                </view>\n                            </tabViewItem>\n                        </tabViewItems>\n                        <accessibility description=\"Edit Filter Navigation Bar\"/>\n                    </tabView>\n                </subviews>\n                <constraints>\n                    <constraint firstItem=\"T01-Nx-QhV\" firstAttribute=\"leading\" secondItem=\"alB-sv-LJa\" secondAttribute=\"leading\" constant=\"20\" symbolic=\"YES\" id=\"313-yA-dtJ\"/>\n                    <constraint firstItem=\"wmA-Wb-Jwj\" firstAttribute=\"firstBaseline\" secondItem=\"dLf-X5-R1o\" secondAttribute=\"firstBaseline\" id=\"6eu-sD-jeM\"/>\n                    <constraint firstItem=\"dLf-X5-R1o\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"alB-sv-LJa\" secondAttribute=\"leading\" constant=\"20\" id=\"DKh-Ad-aJF\"/>\n                    <constraint firstItem=\"T01-Nx-QhV\" firstAttribute=\"top\" secondItem=\"alB-sv-LJa\" secondAttribute=\"top\" constant=\"12\" symbolic=\"YES\" id=\"E0g-PM-axe\"/>\n                    <constraint firstItem=\"wmA-Wb-Jwj\" firstAttribute=\"leading\" secondItem=\"dLf-X5-R1o\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"OPi-GS-LqS\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"T01-Nx-QhV\" secondAttribute=\"trailing\" constant=\"20\" symbolic=\"YES\" id=\"XtM-y2-hFO\"/>\n                    <constraint firstItem=\"wmA-Wb-Jwj\" firstAttribute=\"top\" secondItem=\"T01-Nx-QhV\" secondAttribute=\"bottom\" constant=\"20\" id=\"dGJ-lM-idy\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"wmA-Wb-Jwj\" secondAttribute=\"bottom\" constant=\"20\" id=\"gnX-EQ-b9J\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"wmA-Wb-Jwj\" secondAttribute=\"trailing\" constant=\"20\" id=\"ueU-CV-8zA\"/>\n                </constraints>\n            </view>\n            <connections>\n                <outlet property=\"delegate\" destination=\"-2\" id=\"rly-7V-5kS\"/>\n            </connections>\n            <point key=\"canvasLocation\" x=\"-485.5\" y=\"182\"/>\n        </window>\n        <customObject id=\"TdM-lk-raw\" customClass=\"TVCChannelSelectionViewController\"/>\n        <numberFormatter formatterBehavior=\"default10_4\" localizesFormat=\"NO\" usesGroupingSeparator=\"NO\" groupingSize=\"0\" minimumIntegerDigits=\"0\" maximumIntegerDigits=\"42\" id=\"vGQ-Aw-wDg\" customClass=\"TPI_NumberOnlyTextFieldFormatter\">\n            <real key=\"minimum\" value=\"0.0\"/>\n            <real key=\"maximum\" value=\"1296000\"/>\n        </numberFormatter>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Chat Filter/Resources/User Interface/en.lproj/TPI_ChatFilterExtension.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"18122\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\" customObjectInstantitationMethod=\"direct\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"18122\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPI_ChatFilterExtension\">\n            <connections>\n                <outlet property=\"filterAddButton\" destination=\"un4-9j-DSX\" id=\"3et-fU-PBu\"/>\n                <outlet property=\"filterAddMenu\" destination=\"hfa-1J-jSi\" id=\"UPi-cO-5S5\"/>\n                <outlet property=\"filterArrayController\" destination=\"gVm-uR-B4M\" id=\"Cp9-Xf-cPv\"/>\n                <outlet property=\"filterEditButton\" destination=\"1aY-QC-Kzo\" id=\"PC2-Ob-yAg\"/>\n                <outlet property=\"filterRemoveButton\" destination=\"p1g-v9-KVk\" id=\"Gu2-Tk-deg\"/>\n                <outlet property=\"filterTable\" destination=\"xhh-gD-9rb\" id=\"FUO-oz-IOi\"/>\n                <outlet property=\"preferencesPaneView\" destination=\"Age-ET-si9\" id=\"YNH-Ug-slO\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Age-ET-si9\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"457\"/>\n            <subviews>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1xp-tp-X2E\">\n                    <rect key=\"frame\" x=\"92\" y=\"299\" width=\"488\" height=\"128\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" sendsActionOnEndEditing=\"YES\" id=\"IGh-Af-VcM\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">A “filter” is a powerful, customizable rule that allows you to hide messages or perform commands (including external scripts). They are triggered by specific text appearing in a message or events occurring such as join, part, quit, etc.\n\nClick the + button in the bottom left corner to add your first filter.\n\nDrag and drop filters to change their priority. The table is ranked highest priority to lowest. Only one filter can match a specific message or event. </string>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"un4-9j-DSX\">\n                    <rect key=\"frame\" x=\"93\" y=\"29\" width=\"30\" height=\"25\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"l1a-6x-RTe\"/>\n                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"tIE-Rt-Pwu\"/>\n                    </constraints>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"cTJ-QJ-tKS\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Add Filter\"/>\n                    <connections>\n                        <action selector=\"presentFilterAddMenu:\" target=\"-2\" id=\"Gln-vg-wH7\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1aY-QC-Kzo\">\n                    <rect key=\"frame\" x=\"533\" y=\"29\" width=\"45\" height=\"25\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" relation=\"greaterThanOrEqual\" constant=\"45\" id=\"NnH-eU-lfK\"/>\n                        <constraint firstAttribute=\"height\" constant=\"23\" id=\"en9-1C-Qoe\"/>\n                    </constraints>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" title=\"Edit\" bezelStyle=\"smallSquare\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"yxL-c7-9D2\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Edit Filter\"/>\n                    <connections>\n                        <action selector=\"filterEdit:\" target=\"-2\" id=\"I6w-v3-Z3K\"/>\n                        <binding destination=\"gVm-uR-B4M\" name=\"enabled\" keyPath=\"canRemove\" id=\"Bc1-fQ-e8I\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p1g-v9-KVk\">\n                    <rect key=\"frame\" x=\"124\" y=\"29\" width=\"30\" height=\"25\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"overlaps\" alignment=\"center\" lineBreakMode=\"truncatingTail\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"UvM-Ae-sCx\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <accessibility description=\"Delete Filter\"/>\n                    <connections>\n                        <action selector=\"filterRemove:\" target=\"-2\" id=\"whW-fQ-9Ve\"/>\n                        <binding destination=\"gVm-uR-B4M\" name=\"enabled\" keyPath=\"canRemove\" id=\"9H4-zs-t6R\"/>\n                    </connections>\n                </button>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"20\" horizontalPageScroll=\"10\" verticalLineScroll=\"20\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" horizontalScrollElasticity=\"none\" verticalScrollElasticity=\"none\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gPh-Vf-Ty1\">\n                    <rect key=\"frame\" x=\"93\" y=\"61\" width=\"485\" height=\"220\"/>\n                    <clipView key=\"contentView\" id=\"seO-3c-oh7\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"483\" height=\"218\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnResizing=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" rowHeight=\"18\" rowSizeStyle=\"automatic\" usesAutomaticRowHeights=\"YES\" headerView=\"L4E-jr-cQa\" viewBased=\"YES\" floatsGroupRows=\"NO\" id=\"xhh-gD-9rb\" customClass=\"TVCBasicTableView\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"483\" height=\"190\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"2\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn width=\"471\" minWidth=\"40\" maxWidth=\"1000\" id=\"iBz-kH-njW\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" title=\"Filter Description\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" title=\"Text Cell\" id=\"KdY-Up-3Jt\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                        <prototypeCellViews>\n                                            <tableCellView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ej9-iB-qgp\">\n                                                <rect key=\"frame\" x=\"1\" y=\"1\" width=\"481\" height=\"18\"/>\n                                                <subviews>\n                                                    <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QaU-xP-qMH\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"2\" width=\"481\" height=\"16\"/>\n                                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Table View Cell\" id=\"D7G-go-Bq0\">\n                                                            <font key=\"font\" metaFont=\"system\"/>\n                                                            <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                                        </textFieldCell>\n                                                        <connections>\n                                                            <binding destination=\"ej9-iB-qgp\" name=\"value\" keyPath=\"objectValue.filterDescription\" id=\"poz-jF-z9u\"/>\n                                                        </connections>\n                                                    </textField>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"QaU-xP-qMH\" secondAttribute=\"trailing\" constant=\"2\" id=\"Hm5-c7-350\"/>\n                                                    <constraint firstItem=\"QaU-xP-qMH\" firstAttribute=\"top\" secondItem=\"ej9-iB-qgp\" secondAttribute=\"top\" id=\"WJ6-OS-9MO\"/>\n                                                    <constraint firstItem=\"QaU-xP-qMH\" firstAttribute=\"leading\" secondItem=\"ej9-iB-qgp\" secondAttribute=\"leading\" constant=\"2\" id=\"wYk-Ik-nmG\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"QaU-xP-qMH\" secondAttribute=\"bottom\" constant=\"2\" id=\"zEG-FW-XFY\"/>\n                                                </constraints>\n                                                <connections>\n                                                    <outlet property=\"textField\" destination=\"QaU-xP-qMH\" id=\"Pdv-Vb-F2f\"/>\n                                                </connections>\n                                            </tableCellView>\n                                        </prototypeCellViews>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <action trigger=\"doubleAction\" selector=\"filterTableDoubleClicked:\" target=\"-2\" id=\"mq2-zP-wAj\"/>\n                                    <binding destination=\"gVm-uR-B4M\" name=\"content\" keyPath=\"arrangedObjects\" id=\"LfG-uc-cX4\"/>\n                                    <binding destination=\"gVm-uR-B4M\" name=\"selectionIndexes\" keyPath=\"selectionIndexes\" previousBinding=\"LfG-uc-cX4\" id=\"hDO-mw-Iyw\"/>\n                                    <binding destination=\"gVm-uR-B4M\" name=\"sortDescriptors\" keyPath=\"sortDescriptors\" previousBinding=\"hDO-mw-Iyw\" id=\"SuY-E9-KPr\"/>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"o37-CJ-sxy\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"xtu-9K-hYu\"/>\n                                    <outlet property=\"menu\" destination=\"xvv-Hr-20R\" id=\"Uda-fG-2QF\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"width\" constant=\"485\" id=\"AyQ-2e-aAl\"/>\n                        <constraint firstAttribute=\"height\" constant=\"220\" id=\"oPO-od-3xa\"/>\n                    </constraints>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"iJb-x6-x6a\">\n                        <rect key=\"frame\" x=\"1\" y=\"203\" width=\"483\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"cdX-i1-2vb\">\n                        <rect key=\"frame\" x=\"224\" y=\"17\" width=\"15\" height=\"102\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"L4E-jr-cQa\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"483\" height=\"28\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                    <accessibility description=\"List of Filters\"/>\n                </scrollView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"1xp-tp-X2E\" firstAttribute=\"top\" secondItem=\"Age-ET-si9\" secondAttribute=\"top\" constant=\"30\" id=\"47L-lw-89n\"/>\n                <constraint firstItem=\"gPh-Vf-Ty1\" firstAttribute=\"top\" secondItem=\"1xp-tp-X2E\" secondAttribute=\"bottom\" constant=\"18\" id=\"4qL-94-GL1\"/>\n                <constraint firstItem=\"1xp-tp-X2E\" firstAttribute=\"leading\" secondItem=\"xhh-gD-9rb\" secondAttribute=\"leading\" id=\"Anq-1T-fDX\"/>\n                <constraint firstItem=\"p1g-v9-KVk\" firstAttribute=\"firstBaseline\" secondItem=\"un4-9j-DSX\" secondAttribute=\"firstBaseline\" id=\"Dy0-A0-Enh\"/>\n                <constraint firstItem=\"1xp-tp-X2E\" firstAttribute=\"trailing\" secondItem=\"gPh-Vf-Ty1\" secondAttribute=\"trailing\" id=\"FzP-tm-pUj\"/>\n                <constraint firstItem=\"1aY-QC-Kzo\" firstAttribute=\"top\" secondItem=\"gPh-Vf-Ty1\" secondAttribute=\"bottom\" constant=\"8\" id=\"GqI-Un-LNC\"/>\n                <constraint firstItem=\"p1g-v9-KVk\" firstAttribute=\"height\" secondItem=\"un4-9j-DSX\" secondAttribute=\"height\" id=\"HTZ-Xw-SbN\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"un4-9j-DSX\" secondAttribute=\"bottom\" constant=\"30\" id=\"LUH-JP-vpY\"/>\n                <constraint firstItem=\"un4-9j-DSX\" firstAttribute=\"leading\" secondItem=\"gPh-Vf-Ty1\" secondAttribute=\"leading\" id=\"Qck-pT-anC\"/>\n                <constraint firstItem=\"p1g-v9-KVk\" firstAttribute=\"leading\" secondItem=\"un4-9j-DSX\" secondAttribute=\"trailing\" constant=\"1\" id=\"R78-e2-s6s\"/>\n                <constraint firstItem=\"gPh-Vf-Ty1\" firstAttribute=\"centerX\" secondItem=\"Age-ET-si9\" secondAttribute=\"centerX\" id=\"TJf-6h-1DU\"/>\n                <constraint firstItem=\"1aY-QC-Kzo\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"p1g-v9-KVk\" secondAttribute=\"trailing\" constant=\"20\" id=\"dcX-uG-8Ue\"/>\n                <constraint firstItem=\"p1g-v9-KVk\" firstAttribute=\"width\" secondItem=\"un4-9j-DSX\" secondAttribute=\"width\" id=\"pYr-90-irB\"/>\n                <constraint firstItem=\"1aY-QC-Kzo\" firstAttribute=\"trailing\" secondItem=\"gPh-Vf-Ty1\" secondAttribute=\"trailing\" id=\"uPi-o2-pSC\"/>\n                <constraint firstItem=\"un4-9j-DSX\" firstAttribute=\"top\" secondItem=\"gPh-Vf-Ty1\" secondAttribute=\"bottom\" constant=\"8\" id=\"vc8-xo-twR\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"522\" y=\"309.5\"/>\n        </customView>\n        <arrayController objectClassName=\"TPI_ChatFilter\" preservesSelection=\"NO\" avoidsEmptySelection=\"NO\" id=\"gVm-uR-B4M\">\n            <declaredKeys>\n                <string>filterDescription</string>\n            </declaredKeys>\n            <classReference key=\"objectClass\" className=\"TPI_ChatFilter\"/>\n        </arrayController>\n        <menu id=\"xvv-Hr-20R\" userLabel=\"Selected Filter Menu\">\n            <items>\n                <menuItem title=\"Delete\" id=\"cB7-Fc-maJ\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterRemove:\" target=\"-2\" id=\"4xy-7T-ORQ\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Duplicate\" id=\"7yu-On-a1z\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterDuplicate:\" target=\"-2\" id=\"h7g-vf-gxu\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Edit\" id=\"5PY-LI-i48\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterEdit:\" target=\"-2\" id=\"OV8-vE-f2V\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Export\" id=\"IZ6-4O-w7q\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterExport:\" target=\"-2\" id=\"fwc-MA-z19\"/>\n                    </connections>\n                </menuItem>\n            </items>\n            <point key=\"canvasLocation\" x=\"275\" y=\"-88\"/>\n        </menu>\n        <menu id=\"hfa-1J-jSi\" userLabel=\"Add Filter Menu\">\n            <items>\n                <menuItem title=\"New filter…\" id=\"twd-cR-KxM\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterAdd:\" target=\"-2\" id=\"Bgf-xu-DpK\"/>\n                    </connections>\n                </menuItem>\n                <menuItem title=\"Import filter…\" id=\"t1G-eO-sJ4\">\n                    <modifierMask key=\"keyEquivalentModifierMask\"/>\n                    <connections>\n                        <action selector=\"filterImport:\" target=\"-2\" id=\"KaQ-Zp-pwf\"/>\n                    </connections>\n                </menuItem>\n            </items>\n        </menu>\n        <menuItem isSeparatorItem=\"YES\" id=\"01e-IR-FUy\"/>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"15\" height=\"13\"/>\n        <image name=\"NSRemoveTemplate\" width=\"15\" height=\"4\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Sample Code/Preference Pane/Classes/TPI_PreferencePaneExample.h",
    "content": "\n#import \"Textual.h\"\n\n@interface TPI_PreferencePaneExample : NSObject <THOPluginProtocol>\n@property (nonatomic, strong) IBOutlet NSView *ourView;\n\n- (IBAction)preferenceChanged:(id)sender;\n@end\n"
  },
  {
    "path": "Sources/Plugins/Sample Code/Preference Pane/Classes/TPI_PreferencePaneExample.m",
    "content": "\n#import \"TPI_PreferencePaneExample.h\"\n\n@implementation TPI_PreferencePaneExample\n\n- (NSView *)pluginPreferencesPaneView\n{\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tif ([[NSBundle bundleForClass:self.class] loadNibNamed:@\"PreferencePane\" owner:self topLevelObjects:nil] == NO) {\n\t\t\tNSAssert(NO, @\"TPI_PreferencePaneExample: Failed to load view\");\n\t\t}\n\t});\n\n\treturn self.ourView;\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn @\"My Test Plugin\";\n}\n\n- (void)doSomethingWithPreferences\n{\n\tBOOL isSomethingChecked = [[NSUserDefaults standardUserDefaults] boolForKey:@\"TPI_PreferencesSomethingCheckboxIsChecked\"];\n\t\n\tif (isSomethingChecked) {\n\t\tNSLog(@\"Checkbox is checked\");\n\t} else {\n\t\tNSLog(@\"Checkbox is not checked\");\n\t}\n}\n\n- (IBAction)preferenceChanged:(id)sender\n{\n\t[self doSomethingWithPreferences];\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Sample Code/Preference Pane/PreferencePaneExample.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C0BA81020ECB0CB00C9D351 /* PreferencePane.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0BA80D20ECB0CB00C9D351 /* PreferencePane.xib */; };\n\t\t4C51BE9412D0471600E79CEB /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C51BE9312D0471600E79CEB /* Cocoa.framework */; };\n\t\t4CF30A1F20EC73480028D64F /* TPI_PreferencePaneExample.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF30A1B20EC73480028D64F /* TPI_PreferencePaneExample.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C0BA80D20ECB0CB00C9D351 /* PreferencePane.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencePane.xib; sourceTree = \"<group>\"; };\n\t\t4C0BA80F20ECB0CB00C9D351 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C51BE9312D0471600E79CEB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };\n\t\t4CF30A1A20EC73480028D64F /* TPI_PreferencePaneExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_PreferencePaneExample.h; sourceTree = \"<group>\"; };\n\t\t4CF30A1B20EC73480028D64F /* TPI_PreferencePaneExample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_PreferencePaneExample.m; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* PreferencePaneExample.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreferencePaneExample.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C51BE9412D0471600E79CEB /* Cocoa.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* PreferencePaneExample */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CF30A1920EC73480028D64F /* Classes */,\n\t\t\t\t4CF30A1C20EC73480028D64F /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = PreferencePaneExample;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C51BE9312D0471600E79CEB /* Cocoa.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* PreferencePaneExample.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C0BA80C20ECB0CB00C9D351 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C0BA80D20ECB0CB00C9D351 /* PreferencePane.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C0BA80E20ECB0CB00C9D351 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C0BA80F20ECB0CB00C9D351 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CF30A1920EC73480028D64F /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CF30A1A20EC73480028D64F /* TPI_PreferencePaneExample.h */,\n\t\t\t\t4CF30A1B20EC73480028D64F /* TPI_PreferencePaneExample.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CF30A1C20EC73480028D64F /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C0BA80E20ECB0CB00C9D351 /* Property Lists */,\n\t\t\t\t4C0BA80C20ECB0CB00C9D351 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* PreferencePaneExample */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"PreferencePaneExample\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = PreferencePaneExample;\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = PreferencePaneExample;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* PreferencePaneExample.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1000;\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"PreferencePaneExample\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = English;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\tEnglish,\n\t\t\t\tJapanese,\n\t\t\t\tFrench,\n\t\t\t\tGerman,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* PreferencePaneExample */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* PreferencePaneExample */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C0BA81020ECB0CB00C9D351 /* PreferencePane.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CF30A1F20EC73480028D64F /* TPI_PreferencePaneExample.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = /Applications/Textual.app/Contents/MacOS/Textual;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\\\"/Applications/Textual.app/Contents/Frameworks/**\\\"\";\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tHEADER_SEARCH_PATHS = \"\\\"/Applications/Textual.app/Contents/Headers/**\\\"\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property List/Info.plist\";\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-PreferencePaneExample\";\n\t\t\t\tPRODUCT_NAME = PreferencePaneExample;\n\t\t\t\tWRAPPER_EXTENSION = bundle;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = /Applications/Textual.app/Contents/MacOS/Textual;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = \"\\\"/Applications/Textual.app/Contents/Frameworks/**\\\"\";\n\t\t\t\tHEADER_SEARCH_PATHS = \"\\\"/Applications/Textual.app/Contents/Headers/**\\\"\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property List/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-PreferencePaneExample\";\n\t\t\t\tPRODUCT_NAME = PreferencePaneExample;\n\t\t\t\tWRAPPER_EXTENSION = bundle;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"PreferencePaneExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"PreferencePaneExample\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Sample Code/Preference Pane/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>English</string>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>6.0.0</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPI_PreferencePaneExample</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Sample Code/Preference Pane/Resources/User Interface/PreferencePane.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPI_PreferencePaneExample\">\n            <connections>\n                <outlet property=\"ourView\" destination=\"1\" id=\"16\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"406\"/>\n            <subviews>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2\">\n                    <rect key=\"frame\" x=\"290\" y=\"225\" width=\"90\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Do Something\" id=\"3\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"controlColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"17\">\n                    <rect key=\"frame\" x=\"268\" y=\"163\" width=\"132\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Check something\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"18\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"preferenceChanged:\" target=\"-2\" id=\"22\"/>\n                        <binding destination=\"23\" name=\"value\" keyPath=\"values.TPI_PreferencesSomethingCheckboxIsChecked\" id=\"TbS-CI-9YK\"/>\n                    </connections>\n                </button>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"17\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"28\"/>\n                <constraint firstItem=\"17\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"0sE-rw-xR4\"/>\n                <constraint firstItem=\"2\" firstAttribute=\"top\" secondItem=\"1\" secondAttribute=\"top\" constant=\"165\" id=\"69s-Mq-Or8\"/>\n                <constraint firstItem=\"17\" firstAttribute=\"top\" secondItem=\"2\" secondAttribute=\"bottom\" constant=\"45\" id=\"JeF-w3-50M\"/>\n                <constraint firstItem=\"2\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"nQG-KC-Kp3\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"373.5\" y=\"362\"/>\n        </customView>\n        <userDefaultsController id=\"23\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Classes/TPISmileyConverter.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPISmileyConverter : NSObject <THOPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Classes/TPISmileyConverter.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPISmileyConverter.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPISmileyConverter ()\n@property (nonatomic, copy) NSDictionary<NSString *, NSString *> *conversionTable;\n@property (nonatomic, copy) NSArray<NSString *> *sortedSmileyList;\n@property (nonatomic, strong) IBOutlet NSView *preferencesPane;\n\n- (IBAction)preferenceChanged:(id)sender;\n@end\n\n@implementation TPISmileyConverter\n\n#pragma mark -\n#pragma mark Plugin API\n\n- (void)pluginLoadedIntoMemory\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t[TPIBundleFromClass() loadNibNamed:@\"TPISmileyConverter\" owner:self topLevelObjects:nil];\n\t});\n\n\t[self maybeBuildConversionTable];\n}\n\n- (void)maybeBuildConversionTable\n{\n\tBOOL serviceEnabled = [RZUserDefaults() boolForKey:@\"Smiley Converter Extension -> Enable Service\"];\n\n\tif (serviceEnabled == NO) {\n\t\treturn;\n\t}\n\n\t[self buildConversionTable];\n}\n\n- (void)buildConversionTable\n{\n\tNSMutableDictionary<NSString *, NSString *> *conversionTable = [NSMutableDictionary dictionary];\n\n\tNSURL *tablePath = [TPIBundleFromClass() URLForResource:@\"conversionTable\" withExtension:@\"plist\"];\n\n\t/* Load primary table */\n\tNSDictionary *tableData = [NSDictionary dictionaryWithContentsOfURL:tablePath];\n\n\tNSAssert((tableData != nil),\n\t\t@\"Failed to load conversion table\");\n\n\t[conversionTable addEntriesFromDictionary:tableData];\n\n\t/* Load larger table */\n\tif ([RZUserDefaults() boolForKey:@\"Smiley Converter Extension -> Enable Extra Emoticons\"]) {\n\t\tNSURL *tablePath2 = [TPIBundleFromClass() URLForResource:@\"conversionTable2\" withExtension:@\"plist\"];\n\n\t\tNSDictionary *tableData2 = [NSDictionary dictionaryWithContentsOfURL:tablePath2];\n\n\t\tNSAssert((tableData2 != nil),\n\t\t\t@\"Failed to load conversion table\");\n\n\t\t[conversionTable addEntriesFromDictionary:tableData2];\n\t}\n\n\t/* Save table contents */\n\tself.conversionTable = conversionTable;\n\n\tself.sortedSmileyList = conversionTable.sortedDictionaryKeysReversed;\n}\n\n- (void)destroyConversionTable\n{\n\tself.conversionTable = nil;\n\n\tself.sortedSmileyList = nil;\n}\n\n- (void)preferenceChanged:(id)sender\n{\n\t[self destroyConversionTable];\n\n\t[self maybeBuildConversionTable];\n}\n\n- (NSView *)pluginPreferencesPaneView\n{\n\treturn self.preferencesPane;\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn TPILocalizedString(@\"BasicLanguage[3kj-8f]\");\n}\n\n- (NSString *)willRenderMessage:(NSString *)newMessage forViewController:(TVCLogController *)viewController lineType:(TVCLogLineType)lineType memberType:(TVCLogLineMemberType)memberType\n{\n\tBOOL serviceEnabled = [RZUserDefaults() boolForKey:@\"Smiley Converter Extension -> Enable Service\"];\n\n\tif (serviceEnabled == NO) {\n\t\treturn newMessage;\n\t}\n\n\tif (lineType == TVCLogLineTypeAction ||\n\t\tlineType == TVCLogLineTypePrivateMessage)\n\t{\n\t\treturn [self convertStringToEmoji:newMessage];\n\t}\n\n\treturn newMessage;\n}\n\n#pragma mark -\n#pragma mark Convert API\n\n- (NSString *)convertStringToEmoji:(NSString *)string\n{\n\tNSMutableString *finalString = [string mutableCopy];\n\n\tfor (NSString *smiley in self.sortedSmileyList) {\n\t\t[self stringWithReplacedSmiley:smiley inString:finalString];\n\t}\n\n\treturn [finalString copy];\n}\n\n/* The replacement call uses a lot of work done by the actual Textual rendering engine. */\n- (void)stringWithReplacedSmiley:(NSString *)smiley inString:(NSMutableString *)inString\n{\n\tNSUInteger currentPosition = 0;\n\n\twhile (currentPosition < inString.length) {\n\t\tNSRange range = [inString rangeOfString:smiley\n\t\t\t\t\t\t\t\t\t\toptions:NSCaseInsensitiveSearch\n\t\t\t\t\t\t\t\t\t\t  range:NSMakeRange(currentPosition, (inString.length - currentPosition))];\n\n\t\tif (range.location == NSNotFound) {\n\t\t\tbreak;\n\t\t}\n\n\t\tBOOL enabled = YES;\n\n\t\tNSInteger leftLocation = (range.location - 1);\n\n\t\tif (leftLocation >= 0 && leftLocation < inString.length) {\n\t\t\tUniChar c = [inString characterAtIndex:leftLocation];\n\n\t\t\tif (c != ' ') {\n\t\t\t\tenabled = NO;\n\n\t\t\t\tgoto next_pass;\n\t\t\t}\n\t\t}\n\n\t\tNSInteger rightLocation = NSMaxRange(range);\n\n\t\tif (rightLocation < inString.length) {\n\t\t\tUniChar c = [inString characterAtIndex:rightLocation];\n\n\t\t\tif (c != ' ') {\n\t\t\t\tenabled = NO;\n\n\t\t\t\tgoto next_pass;\n\t\t\t}\n\t\t}\n\nnext_pass:\n\t\tif (enabled) {\n\t\t\tNSString *emoji = self.conversionTable[smiley];\n\n\t\t\t[inString replaceCharactersInRange:range withString:emoji];\n\n\t\t\tcurrentPosition = (range.location + emoji.length + 1);\n\t\t} else {\n\t\t\tcurrentPosition = (NSMaxRange(range) + 1);\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"3kj-8f\" = \"Smiley Converter\";\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.1</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2013 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPISmileyConverter</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Resources/Property Lists/conversionTable.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>:-)</key>\n\t<string>😊</string>\n\t<key>:)</key>\n\t<string>😊</string>\n\t<key>:o)</key>\n\t<string>😊</string>\n\t<key>:]</key>\n\t<string>😊</string>\n\t<key>:3</key>\n\t<string>😊</string>\n\t<key>:c)</key>\n\t<string>😊</string>\n\t<key>:&gt;</key>\n\t<string>😊</string>\n\t<key>=]</key>\n\t<string>😊</string>\n\t<key>8)</key>\n\t<string>😊</string>\n\t<key>=)</key>\n\t<string>😊</string>\n\t<key>:}</key>\n\t<string>😊</string>\n\t<key>:^)</key>\n\t<string>😊</string>\n\t<key>:っ)</key>\n\t<string>😊</string>\n\t<key>:-D</key>\n\t<string>😃</string>\n\t<key>:D</key>\n\t<string>😃</string>\n\t<key>8-D</key>\n\t<string>😃</string>\n\t<key>8D</key>\n\t<string>😃</string>\n\t<key>x-D</key>\n\t<string>😃</string>\n\t<key>xD</key>\n\t<string>😃</string>\n\t<key>X-D</key>\n\t<string>😃</string>\n\t<key>XD</key>\n\t<string>😃</string>\n\t<key>=-D</key>\n\t<string>😃</string>\n\t<key>=D</key>\n\t<string>😃</string>\n\t<key>=-3</key>\n\t<string>😃</string>\n\t<key>=3</key>\n\t<string>😃</string>\n\t<key>B^D</key>\n\t<string>😃</string>\n\t<key>;D</key>\n\t<string>😄</string>\n\t<key>;)</key>\n\t<string>😉</string>\n\t<key>;-)</key>\n\t<string>😉</string>\n\t<key>;P</key>\n\t<string>😜</string>\n\t<key>;p</key>\n\t<string>😜</string>\n\t<key>&gt;:P</key>\n\t<string>😝</string>\n\t<key>:-P</key>\n\t<string>😝</string>\n\t<key>:P</key>\n\t<string>😝</string>\n\t<key>X-P</key>\n\t<string>😝</string>\n\t<key>x-p</key>\n\t<string>😝</string>\n\t<key>:-p</key>\n\t<string>😝</string>\n\t<key>:p</key>\n\t<string>😝</string>\n\t<key>=p</key>\n\t<string>😝</string>\n\t<key>:-Þ</key>\n\t<string>😝</string>\n\t<key>:Þ</key>\n\t<string>😝</string>\n\t<key>:-b</key>\n\t<string>😝</string>\n\t<key>:b</key>\n\t<string>😝</string>\n\t<key>o_o</key>\n\t<string>😳</string>\n\t<key>O_O</key>\n\t<string>😳</string>\n\t<key>o_O</key>\n\t<string>😳</string>\n\t<key>O_o</key>\n\t<string>😳</string>\n\t<key>0_o</key>\n\t<string>😳</string>\n\t<key>o_0</key>\n\t<string>😳</string>\n\t<key>o.o</key>\n\t<string>😳</string>\n\t<key>0_0</key>\n\t<string>😳</string>\n\t<key>O.O</key>\n\t<string>😳</string>\n\t<key>o.O</key>\n\t<string>😳</string>\n\t<key>O.o</key>\n\t<string>😳</string>\n\t<key>:@</key>\n\t<string>😡</string>\n\t<key>&gt;.&lt;</key>\n\t<string>😣</string>\n\t<key>&gt;_&lt;</key>\n\t<string>😫</string>\n\t<key>:(</key>\n\t<string>😞</string>\n\t<key>:-(</key>\n\t<string>😞</string>\n\t<key>n_n</key>\n\t<string>😄</string>\n\t<key>u_u</key>\n\t<string>😔</string>\n\t<key>^_^&apos;</key>\n\t<string>😅</string>\n\t<key>^_^</key>\n\t<string>😄</string>\n\t<key>^.^</key>\n\t<string>😊</string>\n\t<key>x.x</key>\n\t<string>😵</string>\n\t<key>X.x</key>\n\t<string>😵</string>\n\t<key>X.X</key>\n\t<string>😵</string>\n\t<key>x_x</key>\n\t<string>😵</string>\n\t<key>x_X</key>\n\t<string>😵</string>\n\t<key>X_x</key>\n\t<string>😵</string>\n\t<key>X_X</key>\n\t<string>😵</string>\n\t<key>x.X</key>\n\t<string>😵</string>\n\t<key>DD:</key>\n\t<string>😫</string>\n\t<key>D:&lt;</key>\n\t<string>😧</string>\n\t<key>D:</key>\n\t<string>😧</string>\n\t<key>D;</key>\n\t<string>😧</string>\n\t<key>D=</key>\n\t<string>😧</string>\n\t<key>v.v</key>\n\t<string>😧</string>\n\t<key>D-&apos;:</key>\n\t<string>😧</string>\n\t<key>:s</key>\n\t<string>😖</string>\n\t<key>:S</key>\n\t<string>😖</string>\n\t<key>._.&apos;</key>\n\t<string>😰</string>\n\t<key>._.</key>\n\t<string>😞</string>\n\t<key>;_;</key>\n\t<string>😢</string>\n\t<key>;__;</key>\n\t<string>😢</string>\n\t<key>T_T</key>\n\t<string>😭</string>\n\t<key>T.T</key>\n\t<string>😭</string>\n\t<key>:-|</key>\n\t<string>😐</string>\n\t<key>:|</key>\n\t<string>😐</string>\n\t<key>:o</key>\n\t<string>😯</string>\n\t<key>:-o</key>\n\t<string>😯</string>\n\t<key>:O</key>\n\t<string>😱</string>\n\t<key>:-O</key>\n\t<string>😱</string>\n\t<key>:0</key>\n\t<string>😱</string>\n\t<key>:-0</key>\n\t<string>😱</string>\n\t<key>-_-</key>\n\t<string>😑</string>\n\t<key>-.-</key>\n\t<string>😑</string>\n\t<key>:***</key>\n\t<string>😘</string>\n\t<key>:**</key>\n\t<string>😘</string>\n\t<key>:*</key>\n\t<string>😚</string>\n\t<key>:/</key>\n\t<string>😕</string>\n\t<key>:-/</key>\n\t<string>😕</string>\n\t<key>;/</key>\n\t<string>😕</string>\n\t<key>;-/</key>\n\t<string>😕</string>\n\t<key>&lt;3</key>\n\t<string>❤</string>\n\t<key>&gt;:</key>\n\t<string>😡</string>\n\t<key>&gt;.&gt;</key>\n\t<string>😒</string>\n\t<key>&gt;_&gt;</key>\n\t<string>😒</string>\n\t<key>&lt;_&lt;</key>\n\t<string>😒</string>\n\t<key>&lt;.&lt;</key>\n\t<string>😒</string>\n\t<key>:goat:</key>\n\t<string>🐐</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Resources/Property Lists/conversionTable2.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>:+1:</key>\n\t<string>👍</string>\n\t<key>:-1:</key>\n\t<string>👎</string>\n\t<key>:100:</key>\n\t<string>💯</string>\n\t<key>:1234:</key>\n\t<string>🔢</string>\n\t<key>:8ball:</key>\n\t<string>🎱</string>\n\t<key>:a:</key>\n\t<string>🅰</string>\n\t<key>:ab:</key>\n\t<string>🆎</string>\n\t<key>:abc:</key>\n\t<string>🔤</string>\n\t<key>:abcd:</key>\n\t<string>🔡</string>\n\t<key>:accept:</key>\n\t<string>🉑</string>\n\t<key>:aerial_tramway:</key>\n\t<string>🚡</string>\n\t<key>:airplane:</key>\n\t<string>✈</string>\n\t<key>:alarm_clock:</key>\n\t<string>⏰</string>\n\t<key>:alien:</key>\n\t<string>👽</string>\n\t<key>:ambulance:</key>\n\t<string>🚑</string>\n\t<key>:anchor:</key>\n\t<string>⚓</string>\n\t<key>:angel:</key>\n\t<string>👼</string>\n\t<key>:anger:</key>\n\t<string>💢</string>\n\t<key>:angry:</key>\n\t<string>😠</string>\n\t<key>:anguished:</key>\n\t<string>😧</string>\n\t<key>:ant:</key>\n\t<string>🐜</string>\n\t<key>:apple:</key>\n\t<string>🍎</string>\n\t<key>:aquarius:</key>\n\t<string>♒</string>\n\t<key>:aries:</key>\n\t<string>♈</string>\n\t<key>:arrow_backward:</key>\n\t<string>◀</string>\n\t<key>:arrow_double_down:</key>\n\t<string>⏬</string>\n\t<key>:arrow_double_up:</key>\n\t<string>⏫</string>\n\t<key>:arrow_down:</key>\n\t<string>⬇</string>\n\t<key>:arrow_down_small:</key>\n\t<string>🔽</string>\n\t<key>:arrow_forward:</key>\n\t<string>▶</string>\n\t<key>:arrow_heading_down:</key>\n\t<string>⤵</string>\n\t<key>:arrow_heading_up:</key>\n\t<string>⤴</string>\n\t<key>:arrow_left:</key>\n\t<string>⬅</string>\n\t<key>:arrow_lower_left:</key>\n\t<string>↙</string>\n\t<key>:arrow_lower_right:</key>\n\t<string>↘</string>\n\t<key>:arrow_right:</key>\n\t<string>➡</string>\n\t<key>:arrow_right_hook:</key>\n\t<string>↪</string>\n\t<key>:arrow_up:</key>\n\t<string>⬆</string>\n\t<key>:arrow_up_down:</key>\n\t<string>↕</string>\n\t<key>:arrow_up_small:</key>\n\t<string>🔼</string>\n\t<key>:arrow_upper_left:</key>\n\t<string>↖</string>\n\t<key>:arrow_upper_right:</key>\n\t<string>↗</string>\n\t<key>:arrows_clockwise:</key>\n\t<string>🔃</string>\n\t<key>:arrows_counterclockwise:</key>\n\t<string>🔄</string>\n\t<key>:art:</key>\n\t<string>🎨</string>\n\t<key>:articulated_lorry:</key>\n\t<string>🚛</string>\n\t<key>:astonished:</key>\n\t<string>😲</string>\n\t<key>:athletic_shoe:</key>\n\t<string>👟</string>\n\t<key>:atm:</key>\n\t<string>🏧</string>\n\t<key>:b:</key>\n\t<string>🅱</string>\n\t<key>:baby:</key>\n\t<string>👶</string>\n\t<key>:baby_bottle:</key>\n\t<string>🍼</string>\n\t<key>:baby_chick:</key>\n\t<string>🐤</string>\n\t<key>:baby_symbol:</key>\n\t<string>🚼</string>\n\t<key>:back:</key>\n\t<string>🔙</string>\n\t<key>:baggage_claim:</key>\n\t<string>🛄</string>\n\t<key>:balloon:</key>\n\t<string>🎈</string>\n\t<key>:ballot_box_with_check:</key>\n\t<string>☑</string>\n\t<key>:bamboo:</key>\n\t<string>🎍</string>\n\t<key>:banana:</key>\n\t<string>🍌</string>\n\t<key>:bangbang:</key>\n\t<string>‼</string>\n\t<key>:bank:</key>\n\t<string>🏦</string>\n\t<key>:bar_chart:</key>\n\t<string>📊</string>\n\t<key>:barber:</key>\n\t<string>💈</string>\n\t<key>:baseball:</key>\n\t<string>⚾</string>\n\t<key>:basketball:</key>\n\t<string>🏀</string>\n\t<key>:bath:</key>\n\t<string>🛀</string>\n\t<key>:bathtub:</key>\n\t<string>🛁</string>\n\t<key>:battery:</key>\n\t<string>🔋</string>\n\t<key>:bear:</key>\n\t<string>🐻</string>\n\t<key>:bee:</key>\n\t<string>🐝</string>\n\t<key>:beer:</key>\n\t<string>🍺</string>\n\t<key>:beers:</key>\n\t<string>🍻</string>\n\t<key>:beetle:</key>\n\t<string>🐞</string>\n\t<key>:beginner:</key>\n\t<string>🔰</string>\n\t<key>:bell:</key>\n\t<string>🔔</string>\n\t<key>:bento:</key>\n\t<string>🍱</string>\n\t<key>:bicyclist:</key>\n\t<string>🚴</string>\n\t<key>:bike:</key>\n\t<string>🚲</string>\n\t<key>:bikini:</key>\n\t<string>👙</string>\n\t<key>:bird:</key>\n\t<string>🐦</string>\n\t<key>:birthday:</key>\n\t<string>🎂</string>\n\t<key>:black_circle:</key>\n\t<string>⚫</string>\n\t<key>:black_joker:</key>\n\t<string>🃏</string>\n\t<key>:black_large_square:</key>\n\t<string>⬛</string>\n\t<key>:black_medium_small_square:</key>\n\t<string>◾</string>\n\t<key>:black_medium_square:</key>\n\t<string>◼</string>\n\t<key>:black_nib:</key>\n\t<string>✒</string>\n\t<key>:black_small_square:</key>\n\t<string>▪</string>\n\t<key>:black_square_button:</key>\n\t<string>🔲</string>\n\t<key>:blossom:</key>\n\t<string>🌼</string>\n\t<key>:blowfish:</key>\n\t<string>🐡</string>\n\t<key>:blue_book:</key>\n\t<string>📘</string>\n\t<key>:blue_car:</key>\n\t<string>🚙</string>\n\t<key>:blue_heart:</key>\n\t<string>💙</string>\n\t<key>:blush:</key>\n\t<string>😊</string>\n\t<key>:boar:</key>\n\t<string>🐗</string>\n\t<key>:boat:</key>\n\t<string>⛵</string>\n\t<key>:bomb:</key>\n\t<string>💣</string>\n\t<key>:book:</key>\n\t<string>📖</string>\n\t<key>:bookmark:</key>\n\t<string>🔖</string>\n\t<key>:bookmark_tabs:</key>\n\t<string>📑</string>\n\t<key>:books:</key>\n\t<string>📚</string>\n\t<key>:boom:</key>\n\t<string>💥</string>\n\t<key>:boot:</key>\n\t<string>👢</string>\n\t<key>:bouquet:</key>\n\t<string>💐</string>\n\t<key>:bow:</key>\n\t<string>🙇</string>\n\t<key>:bowling:</key>\n\t<string>🎳</string>\n\t<key>:boy:</key>\n\t<string>👦</string>\n\t<key>:bread:</key>\n\t<string>🍞</string>\n\t<key>:bride_with_veil:</key>\n\t<string>👰</string>\n\t<key>:bridge_at_night:</key>\n\t<string>🌉</string>\n\t<key>:briefcase:</key>\n\t<string>💼</string>\n\t<key>:broken_heart:</key>\n\t<string>💔</string>\n\t<key>:bug:</key>\n\t<string>🐛</string>\n\t<key>:bulb:</key>\n\t<string>💡</string>\n\t<key>:bullettrain_front:</key>\n\t<string>🚅</string>\n\t<key>:bullettrain_side:</key>\n\t<string>🚄</string>\n\t<key>:bus:</key>\n\t<string>🚌</string>\n\t<key>:busstop:</key>\n\t<string>🚏</string>\n\t<key>:bust_in_silhouette:</key>\n\t<string>👤</string>\n\t<key>:busts_in_silhouette:</key>\n\t<string>👥</string>\n\t<key>:cactus:</key>\n\t<string>🌵</string>\n\t<key>:cake:</key>\n\t<string>🍰</string>\n\t<key>:calendar:</key>\n\t<string>📆</string>\n\t<key>:calling:</key>\n\t<string>📲</string>\n\t<key>:camel:</key>\n\t<string>🐫</string>\n\t<key>:camera:</key>\n\t<string>📷</string>\n\t<key>:cancer:</key>\n\t<string>♋</string>\n\t<key>:candy:</key>\n\t<string>🍬</string>\n\t<key>:capital_abcd:</key>\n\t<string>🔠</string>\n\t<key>:capricorn:</key>\n\t<string>♑</string>\n\t<key>:car:</key>\n\t<string>🚗</string>\n\t<key>:card_index:</key>\n\t<string>📇</string>\n\t<key>:carousel_horse:</key>\n\t<string>🎠</string>\n\t<key>:cat2:</key>\n\t<string>🐈</string>\n\t<key>:cat:</key>\n\t<string>🐱</string>\n\t<key>:cd:</key>\n\t<string>💿</string>\n\t<key>:chart:</key>\n\t<string>💹</string>\n\t<key>:chart_with_downwards_trend:</key>\n\t<string>📉</string>\n\t<key>:chart_with_upwards_trend:</key>\n\t<string>📈</string>\n\t<key>:checkered_flag:</key>\n\t<string>🏁</string>\n\t<key>:cherries:</key>\n\t<string>🍒</string>\n\t<key>:cherry_blossom:</key>\n\t<string>🌸</string>\n\t<key>:chestnut:</key>\n\t<string>🌰</string>\n\t<key>:chicken:</key>\n\t<string>🐔</string>\n\t<key>:children_crossing:</key>\n\t<string>🚸</string>\n\t<key>:chocolate_bar:</key>\n\t<string>🍫</string>\n\t<key>:christmas_tree:</key>\n\t<string>🎄</string>\n\t<key>:church:</key>\n\t<string>⛪</string>\n\t<key>:cinema:</key>\n\t<string>🎦</string>\n\t<key>:circus_tent:</key>\n\t<string>🎪</string>\n\t<key>:city_sunrise:</key>\n\t<string>🌇</string>\n\t<key>:city_sunset:</key>\n\t<string>🌆</string>\n\t<key>:cl:</key>\n\t<string>🆑</string>\n\t<key>:clap:</key>\n\t<string>👏</string>\n\t<key>:clapper:</key>\n\t<string>🎬</string>\n\t<key>:clipboard:</key>\n\t<string>📋</string>\n\t<key>:clock1030:</key>\n\t<string>🕥</string>\n\t<key>:clock10:</key>\n\t<string>🕙</string>\n\t<key>:clock1130:</key>\n\t<string>🕦</string>\n\t<key>:clock11:</key>\n\t<string>🕚</string>\n\t<key>:clock1230:</key>\n\t<string>🕧</string>\n\t<key>:clock12:</key>\n\t<string>🕛</string>\n\t<key>:clock130:</key>\n\t<string>🕜</string>\n\t<key>:clock1:</key>\n\t<string>🕐</string>\n\t<key>:clock230:</key>\n\t<string>🕝</string>\n\t<key>:clock2:</key>\n\t<string>🕑</string>\n\t<key>:clock330:</key>\n\t<string>🕞</string>\n\t<key>:clock3:</key>\n\t<string>🕒</string>\n\t<key>:clock430:</key>\n\t<string>🕟</string>\n\t<key>:clock4:</key>\n\t<string>🕓</string>\n\t<key>:clock530:</key>\n\t<string>🕠</string>\n\t<key>:clock5:</key>\n\t<string>🕔</string>\n\t<key>:clock630:</key>\n\t<string>🕡</string>\n\t<key>:clock6:</key>\n\t<string>🕕</string>\n\t<key>:clock730:</key>\n\t<string>🕢</string>\n\t<key>:clock7:</key>\n\t<string>🕖</string>\n\t<key>:clock830:</key>\n\t<string>🕣</string>\n\t<key>:clock8:</key>\n\t<string>🕗</string>\n\t<key>:clock930:</key>\n\t<string>🕤</string>\n\t<key>:clock9:</key>\n\t<string>🕘</string>\n\t<key>:closed_book:</key>\n\t<string>📕</string>\n\t<key>:closed_lock_with_key:</key>\n\t<string>🔐</string>\n\t<key>:closed_umbrella:</key>\n\t<string>🌂</string>\n\t<key>:cloud:</key>\n\t<string>☁</string>\n\t<key>:clubs:</key>\n\t<string>♣</string>\n\t<key>:cocktail:</key>\n\t<string>🍸</string>\n\t<key>:coffee:</key>\n\t<string>☕</string>\n\t<key>:cold_sweat:</key>\n\t<string>😰</string>\n\t<key>:collision:</key>\n\t<string>💥</string>\n\t<key>:computer:</key>\n\t<string>💻</string>\n\t<key>:confetti_ball:</key>\n\t<string>🎊</string>\n\t<key>:confounded:</key>\n\t<string>😖</string>\n\t<key>:confused:</key>\n\t<string>😕</string>\n\t<key>:congratulations:</key>\n\t<string>㊗</string>\n\t<key>:construction:</key>\n\t<string>🚧</string>\n\t<key>:construction_worker:</key>\n\t<string>👷</string>\n\t<key>:convenience_store:</key>\n\t<string>🏪</string>\n\t<key>:cookie:</key>\n\t<string>🍪</string>\n\t<key>:cool:</key>\n\t<string>🆒</string>\n\t<key>:cop:</key>\n\t<string>👮</string>\n\t<key>:copyright:</key>\n\t<string>©</string>\n\t<key>:corn:</key>\n\t<string>🌽</string>\n\t<key>:couple:</key>\n\t<string>👫</string>\n\t<key>:couple_with_heart:</key>\n\t<string>💑</string>\n\t<key>:couplekiss:</key>\n\t<string>💏</string>\n\t<key>:cow2:</key>\n\t<string>🐄</string>\n\t<key>:cow:</key>\n\t<string>🐮</string>\n\t<key>:credit_card:</key>\n\t<string>💳</string>\n\t<key>:crescent_moon:</key>\n\t<string>🌙</string>\n\t<key>:crocodile:</key>\n\t<string>🐊</string>\n\t<key>:crossed_flags:</key>\n\t<string>🎌</string>\n\t<key>:crown:</key>\n\t<string>👑</string>\n\t<key>:cry:</key>\n\t<string>😢</string>\n\t<key>:crying_cat_face:</key>\n\t<string>😿</string>\n\t<key>:crystal_ball:</key>\n\t<string>🔮</string>\n\t<key>:cupid:</key>\n\t<string>💘</string>\n\t<key>:curly_loop:</key>\n\t<string>➰</string>\n\t<key>:currency_exchange:</key>\n\t<string>💱</string>\n\t<key>:curry:</key>\n\t<string>🍛</string>\n\t<key>:custard:</key>\n\t<string>🍮</string>\n\t<key>:customs:</key>\n\t<string>🛃</string>\n\t<key>:cyclone:</key>\n\t<string>🌀</string>\n\t<key>:dancer:</key>\n\t<string>💃</string>\n\t<key>:dancers:</key>\n\t<string>👯</string>\n\t<key>:dango:</key>\n\t<string>🍡</string>\n\t<key>:dart:</key>\n\t<string>🎯</string>\n\t<key>:dash:</key>\n\t<string>💨</string>\n\t<key>:date:</key>\n\t<string>📅</string>\n\t<key>:deciduous_tree:</key>\n\t<string>🌳</string>\n\t<key>:department_store:</key>\n\t<string>🏬</string>\n\t<key>:diamond_shape_with_a_dot_inside:</key>\n\t<string>💠</string>\n\t<key>:diamonds:</key>\n\t<string>♦</string>\n\t<key>:disappointed:</key>\n\t<string>😞</string>\n\t<key>:disappointed_relieved:</key>\n\t<string>😥</string>\n\t<key>:dizzy:</key>\n\t<string>💫</string>\n\t<key>:dizzy_face:</key>\n\t<string>😵</string>\n\t<key>:do_not_litter:</key>\n\t<string>🚯</string>\n\t<key>:dog2:</key>\n\t<string>🐕</string>\n\t<key>:dog:</key>\n\t<string>🐶</string>\n\t<key>:dollar:</key>\n\t<string>💵</string>\n\t<key>:dolls:</key>\n\t<string>🎎</string>\n\t<key>:dolphin:</key>\n\t<string>🐬</string>\n\t<key>:door:</key>\n\t<string>🚪</string>\n\t<key>:doughnut:</key>\n\t<string>🍩</string>\n\t<key>:dragon:</key>\n\t<string>🐉</string>\n\t<key>:dragon_face:</key>\n\t<string>🐲</string>\n\t<key>:dress:</key>\n\t<string>👗</string>\n\t<key>:dromedary_camel:</key>\n\t<string>🐪</string>\n\t<key>:droplet:</key>\n\t<string>💧</string>\n\t<key>:dvd:</key>\n\t<string>📀</string>\n\t<key>:e-mail:</key>\n\t<string>📧</string>\n\t<key>:ear:</key>\n\t<string>👂</string>\n\t<key>:ear_of_rice:</key>\n\t<string>🌾</string>\n\t<key>:earth_africa:</key>\n\t<string>🌍</string>\n\t<key>:earth_americas:</key>\n\t<string>🌎</string>\n\t<key>:earth_asia:</key>\n\t<string>🌏</string>\n\t<key>:egg:</key>\n\t<string>🍳</string>\n\t<key>:eggplant:</key>\n\t<string>🍆</string>\n\t<key>:eight_pointed_black_star:</key>\n\t<string>✴</string>\n\t<key>:eight_spoked_asterisk:</key>\n\t<string>✳</string>\n\t<key>:electric_plug:</key>\n\t<string>🔌</string>\n\t<key>:elephant:</key>\n\t<string>🐘</string>\n\t<key>:email:</key>\n\t<string>✉</string>\n\t<key>:end:</key>\n\t<string>🔚</string>\n\t<key>:envelope:</key>\n\t<string>✉</string>\n\t<key>:envelope_with_arrow:</key>\n\t<string>📩</string>\n\t<key>:euro:</key>\n\t<string>💶</string>\n\t<key>:european_castle:</key>\n\t<string>🏰</string>\n\t<key>:european_post_office:</key>\n\t<string>🏤</string>\n\t<key>:evergreen_tree:</key>\n\t<string>🌲</string>\n\t<key>:exclamation:</key>\n\t<string>❗</string>\n\t<key>:expressionless:</key>\n\t<string>😑</string>\n\t<key>:eyeglasses:</key>\n\t<string>👓</string>\n\t<key>:eyes:</key>\n\t<string>👀</string>\n\t<key>:facepunch:</key>\n\t<string>👊</string>\n\t<key>:factory:</key>\n\t<string>🏭</string>\n\t<key>:fallen_leaf:</key>\n\t<string>🍂</string>\n\t<key>:family:</key>\n\t<string>👪</string>\n\t<key>:fast_forward:</key>\n\t<string>⏩</string>\n\t<key>:fax:</key>\n\t<string>📠</string>\n\t<key>:fearful:</key>\n\t<string>😨</string>\n\t<key>:feet:</key>\n\t<string>🐾</string>\n\t<key>:ferris_wheel:</key>\n\t<string>🎡</string>\n\t<key>:file_folder:</key>\n\t<string>📁</string>\n\t<key>:fire:</key>\n\t<string>🔥</string>\n\t<key>:fire_engine:</key>\n\t<string>🚒</string>\n\t<key>:fireworks:</key>\n\t<string>🎆</string>\n\t<key>:first_quarter_moon:</key>\n\t<string>🌓</string>\n\t<key>:first_quarter_moon_with_face:</key>\n\t<string>🌛</string>\n\t<key>:fish:</key>\n\t<string>🐟</string>\n\t<key>:fish_cake:</key>\n\t<string>🍥</string>\n\t<key>:fishing_pole_and_fish:</key>\n\t<string>🎣</string>\n\t<key>:fist:</key>\n\t<string>✊</string>\n\t<key>:flags:</key>\n\t<string>🎏</string>\n\t<key>:flashlight:</key>\n\t<string>🔦</string>\n\t<key>:flipper:</key>\n\t<string>🐬</string>\n\t<key>:floppy_disk:</key>\n\t<string>💾</string>\n\t<key>:flower_playing_cards:</key>\n\t<string>🎴</string>\n\t<key>:flushed:</key>\n\t<string>😳</string>\n\t<key>:foggy:</key>\n\t<string>🌁</string>\n\t<key>:football:</key>\n\t<string>🏈</string>\n\t<key>:footprints:</key>\n\t<string>👣</string>\n\t<key>:fork_and_knife:</key>\n\t<string>🍴</string>\n\t<key>:fountain:</key>\n\t<string>⛲</string>\n\t<key>:four_leaf_clover:</key>\n\t<string>🍀</string>\n\t<key>:free:</key>\n\t<string>🆓</string>\n\t<key>:fried_shrimp:</key>\n\t<string>🍤</string>\n\t<key>:fries:</key>\n\t<string>🍟</string>\n\t<key>:frog:</key>\n\t<string>🐸</string>\n\t<key>:frowning:</key>\n\t<string>😦</string>\n\t<key>:fuelpump:</key>\n\t<string>⛽</string>\n\t<key>:full_moon:</key>\n\t<string>🌕</string>\n\t<key>:full_moon_with_face:</key>\n\t<string>🌝</string>\n\t<key>:game_die:</key>\n\t<string>🎲</string>\n\t<key>:gem:</key>\n\t<string>💎</string>\n\t<key>:gemini:</key>\n\t<string>♊</string>\n\t<key>:ghost:</key>\n\t<string>👻</string>\n\t<key>:gift:</key>\n\t<string>🎁</string>\n\t<key>:gift_heart:</key>\n\t<string>💝</string>\n\t<key>:girl:</key>\n\t<string>👧</string>\n\t<key>:globe_with_meridians:</key>\n\t<string>🌐</string>\n\t<key>:goat:</key>\n\t<string>🐐</string>\n\t<key>:golf:</key>\n\t<string>⛳</string>\n\t<key>:grapes:</key>\n\t<string>🍇</string>\n\t<key>:green_apple:</key>\n\t<string>🍏</string>\n\t<key>:green_book:</key>\n\t<string>📗</string>\n\t<key>:green_heart:</key>\n\t<string>💚</string>\n\t<key>:grey_exclamation:</key>\n\t<string>❕</string>\n\t<key>:grey_question:</key>\n\t<string>❔</string>\n\t<key>:grimacing:</key>\n\t<string>😬</string>\n\t<key>:grin:</key>\n\t<string>😁</string>\n\t<key>:grinning:</key>\n\t<string>😀</string>\n\t<key>:guardsman:</key>\n\t<string>💂</string>\n\t<key>:guitar:</key>\n\t<string>🎸</string>\n\t<key>:gun:</key>\n\t<string>🔫</string>\n\t<key>:haircut:</key>\n\t<string>💇</string>\n\t<key>:hamburger:</key>\n\t<string>🍔</string>\n\t<key>:hammer:</key>\n\t<string>🔨</string>\n\t<key>:hamster:</key>\n\t<string>🐹</string>\n\t<key>:hand:</key>\n\t<string>✋</string>\n\t<key>:handbag:</key>\n\t<string>👜</string>\n\t<key>:hankey:</key>\n\t<string>💩</string>\n\t<key>:hatched_chick:</key>\n\t<string>🐥</string>\n\t<key>:hatching_chick:</key>\n\t<string>🐣</string>\n\t<key>:headphones:</key>\n\t<string>🎧</string>\n\t<key>:hear_no_evil:</key>\n\t<string>🙉</string>\n\t<key>:heart:</key>\n\t<string>❤</string>\n\t<key>:heart_decoration:</key>\n\t<string>💟</string>\n\t<key>:heart_eyes:</key>\n\t<string>😍</string>\n\t<key>:heart_eyes_cat:</key>\n\t<string>😻</string>\n\t<key>:heartbeat:</key>\n\t<string>💓</string>\n\t<key>:heartpulse:</key>\n\t<string>💗</string>\n\t<key>:hearts:</key>\n\t<string>♥</string>\n\t<key>:heavy_check_mark:</key>\n\t<string>✔</string>\n\t<key>:heavy_division_sign:</key>\n\t<string>➗</string>\n\t<key>:heavy_dollar_sign:</key>\n\t<string>💲</string>\n\t<key>:heavy_exclamation_mark:</key>\n\t<string>❗</string>\n\t<key>:heavy_minus_sign:</key>\n\t<string>➖</string>\n\t<key>:heavy_multiplication_x:</key>\n\t<string>✖</string>\n\t<key>:heavy_plus_sign:</key>\n\t<string>➕</string>\n\t<key>:helicopter:</key>\n\t<string>🚁</string>\n\t<key>:herb:</key>\n\t<string>🌿</string>\n\t<key>:hibiscus:</key>\n\t<string>🌺</string>\n\t<key>:high_brightness:</key>\n\t<string>🔆</string>\n\t<key>:high_heel:</key>\n\t<string>👠</string>\n\t<key>:hocho:</key>\n\t<string>🔪</string>\n\t<key>:honey_pot:</key>\n\t<string>🍯</string>\n\t<key>:honeybee:</key>\n\t<string>🐝</string>\n\t<key>:horse:</key>\n\t<string>🐴</string>\n\t<key>:horse_racing:</key>\n\t<string>🏇</string>\n\t<key>:hospital:</key>\n\t<string>🏥</string>\n\t<key>:hotel:</key>\n\t<string>🏨</string>\n\t<key>:hotsprings:</key>\n\t<string>♨</string>\n\t<key>:hourglass:</key>\n\t<string>⌛</string>\n\t<key>:hourglass_flowing_sand:</key>\n\t<string>⏳</string>\n\t<key>:house:</key>\n\t<string>🏠</string>\n\t<key>:house_with_garden:</key>\n\t<string>🏡</string>\n\t<key>:hushed:</key>\n\t<string>😯</string>\n\t<key>:ice_cream:</key>\n\t<string>🍨</string>\n\t<key>:icecream:</key>\n\t<string>🍦</string>\n\t<key>:id:</key>\n\t<string>🆔</string>\n\t<key>:ideograph_advantage:</key>\n\t<string>🉐</string>\n\t<key>:imp:</key>\n\t<string>👿</string>\n\t<key>:inbox_tray:</key>\n\t<string>📥</string>\n\t<key>:incoming_envelope:</key>\n\t<string>📨</string>\n\t<key>:information_desk_person:</key>\n\t<string>💁</string>\n\t<key>:information_source:</key>\n\t<string>ℹ</string>\n\t<key>:innocent:</key>\n\t<string>😇</string>\n\t<key>:interrobang:</key>\n\t<string>⁉</string>\n\t<key>:iphone:</key>\n\t<string>📱</string>\n\t<key>:izakaya_lantern:</key>\n\t<string>🏮</string>\n\t<key>:jack_o_lantern:</key>\n\t<string>🎃</string>\n\t<key>:japan:</key>\n\t<string>🗾</string>\n\t<key>:japanese_castle:</key>\n\t<string>🏯</string>\n\t<key>:japanese_goblin:</key>\n\t<string>👺</string>\n\t<key>:japanese_ogre:</key>\n\t<string>👹</string>\n\t<key>:jeans:</key>\n\t<string>👖</string>\n\t<key>:joy:</key>\n\t<string>😂</string>\n\t<key>:joy_cat:</key>\n\t<string>😹</string>\n\t<key>:key:</key>\n\t<string>🔑</string>\n\t<key>:keycap_ten:</key>\n\t<string>🔟</string>\n\t<key>:kimono:</key>\n\t<string>👘</string>\n\t<key>:kiss:</key>\n\t<string>💋</string>\n\t<key>:kissing:</key>\n\t<string>😗</string>\n\t<key>:kissing_cat:</key>\n\t<string>😽</string>\n\t<key>:kissing_closed_eyes:</key>\n\t<string>😚</string>\n\t<key>:kissing_heart:</key>\n\t<string>😘</string>\n\t<key>:kissing_smiling_eyes:</key>\n\t<string>😙</string>\n\t<key>:koala:</key>\n\t<string>🐨</string>\n\t<key>:koko:</key>\n\t<string>🈁</string>\n\t<key>:lantern:</key>\n\t<string>🏮</string>\n\t<key>:large_blue_circle:</key>\n\t<string>🔵</string>\n\t<key>:large_blue_diamond:</key>\n\t<string>🔷</string>\n\t<key>:large_orange_diamond:</key>\n\t<string>🔶</string>\n\t<key>:last_quarter_moon:</key>\n\t<string>🌗</string>\n\t<key>:last_quarter_moon_with_face:</key>\n\t<string>🌜</string>\n\t<key>:laughing:</key>\n\t<string>😆</string>\n\t<key>:leaves:</key>\n\t<string>🍃</string>\n\t<key>:ledger:</key>\n\t<string>📒</string>\n\t<key>:left_luggage:</key>\n\t<string>🛅</string>\n\t<key>:left_right_arrow:</key>\n\t<string>↔</string>\n\t<key>:leftwards_arrow_with_hook:</key>\n\t<string>↩</string>\n\t<key>:lemon:</key>\n\t<string>🍋</string>\n\t<key>:leo:</key>\n\t<string>♌</string>\n\t<key>:leopard:</key>\n\t<string>🐆</string>\n\t<key>:libra:</key>\n\t<string>♎</string>\n\t<key>:light_rail:</key>\n\t<string>🚈</string>\n\t<key>:link:</key>\n\t<string>🔗</string>\n\t<key>:lips:</key>\n\t<string>👄</string>\n\t<key>:lipstick:</key>\n\t<string>💄</string>\n\t<key>:lock:</key>\n\t<string>🔒</string>\n\t<key>:lock_with_ink_pen:</key>\n\t<string>🔏</string>\n\t<key>:lollipop:</key>\n\t<string>🍭</string>\n\t<key>:loop:</key>\n\t<string>➿</string>\n\t<key>:loudspeaker:</key>\n\t<string>📢</string>\n\t<key>:love_hotel:</key>\n\t<string>🏩</string>\n\t<key>:love_letter:</key>\n\t<string>💌</string>\n\t<key>:low_brightness:</key>\n\t<string>🔅</string>\n\t<key>:m:</key>\n\t<string>Ⓜ</string>\n\t<key>:mag:</key>\n\t<string>🔍</string>\n\t<key>:mag_right:</key>\n\t<string>🔎</string>\n\t<key>:mahjong:</key>\n\t<string>🀄</string>\n\t<key>:mailbox:</key>\n\t<string>📫</string>\n\t<key>:mailbox_closed:</key>\n\t<string>📪</string>\n\t<key>:mailbox_with_mail:</key>\n\t<string>📬</string>\n\t<key>:mailbox_with_no_mail:</key>\n\t<string>📭</string>\n\t<key>:man:</key>\n\t<string>👨</string>\n\t<key>:man_with_gua_pi_mao:</key>\n\t<string>👲</string>\n\t<key>:man_with_turban:</key>\n\t<string>👳</string>\n\t<key>:mans_shoe:</key>\n\t<string>👞</string>\n\t<key>:maple_leaf:</key>\n\t<string>🍁</string>\n\t<key>:mask:</key>\n\t<string>😷</string>\n\t<key>:massage:</key>\n\t<string>💆</string>\n\t<key>:meat_on_bone:</key>\n\t<string>🍖</string>\n\t<key>:mega:</key>\n\t<string>📣</string>\n\t<key>:melon:</key>\n\t<string>🍈</string>\n\t<key>:memo:</key>\n\t<string>📝</string>\n\t<key>:mens:</key>\n\t<string>🚹</string>\n\t<key>:metro:</key>\n\t<string>🚇</string>\n\t<key>:microphone:</key>\n\t<string>🎤</string>\n\t<key>:microscope:</key>\n\t<string>🔬</string>\n\t<key>:milky_way:</key>\n\t<string>🌌</string>\n\t<key>:minibus:</key>\n\t<string>🚐</string>\n\t<key>:minidisc:</key>\n\t<string>💽</string>\n\t<key>:mobile_phone_off:</key>\n\t<string>📴</string>\n\t<key>:money_with_wings:</key>\n\t<string>💸</string>\n\t<key>:moneybag:</key>\n\t<string>💰</string>\n\t<key>:monkey:</key>\n\t<string>🐒</string>\n\t<key>:monkey_face:</key>\n\t<string>🐵</string>\n\t<key>:monorail:</key>\n\t<string>🚝</string>\n\t<key>:moon:</key>\n\t<string>🌔</string>\n\t<key>:mortar_board:</key>\n\t<string>🎓</string>\n\t<key>:mount_fuji:</key>\n\t<string>🗻</string>\n\t<key>:mountain_bicyclist:</key>\n\t<string>🚵</string>\n\t<key>:mountain_cableway:</key>\n\t<string>🚠</string>\n\t<key>:mountain_railway:</key>\n\t<string>🚞</string>\n\t<key>:mouse2:</key>\n\t<string>🐁</string>\n\t<key>:mouse:</key>\n\t<string>🐭</string>\n\t<key>:movie_camera:</key>\n\t<string>🎥</string>\n\t<key>:moyai:</key>\n\t<string>🗿</string>\n\t<key>:muscle:</key>\n\t<string>💪</string>\n\t<key>:mushroom:</key>\n\t<string>🍄</string>\n\t<key>:musical_keyboard:</key>\n\t<string>🎹</string>\n\t<key>:musical_note:</key>\n\t<string>🎵</string>\n\t<key>:musical_score:</key>\n\t<string>🎼</string>\n\t<key>:mute:</key>\n\t<string>🔇</string>\n\t<key>:nail_care:</key>\n\t<string>💅</string>\n\t<key>:name_badge:</key>\n\t<string>📛</string>\n\t<key>:necktie:</key>\n\t<string>👔</string>\n\t<key>:negative_squared_cross_mark:</key>\n\t<string>❎</string>\n\t<key>:neutral_face:</key>\n\t<string>😐</string>\n\t<key>:new:</key>\n\t<string>🆕</string>\n\t<key>:new_moon:</key>\n\t<string>🌑</string>\n\t<key>:new_moon_with_face:</key>\n\t<string>🌚</string>\n\t<key>:newspaper:</key>\n\t<string>📰</string>\n\t<key>:ng:</key>\n\t<string>🆖</string>\n\t<key>:no_bell:</key>\n\t<string>🔕</string>\n\t<key>:no_bicycles:</key>\n\t<string>🚳</string>\n\t<key>:no_entry:</key>\n\t<string>⛔</string>\n\t<key>:no_entry_sign:</key>\n\t<string>🚫</string>\n\t<key>:no_good:</key>\n\t<string>🙅</string>\n\t<key>:no_mobile_phones:</key>\n\t<string>📵</string>\n\t<key>:no_mouth:</key>\n\t<string>😶</string>\n\t<key>:no_pedestrians:</key>\n\t<string>🚷</string>\n\t<key>:no_smoking:</key>\n\t<string>🚭</string>\n\t<key>:non-potable_water:</key>\n\t<string>🚱</string>\n\t<key>:nose:</key>\n\t<string>👃</string>\n\t<key>:notebook:</key>\n\t<string>📓</string>\n\t<key>:notebook_with_decorative_cover:</key>\n\t<string>📔</string>\n\t<key>:notes:</key>\n\t<string>🎶</string>\n\t<key>:nut_and_bolt:</key>\n\t<string>🔩</string>\n\t<key>:o2:</key>\n\t<string>🅾</string>\n\t<key>:o:</key>\n\t<string>⭕</string>\n\t<key>:ocean:</key>\n\t<string>🌊</string>\n\t<key>:octopus:</key>\n\t<string>🐙</string>\n\t<key>:oden:</key>\n\t<string>🍢</string>\n\t<key>:office:</key>\n\t<string>🏢</string>\n\t<key>:ok:</key>\n\t<string>🆗</string>\n\t<key>:ok_hand:</key>\n\t<string>👌</string>\n\t<key>:ok_woman:</key>\n\t<string>🙆</string>\n\t<key>:older_man:</key>\n\t<string>👴</string>\n\t<key>:older_woman:</key>\n\t<string>👵</string>\n\t<key>:on:</key>\n\t<string>🔛</string>\n\t<key>:oncoming_automobile:</key>\n\t<string>🚘</string>\n\t<key>:oncoming_bus:</key>\n\t<string>🚍</string>\n\t<key>:oncoming_police_car:</key>\n\t<string>🚔</string>\n\t<key>:oncoming_taxi:</key>\n\t<string>🚖</string>\n\t<key>:open_book:</key>\n\t<string>📖</string>\n\t<key>:open_file_folder:</key>\n\t<string>📂</string>\n\t<key>:open_hands:</key>\n\t<string>👐</string>\n\t<key>:open_mouth:</key>\n\t<string>😮</string>\n\t<key>:ophiuchus:</key>\n\t<string>⛎</string>\n\t<key>:orange_book:</key>\n\t<string>📙</string>\n\t<key>:outbox_tray:</key>\n\t<string>📤</string>\n\t<key>:ox:</key>\n\t<string>🐂</string>\n\t<key>:package:</key>\n\t<string>📦</string>\n\t<key>:page_facing_up:</key>\n\t<string>📄</string>\n\t<key>:page_with_curl:</key>\n\t<string>📃</string>\n\t<key>:pager:</key>\n\t<string>📟</string>\n\t<key>:palm_tree:</key>\n\t<string>🌴</string>\n\t<key>:panda_face:</key>\n\t<string>🐼</string>\n\t<key>:paperclip:</key>\n\t<string>📎</string>\n\t<key>:parking:</key>\n\t<string>🅿</string>\n\t<key>:part_alternation_mark:</key>\n\t<string>〽</string>\n\t<key>:partly_sunny:</key>\n\t<string>⛅</string>\n\t<key>:passport_control:</key>\n\t<string>🛂</string>\n\t<key>:paw_prints:</key>\n\t<string>🐾</string>\n\t<key>:peach:</key>\n\t<string>🍑</string>\n\t<key>:pear:</key>\n\t<string>🍐</string>\n\t<key>:pencil2:</key>\n\t<string>✏</string>\n\t<key>:pencil:</key>\n\t<string>📝</string>\n\t<key>:penguin:</key>\n\t<string>🐧</string>\n\t<key>:pensive:</key>\n\t<string>😔</string>\n\t<key>:performing_arts:</key>\n\t<string>🎭</string>\n\t<key>:persevere:</key>\n\t<string>😣</string>\n\t<key>:person_frowning:</key>\n\t<string>🙍</string>\n\t<key>:person_with_blond_hair:</key>\n\t<string>👱</string>\n\t<key>:person_with_pouting_face:</key>\n\t<string>🙎</string>\n\t<key>:phone:</key>\n\t<string>☎</string>\n\t<key>:pig2:</key>\n\t<string>🐖</string>\n\t<key>:pig:</key>\n\t<string>🐷</string>\n\t<key>:pig_nose:</key>\n\t<string>🐽</string>\n\t<key>:pill:</key>\n\t<string>💊</string>\n\t<key>:pineapple:</key>\n\t<string>🍍</string>\n\t<key>:pisces:</key>\n\t<string>♓</string>\n\t<key>:pizza:</key>\n\t<string>🍕</string>\n\t<key>:point_down:</key>\n\t<string>👇</string>\n\t<key>:point_left:</key>\n\t<string>👈</string>\n\t<key>:point_right:</key>\n\t<string>👉</string>\n\t<key>:point_up:</key>\n\t<string>☝</string>\n\t<key>:point_up_2:</key>\n\t<string>👆</string>\n\t<key>:police_car:</key>\n\t<string>🚓</string>\n\t<key>:poodle:</key>\n\t<string>🐩</string>\n\t<key>:poop:</key>\n\t<string>💩</string>\n\t<key>:post_office:</key>\n\t<string>🏣</string>\n\t<key>:postal_horn:</key>\n\t<string>📯</string>\n\t<key>:postbox:</key>\n\t<string>📮</string>\n\t<key>:potable_water:</key>\n\t<string>🚰</string>\n\t<key>:pouch:</key>\n\t<string>👝</string>\n\t<key>:poultry_leg:</key>\n\t<string>🍗</string>\n\t<key>:pound:</key>\n\t<string>💷</string>\n\t<key>:pouting_cat:</key>\n\t<string>😾</string>\n\t<key>:pray:</key>\n\t<string>🙏</string>\n\t<key>:princess:</key>\n\t<string>👸</string>\n\t<key>:punch:</key>\n\t<string>👊</string>\n\t<key>:purple_heart:</key>\n\t<string>💜</string>\n\t<key>:purse:</key>\n\t<string>👛</string>\n\t<key>:pushpin:</key>\n\t<string>📌</string>\n\t<key>:put_litter_in_its_place:</key>\n\t<string>🚮</string>\n\t<key>:question:</key>\n\t<string>❓</string>\n\t<key>:rabbit2:</key>\n\t<string>🐇</string>\n\t<key>:rabbit:</key>\n\t<string>🐰</string>\n\t<key>:racehorse:</key>\n\t<string>🐎</string>\n\t<key>:radio:</key>\n\t<string>📻</string>\n\t<key>:radio_button:</key>\n\t<string>🔘</string>\n\t<key>:rage:</key>\n\t<string>😡</string>\n\t<key>:railway_car:</key>\n\t<string>🚃</string>\n\t<key>:rainbow:</key>\n\t<string>🌈</string>\n\t<key>:raised_hand:</key>\n\t<string>✋</string>\n\t<key>:raised_hands:</key>\n\t<string>🙌</string>\n\t<key>:raising_hand:</key>\n\t<string>🙋</string>\n\t<key>:ram:</key>\n\t<string>🐏</string>\n\t<key>:ramen:</key>\n\t<string>🍜</string>\n\t<key>:rat:</key>\n\t<string>🐀</string>\n\t<key>:recycle:</key>\n\t<string>♻</string>\n\t<key>:red_car:</key>\n\t<string>🚗</string>\n\t<key>:red_circle:</key>\n\t<string>🔴</string>\n\t<key>:registered:</key>\n\t<string>®</string>\n\t<key>:relaxed:</key>\n\t<string>☺</string>\n\t<key>:relieved:</key>\n\t<string>😌</string>\n\t<key>:repeat:</key>\n\t<string>🔁</string>\n\t<key>:repeat_one:</key>\n\t<string>🔂</string>\n\t<key>:restroom:</key>\n\t<string>🚻</string>\n\t<key>:revolving_hearts:</key>\n\t<string>💞</string>\n\t<key>:rewind:</key>\n\t<string>⏪</string>\n\t<key>:ribbon:</key>\n\t<string>🎀</string>\n\t<key>:rice:</key>\n\t<string>🍚</string>\n\t<key>:rice_ball:</key>\n\t<string>🍙</string>\n\t<key>:rice_cracker:</key>\n\t<string>🍘</string>\n\t<key>:rice_scene:</key>\n\t<string>🎑</string>\n\t<key>:ring:</key>\n\t<string>💍</string>\n\t<key>:rocket:</key>\n\t<string>🚀</string>\n\t<key>:roller_coaster:</key>\n\t<string>🎢</string>\n\t<key>:rooster:</key>\n\t<string>🐓</string>\n\t<key>:rose:</key>\n\t<string>🌹</string>\n\t<key>:rotating_light:</key>\n\t<string>🚨</string>\n\t<key>:round_pushpin:</key>\n\t<string>📍</string>\n\t<key>:rowboat:</key>\n\t<string>🚣</string>\n\t<key>:rugby_football:</key>\n\t<string>🏉</string>\n\t<key>:runner:</key>\n\t<string>🏃</string>\n\t<key>:running:</key>\n\t<string>🏃</string>\n\t<key>:running_shirt_with_sash:</key>\n\t<string>🎽</string>\n\t<key>:sa:</key>\n\t<string>🈂</string>\n\t<key>:sagittarius:</key>\n\t<string>♐</string>\n\t<key>:sailboat:</key>\n\t<string>⛵</string>\n\t<key>:sake:</key>\n\t<string>🍶</string>\n\t<key>:sandal:</key>\n\t<string>👡</string>\n\t<key>:santa:</key>\n\t<string>🎅</string>\n\t<key>:satellite:</key>\n\t<string>📡</string>\n\t<key>:satisfied:</key>\n\t<string>😆</string>\n\t<key>:saxophone:</key>\n\t<string>🎷</string>\n\t<key>:school:</key>\n\t<string>🏫</string>\n\t<key>:school_satchel:</key>\n\t<string>🎒</string>\n\t<key>:scissors:</key>\n\t<string>✂</string>\n\t<key>:scorpius:</key>\n\t<string>♏</string>\n\t<key>:scream:</key>\n\t<string>😱</string>\n\t<key>:scream_cat:</key>\n\t<string>🙀</string>\n\t<key>:scroll:</key>\n\t<string>📜</string>\n\t<key>:seat:</key>\n\t<string>💺</string>\n\t<key>:secret:</key>\n\t<string>㊙</string>\n\t<key>:see_no_evil:</key>\n\t<string>🙈</string>\n\t<key>:seedling:</key>\n\t<string>🌱</string>\n\t<key>:shaved_ice:</key>\n\t<string>🍧</string>\n\t<key>:sheep:</key>\n\t<string>🐑</string>\n\t<key>:shell:</key>\n\t<string>🐚</string>\n\t<key>:ship:</key>\n\t<string>🚢</string>\n\t<key>:shirt:</key>\n\t<string>👕</string>\n\t<key>:shit:</key>\n\t<string>💩</string>\n\t<key>:simple_smile:</key>\n\t<string>😊</string>\n\t<key>:shoe:</key>\n\t<string>👞</string>\n\t<key>:shower:</key>\n\t<string>🚿</string>\n\t<key>:signal_strength:</key>\n\t<string>📶</string>\n\t<key>:six_pointed_star:</key>\n\t<string>🔯</string>\n\t<key>:ski:</key>\n\t<string>🎿</string>\n\t<key>:skull:</key>\n\t<string>💀</string>\n\t<key>:sleeping:</key>\n\t<string>😴</string>\n\t<key>:sleepy:</key>\n\t<string>😪</string>\n\t<key>:slot_machine:</key>\n\t<string>🎰</string>\n\t<key>:small_blue_diamond:</key>\n\t<string>🔹</string>\n\t<key>:small_orange_diamond:</key>\n\t<string>🔸</string>\n\t<key>:small_red_triangle:</key>\n\t<string>🔺</string>\n\t<key>:small_red_triangle_down:</key>\n\t<string>🔻</string>\n\t<key>:smile:</key>\n\t<string>😄</string>\n\t<key>:smile_cat:</key>\n\t<string>😸</string>\n\t<key>:smiley:</key>\n\t<string>😃</string>\n\t<key>:smiley_cat:</key>\n\t<string>😺</string>\n\t<key>:smiling_imp:</key>\n\t<string>😈</string>\n\t<key>:smirk:</key>\n\t<string>😏</string>\n\t<key>:smirk_cat:</key>\n\t<string>😼</string>\n\t<key>:smoking:</key>\n\t<string>🚬</string>\n\t<key>:snail:</key>\n\t<string>🐌</string>\n\t<key>:snake:</key>\n\t<string>🐍</string>\n\t<key>:snowboarder:</key>\n\t<string>🏂</string>\n\t<key>:snowflake:</key>\n\t<string>❄</string>\n\t<key>:snowman:</key>\n\t<string>⛄</string>\n\t<key>:sob:</key>\n\t<string>😭</string>\n\t<key>:soccer:</key>\n\t<string>⚽</string>\n\t<key>:soon:</key>\n\t<string>🔜</string>\n\t<key>:sos:</key>\n\t<string>🆘</string>\n\t<key>:sound:</key>\n\t<string>🔉</string>\n\t<key>:space_invader:</key>\n\t<string>👾</string>\n\t<key>:spades:</key>\n\t<string>♠</string>\n\t<key>:spaghetti:</key>\n\t<string>🍝</string>\n\t<key>:sparkle:</key>\n\t<string>❇</string>\n\t<key>:sparkler:</key>\n\t<string>🎇</string>\n\t<key>:sparkles:</key>\n\t<string>✨</string>\n\t<key>:sparkling_heart:</key>\n\t<string>💖</string>\n\t<key>:speak_no_evil:</key>\n\t<string>🙊</string>\n\t<key>:speaker:</key>\n\t<string>🔊</string>\n\t<key>:speech_balloon:</key>\n\t<string>💬</string>\n\t<key>:speedboat:</key>\n\t<string>🚤</string>\n\t<key>:star2:</key>\n\t<string>🌟</string>\n\t<key>:star:</key>\n\t<string>⭐</string>\n\t<key>:stars:</key>\n\t<string>🌃</string>\n\t<key>:station:</key>\n\t<string>🚉</string>\n\t<key>:statue_of_liberty:</key>\n\t<string>🗽</string>\n\t<key>:steam_locomotive:</key>\n\t<string>🚂</string>\n\t<key>:stew:</key>\n\t<string>🍲</string>\n\t<key>:straight_ruler:</key>\n\t<string>📏</string>\n\t<key>:strawberry:</key>\n\t<string>🍓</string>\n\t<key>:stuck_out_tongue:</key>\n\t<string>😛</string>\n\t<key>:stuck_out_tongue_closed_eyes:</key>\n\t<string>😝</string>\n\t<key>:stuck_out_tongue_winking_eye:</key>\n\t<string>😜</string>\n\t<key>:sun_with_face:</key>\n\t<string>🌞</string>\n\t<key>:sunflower:</key>\n\t<string>🌻</string>\n\t<key>:sunglasses:</key>\n\t<string>😎</string>\n\t<key>:sunny:</key>\n\t<string>☀</string>\n\t<key>:sunrise:</key>\n\t<string>🌅</string>\n\t<key>:sunrise_over_mountains:</key>\n\t<string>🌄</string>\n\t<key>:surfer:</key>\n\t<string>🏄</string>\n\t<key>:sushi:</key>\n\t<string>🍣</string>\n\t<key>:suspension_railway:</key>\n\t<string>🚟</string>\n\t<key>:sweat:</key>\n\t<string>😓</string>\n\t<key>:sweat_drops:</key>\n\t<string>💦</string>\n\t<key>:sweat_smile:</key>\n\t<string>😅</string>\n\t<key>:sweet_potato:</key>\n\t<string>🍠</string>\n\t<key>:swimmer:</key>\n\t<string>🏊</string>\n\t<key>:symbols:</key>\n\t<string>🔣</string>\n\t<key>:syringe:</key>\n\t<string>💉</string>\n\t<key>:tada:</key>\n\t<string>🎉</string>\n\t<key>:tanabata_tree:</key>\n\t<string>🎋</string>\n\t<key>:tangerine:</key>\n\t<string>🍊</string>\n\t<key>:taurus:</key>\n\t<string>♉</string>\n\t<key>:taxi:</key>\n\t<string>🚕</string>\n\t<key>:tea:</key>\n\t<string>🍵</string>\n\t<key>:telephone:</key>\n\t<string>☎</string>\n\t<key>:telephone_receiver:</key>\n\t<string>📞</string>\n\t<key>:telescope:</key>\n\t<string>🔭</string>\n\t<key>:tennis:</key>\n\t<string>🎾</string>\n\t<key>:tent:</key>\n\t<string>⛺</string>\n\t<key>:thinking:</key>\n\t<string>🤔</string>\n\t<key>:thought_balloon:</key>\n\t<string>💭</string>\n\t<key>:thumbsdown:</key>\n\t<string>👎</string>\n\t<key>:thumbsup:</key>\n\t<string>👍</string>\n\t<key>:ticket:</key>\n\t<string>🎫</string>\n\t<key>:tiger2:</key>\n\t<string>🐅</string>\n\t<key>:tiger:</key>\n\t<string>🐯</string>\n\t<key>:tired_face:</key>\n\t<string>😫</string>\n\t<key>:tm:</key>\n\t<string>™</string>\n\t<key>:toilet:</key>\n\t<string>🚽</string>\n\t<key>:tokyo_tower:</key>\n\t<string>🗼</string>\n\t<key>:tomato:</key>\n\t<string>🍅</string>\n\t<key>:tongue:</key>\n\t<string>👅</string>\n\t<key>:top:</key>\n\t<string>🔝</string>\n\t<key>:tophat:</key>\n\t<string>🎩</string>\n\t<key>:tractor:</key>\n\t<string>🚜</string>\n\t<key>:traffic_light:</key>\n\t<string>🚥</string>\n\t<key>:train2:</key>\n\t<string>🚆</string>\n\t<key>:train:</key>\n\t<string>🚃</string>\n\t<key>:tram:</key>\n\t<string>🚊</string>\n\t<key>:triangular_flag_on_post:</key>\n\t<string>🚩</string>\n\t<key>:triangular_ruler:</key>\n\t<string>📐</string>\n\t<key>:trident:</key>\n\t<string>🔱</string>\n\t<key>:triumph:</key>\n\t<string>😤</string>\n\t<key>:trolleybus:</key>\n\t<string>🚎</string>\n\t<key>:trophy:</key>\n\t<string>🏆</string>\n\t<key>:tropical_drink:</key>\n\t<string>🍹</string>\n\t<key>:tropical_fish:</key>\n\t<string>🐠</string>\n\t<key>:truck:</key>\n\t<string>🚚</string>\n\t<key>:trumpet:</key>\n\t<string>🎺</string>\n\t<key>:tshirt:</key>\n\t<string>👕</string>\n\t<key>:tulip:</key>\n\t<string>🌷</string>\n\t<key>:turtle:</key>\n\t<string>🐢</string>\n\t<key>:tv:</key>\n\t<string>📺</string>\n\t<key>:twisted_rightwards_arrows:</key>\n\t<string>🔀</string>\n\t<key>:two_hearts:</key>\n\t<string>💕</string>\n\t<key>:two_men_holding_hands:</key>\n\t<string>👬</string>\n\t<key>:two_women_holding_hands:</key>\n\t<string>👭</string>\n\t<key>:u5272:</key>\n\t<string>🈹</string>\n\t<key>:u5408:</key>\n\t<string>🈴</string>\n\t<key>:u55b6:</key>\n\t<string>🈺</string>\n\t<key>:u6307:</key>\n\t<string>🈯</string>\n\t<key>:u6708:</key>\n\t<string>🈷</string>\n\t<key>:u6709:</key>\n\t<string>🈶</string>\n\t<key>:u6e80:</key>\n\t<string>🈵</string>\n\t<key>:u7121:</key>\n\t<string>🈚</string>\n\t<key>:u7533:</key>\n\t<string>🈸</string>\n\t<key>:u7981:</key>\n\t<string>🈲</string>\n\t<key>:u7a7a:</key>\n\t<string>🈳</string>\n\t<key>:umbrella:</key>\n\t<string>☔</string>\n\t<key>:unamused:</key>\n\t<string>😒</string>\n\t<key>:underage:</key>\n\t<string>🔞</string>\n\t<key>:unlock:</key>\n\t<string>🔓</string>\n\t<key>:up:</key>\n\t<string>🆙</string>\n\t<key>:v:</key>\n\t<string>✌</string>\n\t<key>:vertical_traffic_light:</key>\n\t<string>🚦</string>\n\t<key>:vhs:</key>\n\t<string>📼</string>\n\t<key>:vibration_mode:</key>\n\t<string>📳</string>\n\t<key>:video_camera:</key>\n\t<string>📹</string>\n\t<key>:video_game:</key>\n\t<string>🎮</string>\n\t<key>:violin:</key>\n\t<string>🎻</string>\n\t<key>:virgo:</key>\n\t<string>♍</string>\n\t<key>:volcano:</key>\n\t<string>🌋</string>\n\t<key>:vs:</key>\n\t<string>🆚</string>\n\t<key>:walking:</key>\n\t<string>🚶</string>\n\t<key>:waning_crescent_moon:</key>\n\t<string>🌘</string>\n\t<key>:waning_gibbous_moon:</key>\n\t<string>🌖</string>\n\t<key>:warning:</key>\n\t<string>⚠</string>\n\t<key>:watch:</key>\n\t<string>⌚</string>\n\t<key>:water_buffalo:</key>\n\t<string>🐃</string>\n\t<key>:watermelon:</key>\n\t<string>🍉</string>\n\t<key>:wave:</key>\n\t<string>👋</string>\n\t<key>:wavy_dash:</key>\n\t<string>〰</string>\n\t<key>:waxing_crescent_moon:</key>\n\t<string>🌒</string>\n\t<key>:waxing_gibbous_moon:</key>\n\t<string>🌔</string>\n\t<key>:wc:</key>\n\t<string>🚾</string>\n\t<key>:weary:</key>\n\t<string>😩</string>\n\t<key>:wedding:</key>\n\t<string>💒</string>\n\t<key>:whale2:</key>\n\t<string>🐋</string>\n\t<key>:whale:</key>\n\t<string>🐳</string>\n\t<key>:wheelchair:</key>\n\t<string>♿</string>\n\t<key>:white_check_mark:</key>\n\t<string>✅</string>\n\t<key>:white_circle:</key>\n\t<string>⚪</string>\n\t<key>:white_flower:</key>\n\t<string>💮</string>\n\t<key>:white_large_square:</key>\n\t<string>⬜</string>\n\t<key>:white_medium_small_square:</key>\n\t<string>◽</string>\n\t<key>:white_medium_square:</key>\n\t<string>◻</string>\n\t<key>:white_small_square:</key>\n\t<string>▫</string>\n\t<key>:white_square_button:</key>\n\t<string>🔳</string>\n\t<key>:wind_chime:</key>\n\t<string>🎐</string>\n\t<key>:wine_glass:</key>\n\t<string>🍷</string>\n\t<key>:wink:</key>\n\t<string>😉</string>\n\t<key>:wolf:</key>\n\t<string>🐺</string>\n\t<key>:woman:</key>\n\t<string>👩</string>\n\t<key>:womans_clothes:</key>\n\t<string>👚</string>\n\t<key>:womans_hat:</key>\n\t<string>👒</string>\n\t<key>:womens:</key>\n\t<string>🚺</string>\n\t<key>:worried:</key>\n\t<string>😟</string>\n\t<key>:wrench:</key>\n\t<string>🔧</string>\n\t<key>:x:</key>\n\t<string>❌</string>\n\t<key>:yellow_heart:</key>\n\t<string>💛</string>\n\t<key>:yen:</key>\n\t<string>💴</string>\n\t<key>:yum:</key>\n\t<string>😋</string>\n\t<key>:zap:</key>\n\t<string>⚡</string>\n\t<key>:zzz:</key>\n\t<string>💤</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Resources/User Interface/en.lproj/TPISmileyConverter.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17506\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17506\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPISmileyConverter\">\n            <connections>\n                <outlet property=\"preferencesPane\" destination=\"1\" id=\"yrj-oC-HQn\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"156\"/>\n            <userGuides>\n                <userLayoutGuide location=\"432\" affinity=\"minY\"/>\n                <userLayoutGuide location=\"373\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s9C-FG-WiP\">\n                    <rect key=\"frame\" x=\"144\" y=\"94\" width=\"382\" height=\"32\"/>\n                    <textFieldCell key=\"cell\" sendsActionOnEndEditing=\"YES\" title=\"This addon replaces plain text emoticons (e.g. “:-)”) with their emoji equivalent; the result of which is only visible to you.\" id=\"fQA-0x-acP\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"12\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AEE-0p-afi\">\n                    <rect key=\"frame\" x=\"150\" y=\"30\" width=\"371\" height=\"44\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"64\">\n                            <rect key=\"frame\" x=\"-2\" y=\"27\" width=\"175\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Enable Smiley Converter\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"65\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"preferenceChanged:\" target=\"-2\" id=\"hl1-Tp-jqb\"/>\n                                <binding destination=\"LeY-as-hAW\" name=\"value\" keyPath=\"values.Smiley Converter Extension -&gt; Enable Service\" id=\"2bD-6F-V3R\"/>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"d4p-fS-sg0\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"373\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Enable the www.emoji-cheat-sheet.com set of emoticons\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"nlC-dQ-P7M\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <action selector=\"preferenceChanged:\" target=\"-2\" id=\"IRd-n3-a4p\"/>\n                                <binding destination=\"LeY-as-hAW\" name=\"value\" keyPath=\"values.Smiley Converter Extension -&gt; Enable Extra Emoticons\" id=\"Hkv-nI-vbY\"/>\n                                <binding destination=\"LeY-as-hAW\" name=\"enabled\" keyPath=\"values.Smiley Converter Extension -&gt; Enable Service\" id=\"QoG-q7-Hnu\"/>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"AEE-0p-afi\" firstAttribute=\"top\" secondItem=\"s9C-FG-WiP\" secondAttribute=\"bottom\" constant=\"20\" id=\"3oW-li-kdQ\"/>\n                <constraint firstItem=\"s9C-FG-WiP\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"6QC-1C-hj5\"/>\n                <constraint firstItem=\"s9C-FG-WiP\" firstAttribute=\"top\" secondItem=\"1\" secondAttribute=\"top\" constant=\"30\" id=\"E1z-Wc-Pn2\"/>\n                <constraint firstItem=\"AEE-0p-afi\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"KwX-MQ-Vn5\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"AEE-0p-afi\" secondAttribute=\"bottom\" constant=\"30\" id=\"pA9-Of-mCj\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"63\" y=\"104\"/>\n        </customView>\n        <userDefaultsController id=\"LeY-as-hAW\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Smiley Converter/Smiley Converter Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AADF20F27D8E007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AADD20F27D8E007CA939 /* BasicLanguage.strings */; };\n\t\t4C36AAE220F27D9A007CA939 /* TPISmileyConverter.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAE020F27D9A007CA939 /* TPISmileyConverter.xib */; };\n\t\t4C46A0C820EC6BA900094EA4 /* TPISmileyConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A0C620EC6BA900094EA4 /* TPISmileyConverter.m */; };\n\t\t4C46A0D220EC6BB700094EA4 /* conversionTable2.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A0CA20EC6BB700094EA4 /* conversionTable2.plist */; };\n\t\t4C46A0D320EC6BB700094EA4 /* conversionTable.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A0CB20EC6BB700094EA4 /* conversionTable.plist */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C1D10E820EBF45200E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D10E920EBF45200E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10ED20EBF45200E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10FB20EBF45200E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D10FC20EBF45200E72D80 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10FD20EBF45200E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D10FF20EBF45200E72D80 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D110220EBF45200E72D80 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D111020EBF45200E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D111120EBF45200E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D111520EBF45200E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C36AADE20F27D8E007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C36AAE120F27D9A007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPISmileyConverter.xib; sourceTree = \"<group>\"; };\n\t\t4C46A0C620EC6BA900094EA4 /* TPISmileyConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPISmileyConverter.m; sourceTree = \"<group>\"; };\n\t\t4C46A0C720EC6BA900094EA4 /* TPISmileyConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPISmileyConverter.h; sourceTree = \"<group>\"; };\n\t\t4C46A0CA20EC6BB700094EA4 /* conversionTable2.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = conversionTable2.plist; sourceTree = \"<group>\"; };\n\t\t4C46A0CB20EC6BB700094EA4 /* conversionTable.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = conversionTable.plist; sourceTree = \"<group>\"; };\n\t\t4C46A0CC20EC6BB700094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* Smiley Converter.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"Smiley Converter.bundle\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BragSpam */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0C520EC6BA900094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BragSpam;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C69189716E3276C00BDE3A8 /* Configurations */,\n\t\t\t\t4C46A0D020EC6BB700094EA4 /* Language Files */,\n\t\t\t\t4C46A0C920EC6BB700094EA4 /* Property Lists */,\n\t\t\t\t4C46A0CD20EC6BB700094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* Smiley Converter.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D10E420EBF45200E72D80 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D10F820EBF45200E72D80 /* Common */,\n\t\t\t\t4C1D110D20EBF45200E72D80 /* Debug */,\n\t\t\t\t4C1D10E520EBF45200E72D80 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D10E520EBF45200E72D80 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D10ED20EBF45200E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D10E920EBF45200E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D10E820EBF45200E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D10F820EBF45200E72D80 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D110220EBF45200E72D80 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C1D10FF20EBF45200E72D80 /* Foundation.xcconfig */,\n\t\t\t\t4C1D10FC20EBF45200E72D80 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C1D10FD20EBF45200E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D10FB20EBF45200E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D110D20EBF45200E72D80 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D111520EBF45200E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D111120EBF45200E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D111020EBF45200E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0C520EC6BA900094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0C720EC6BA900094EA4 /* TPISmileyConverter.h */,\n\t\t\t\t4C46A0C620EC6BA900094EA4 /* TPISmileyConverter.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0C920EC6BB700094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0CB20EC6BB700094EA4 /* conversionTable.plist */,\n\t\t\t\t4C46A0CA20EC6BB700094EA4 /* conversionTable2.plist */,\n\t\t\t\t4C46A0CC20EC6BB700094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0CD20EC6BB700094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE020F27D9A007CA939 /* TPISmileyConverter.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0D020EC6BB700094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AADD20F27D8E007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C69189716E3276C00BDE3A8 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D10E420EBF45200E72D80 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* Smiley Converter Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Smiley Converter Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Smiley Converter Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BragSpam;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* Smiley Converter.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Smiley Converter Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BragSpam */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* Smiley Converter Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A0D220EC6BB700094EA4 /* conversionTable2.plist in Resources */,\n\t\t\t\t4C46A0D320EC6BB700094EA4 /* conversionTable.plist in Resources */,\n\t\t\t\t4C36AADF20F27D8E007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t\t4C36AAE220F27D9A007CA939 /* TPISmileyConverter.xib in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A0C820EC6BA900094EA4 /* TPISmileyConverter.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AADD20F27D8E007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AADE20F27D8E007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAE020F27D9A007CA939 /* TPISmileyConverter.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAE120F27D9A007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPISmileyConverter.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SmileyConverter\";\n\t\t\t\tPRODUCT_NAME = \"Smiley Converter\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SmileyConverter\";\n\t\t\t\tPRODUCT_NAME = \"Smiley Converter\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D111120EBF45200E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D10E920EBF45200E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C9580121FA41EA700F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4C9580131FA41EA700F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SmileyConverter\";\n\t\t\t\tPRODUCT_NAME = \"Smiley Converter\";\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Smiley Converter Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4C9580131FA41EA700F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Smiley Converter Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4C9580121FA41EA700F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Classes/SystemProfiler.h",
    "content": "\n#import <IOKit/IOKitLib.h>\n\n#import \"Textual.h\"\n\n#include <mach/mach.h>\n#include <mach/mach_host.h>\n#include <mach/host_info.h>\n#include <mach/mach_vm.h>\n\n#import <libproc.h>\n\n#include <sys/mount.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\n#include <sys/socket.h>\n#include <sys/utsname.h>\n\n#include <ifaddrs.h>\n#include <net/if.h>\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Classes/TPISystemProfiler.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2012 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#include \"SystemProfiler.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPISystemProfiler : NSObject <THOPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Classes/TPISystemProfiler.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2012 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPISystemProfiler.h\"\n#import \"TPI_SP_SysInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPISystemProfiler ()\n@property (nonatomic, strong) NSView *preferencePaneView;\n@end\n\n@implementation TPISystemProfiler\n\n#pragma mark -\n#pragma mark Memory Allocation & Deallocation\n\n/* Allocation & Deallocation */\n- (void)pluginLoadedIntoMemory\n{\n\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\tNSDictionary *defaults = @{\n\t\t\t@\"System Profiler Extension -> Feature Disabled -> GPU Model\" : @(YES),\n\t\t\t@\"System Profiler Extension -> Feature Disabled -> Disk Information\" : @(YES),\n\t\t\t@\"System Profiler Extension -> Feature Disabled -> System Uptime\" : @(YES),\n\t\t\t@\"System Profiler Extension -> Feature Disabled -> Memory Information\" : @(YES),\n\t\t\t@\"System Profiler Extension -> Feature Disabled -> Screen Resolution\" : @(YES),\n\t\t};\n\n\t\t[RZUserDefaults() registerDefaults:defaults];\n\n\t\t[TPIBundleFromClass() loadNibNamed:@\"TPISystemProfiler\" owner:self topLevelObjects:nil];\n\t});\n}\n\n#pragma mark -\n#pragma mark Preference Pane\n\n/* Preference Pane */\n- (NSView *)pluginPreferencesPaneView\n{\n\treturn self.preferencePaneView;\n}\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n\treturn TPILocalizedString(@\"BasicLanguage[dff-13]\");\n}\n\n#pragma mark -\n#pragma mark User Input\n\n- (NSArray *)subscribedUserInputCommands\n{\n\treturn @[@\"sysinfo\", @\"memory\", @\"uptime\", @\"netstats\", \n\t@\"msgcount\", @\"diskspace\", @\"style\", @\"screens\",\n\t@\"runcount\", @\"sysmem\"];\n}\n\n- (void)printDebugInformation:(NSString *)message onClient:(IRCClient *)client inChannel:(IRCChannel *)channel\n{\n\tNSArray *messages = [message componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];\n\n\tfor (NSString *messageSplit in messages) {\n\t\t[client printDebugInformation:messageSplit inChannel:channel];\n\t}\n}\n\n- (void)sendMessage:(NSString *)message onClient:(IRCClient *)client toChannel:(IRCChannel *)channel\n{\n\tNSArray *messages = [message componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];\n\n\tfor (NSString *messageSplit in messages) {\n\t\t[client sendPrivmsg:messageSplit toChannel:channel];\n\t}\n}\n\n- (void)userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t  commandString:(NSString *)commandString\n\t\t\t\t\t\t  messageString:(NSString *)messageString\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _userInputCommandInvokedOnClient:client\n\t\t\t\t\t\t\t\t commandString:commandString\n\t\t\t\t\t\t\t\t messageString:messageString];\n\t});\n}\n\n- (void)_userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t   commandString:(NSString *)commandString\n\t\t\t\t\t\t   messageString:(NSString *)messageString\n{\n\tIRCChannel *channel = mainWindow().selectedChannel;\n\n\tif (channel == nil) {\n\t\treturn;\n\t}\n\n\tBOOL quietMessage = [messageString isEqualIgnoringCase:@\"quiet\"];\n\n\tNSString *messageOut = nil;\n\n\tif ([commandString isEqualToString:@\"SYSINFO\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput systemInformation];\n\t} else if ([commandString isEqualToString:@\"MEMORY\"]) {\n\t\tNSString *memoryMessage = [TPI_SP_CompiledOutput applicationMemoryUsage];\n\n\t\tif (quietMessage) {\n\t\t\t[self printDebugInformation:memoryMessage onClient:client inChannel:channel];\n\t\t} else {\n\t\t\t[self sendMessage:memoryMessage onClient:client toChannel:channel];\n\t\t}\n\n\t\tNSString *webKitMemoryUse = [TPI_SP_CompiledOutput webKitFrameworkMemoryUsage];\n\n\t\tif (webKitMemoryUse) {\n\t\t\t[self printDebugInformation:webKitMemoryUse onClient:client inChannel:channel];\n\t\t}\n\t} else if ([commandString isEqualToString:@\"UPTIME\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput applicationAndSystemUptime];\n\t} else if ([commandString isEqualToString:@\"NETSTATS\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput systemNetworkInformation];\n\t} else if ([commandString isEqualToString:@\"MSGCOUNT\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput applicationBandwidthStatistics];\n\t} else if ([commandString isEqualToString:@\"DISKSPACE\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput systemDiskspaceInformation];\n\t} else if ([commandString isEqualToString:@\"STYLE\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput applicationActiveStyle];\n\t} else if ([commandString isEqualToString:@\"SCREENS\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput systemDisplayInformation];\n\t} else if ([commandString isEqualToString:@\"RUNCOUNT\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput applicationRuntimeStatistics];\n\t} else if ([commandString isEqualToString:@\"SYSMEM\"]) {\n\t\tmessageOut = [TPI_SP_CompiledOutput systemMemoryInformation];\n\t}\n\n\tif (messageOut) {\n\t\tif (quietMessage) {\n\t\t\t[self printDebugInformation:messageOut onClient:client inChannel:channel];\n\t\t} else {\n\t\t\t[self sendMessage:messageOut onClient:client toChannel:channel];\n\t\t}\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Classes/TPI_SP_SysInfo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2012 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#include \"SystemProfiler.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_SP_CompiledOutput : NSObject\n+ (NSString *)applicationActiveStyle;\n+ (NSString *)applicationAndSystemUptime;\n+ (NSString *)applicationBandwidthStatistics;\n+ (NSString *)applicationMemoryUsage;\n+ (NSString *)applicationRuntimeStatistics;\n+ (NSString *)systemDiskspaceInformation;\n+ (NSString *)systemDisplayInformation;\n+ (NSString *)systemInformation;\n+ (NSString *)systemMemoryInformation;\n+ (NSString *)systemNetworkInformation;\n+ (nullable NSString *)webKitFrameworkMemoryUsage;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Classes/TPI_SP_SysInfo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2012 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <WebKit/WebKit.h>\n\n#import \"TPI_SP_SysInfo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define _localVolumeBaseDirectory\t\t@\"/Volumes\"\n\n#define _systemMemoryDivisor\t\t\t1.073741824\n\n@interface WKWebView ()\n@property (nonatomic, readonly) pid_t _webProcessIdentifier;\n@end\n\n@interface TPI_SP_WebViewProcessInfo : NSObject\n@property (nonatomic, assign) pid_t processIdentifier;\n@property (nonatomic, assign) uint64_t processMemoryUse;\n@property (nonatomic, strong) NSArray<NSString *> *processViewNames;\n@end\n\n@interface TPI_SP_SysInfo : NSObject\n+ (nullable NSString *)modelIdentifier;\n\n+ (nullable NSString *)processor;\n+ (NSUInteger)processorPhysicalCoreCount;\n+ (NSUInteger)processorVirtualCoreCount;\n+ (nullable NSString *)processorClockSpeed;\n\n+ (NSTimeInterval)systemUptime;\n+ (NSTimeInterval)applicationUptime;\n\n+ (uint64_t)freeMemorySize;\n+ (uint64_t)totalMemorySize;\n\n+ (uint64_t)applicationMemoryInformation;\n\n+ (nullable NSString *)formattedGraphicsCardInformation;\n+ (nullable NSString *)formattedLocalVolumeDiskUsage;\n+ (NSString *)formattedTotalMemorySize;\n+ (NSString *)formattedDiskSize:(uint64_t)diskSize;\n+ (NSString *)formattedCPUFrequency:(double)frequency;\n\n+ (NSString *)descriptionForSidebarAppearance;\n+ (NSString *)descriptionForThemeAppearance;\n+ (NSString *)descriptionForThemeAppearance:(TPCThemeAppearanceType)appearance;\n\n+ (uint64_t)memoryUseForProcess:(pid_t)processIdentifier;\n\n+ (NSArray<TPI_SP_WebViewProcessInfo *> *)webViewProcessIdentifiers;\n+ (pid_t)webViewProcessIdentifierForTreeItem:(IRCTreeItem *)treeItem;\n\n+ (nullable NSString *)refreshRateForScreen:(NSScreen *)screen;\n@end\n\n@implementation TPI_SP_CompiledOutput\n\n+ (NSString *)applicationActiveStyle\n{\n\tNSString *themeName = themeController().name;\n\n\tTPCThemeStorageLocation storageLocation = themeController().storageLocation;\n\n\tNSString *storageLocationLabel = [TPCThemeController descriptionForStorageLocation:storageLocation];\n\n\tNSString *sidebarAppearance = [TPI_SP_SysInfo descriptionForSidebarAppearance];\n\tNSString *themeAppearance = [TPI_SP_SysInfo descriptionForThemeAppearance];\n\n\tNSString *appearanceText = nil;\n\n\tif ([sidebarAppearance isEqualToString:themeAppearance]) {\n\t\tappearanceText = TPILocalizedString(@\"BasicLanguage[614-dj]\", sidebarAppearance);\n\t} else {\n\t\tappearanceText = TPILocalizedString(@\"BasicLanguage[843-z4]\", themeAppearance, sidebarAppearance);\n\t}\n\n\treturn TPILocalizedString(@\"BasicLanguage[z37-85]\",\n\t\t   themeName, storageLocationLabel, appearanceText);\n}\n\n+ (NSString *)applicationAndSystemUptime\n{\n\tNSUInteger dateFormat = (NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond);\n\n\tNSString *systemUptime = TXHumanReadableTimeInterval([TPI_SP_SysInfo systemUptime], NO, dateFormat);\n\tNSString *textualUptime = TXHumanReadableTimeInterval([TPI_SP_SysInfo applicationUptime], NO, dateFormat);\n\n\treturn TPILocalizedString(@\"BasicLanguage[v03-jx]\", systemUptime, textualUptime);\n}\n\n+ (NSString *)applicationBandwidthStatistics\n{\n\tIRCClient *client = mainWindow().selectedClient;\n\n\tNSTimeInterval lastMessage = [NSDate timeIntervalSinceNow:client.lastMessageReceived];\n\n\treturn TPILocalizedString(@\"BasicLanguage[rua-9r]\",\n\t\t\t  TXFormattedNumber(worldController().messagesSent),\n\t\t\t  TXFormattedNumber(worldController().messagesReceived),\n\t\t\t  TXHumanReadableTimeInterval(lastMessage, YES, NSCalendarUnitSecond),\n\t\t\t  [TPI_SP_SysInfo formattedDiskSize:worldController().bandwidthIn],\n\t\t\t  [TPI_SP_SysInfo formattedDiskSize:worldController().bandwidthOut]);\n}\n\n+ (NSString *)applicationMemoryUsage\n{\n\tNSUInteger totalScrollbackSize = 0;\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\ttotalScrollbackSize += u.viewController.numberOfLines;\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\ttotalScrollbackSize += c.viewController.numberOfLines;\n\t\t}\n\t}\n\n\tuint64_t textualMemoryUse = [TPI_SP_SysInfo applicationMemoryInformation];\n\n\treturn TPILocalizedString(@\"BasicLanguage[scn-br]\",\n\t\t[TPI_SP_SysInfo formattedDiskSize:textualMemoryUse],\n\t\t TXFormattedNumber(totalScrollbackSize));\n}\n\n+ (nullable NSString *)webKitFrameworkMemoryUsage\n{\n\tNSArray *webViewProcesses = [TPI_SP_SysInfo webViewProcessIdentifiers];\n\n\tif (webViewProcesses.count == 0) {\n\t\treturn nil;\n\t}\n\n\tTPI_SP_WebViewProcessInfo *topProcess = webViewProcesses[0];\n\n\tNSArray *viewNameArray = topProcess.processViewNames;\n\n\tif (viewNameArray.count == 0) {\n\t\treturn nil;\n\t}\n\n\tNSString *viewName = [viewNameArray componentsJoinedByString:@\", \"];\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\tif (viewNameArray.count == 1) {\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[ioy-qc]\",\n\t\t\ttopProcess.processIdentifier,\n\t\t\t viewName,\n\t\t\t[TPI_SP_SysInfo formattedDiskSize:topProcess.processMemoryUse])];\n\t} else {\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[a00-8n]\",\n\t\t\ttopProcess.processIdentifier,\n\t\t\t viewName,\n\t\t\t[TPI_SP_SysInfo formattedDiskSize:topProcess.processMemoryUse])];\n\t}\n\n\t[resultString appendString:@\"\\n\"];\n\n\tuint64_t totalMemoryUse = 0;\n\n\tfor (TPI_SP_WebViewProcessInfo *processInfo in webViewProcesses) {\n\t\ttotalMemoryUse += processInfo.processMemoryUse;\n\t}\n\n\t[resultString appendString:\n\t TPILocalizedString(@\"BasicLanguage[a5u-m1]\",\n\t\twebViewProcesses.count,\n\t\t[TPI_SP_SysInfo formattedDiskSize:totalMemoryUse])];\n\n\treturn [resultString copy];\n}\n\n+ (NSString *)applicationRuntimeStatistics\n{\n\tNSTimeInterval runtime = [TPCApplicationInfo timeIntervalSinceApplicationInstall];\n\n\tNSTimeInterval birthday = [NSDate timeIntervalSinceNow:[TPCApplicationInfo applicationBirthday]];\n\n\tif (runtime > birthday) {\n\t\truntime = birthday;\n\t}\n\n\treturn TPILocalizedString(@\"BasicLanguage[6fn-xh]\",\n\t\t\tTXFormattedNumber([TPCApplicationInfo applicationRunCount]),\n\t\t\tTXHumanReadableTimeInterval(runtime, NO, 0));\n}\n\n+ (NSString *)systemDiskspaceInformation\n{\n\tNSMutableString *resultString = [NSMutableString string];\n\n\tNSArray *volumeAttributes = @[NSURLVolumeNameKey, NSURLVolumeTotalCapacityKey, NSURLVolumeAvailableCapacityKey];\n\n\tNSArray *volumes = [RZFileManager() mountedVolumeURLsIncludingResourceValuesForKeys:volumeAttributes options:NSVolumeEnumerationSkipHiddenVolumes];\n\n\t[volumes enumerateObjectsUsingBlock:^(NSURL *volume, NSUInteger index, BOOL *stop) {\n\t\tNSString *volumeName = [volume resourceValueForKey:NSURLVolumeNameKey];\n\n\t\tuint64_t totalSpace = [[volume resourceValueForKey:NSURLVolumeTotalCapacityKey] longLongValue];\n\t\tuint64_t freeSpace = [[volume resourceValueForKey:NSURLVolumeAvailableCapacityKey] longLongValue];\n\n\t\tif (index == 0) {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[bvr-wz]\", volumeName,\n\t\t\t\t\t\t\t\t\t\t[TPI_SP_SysInfo formattedDiskSize:totalSpace],\n\t\t\t\t\t\t\t\t\t\t[TPI_SP_SysInfo formattedDiskSize:freeSpace])];\n\t\t} else {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[lct-7h]\", volumeName,\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:totalSpace],\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:freeSpace])];\n\t\t}\n\t}];\n\n\tif (resultString.length == 0) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[ler-a5]\");\n\t} else {\n\t\treturn TPILocalizedString(@\"BasicLanguage[n6i-xd]\", resultString);\n\t}\n}\n\n+ (NSString *)systemDisplayInformation\n{\n\tNSMutableString *resultString = [NSMutableString string];\n\n\tNSArray *screens = [NSScreen screens];\n\n\t[screens enumerateObjectsUsingBlock:^(NSScreen *screen, NSUInteger index, BOOL *stop) {\n\t\tNSInteger screenNumber = (index + 1);\n\n\t\tNSString *refreshRate = [TPI_SP_SysInfo refreshRateForScreen:screen];\n\n\t\tNSString *localization = nil;\n\n\t\tif (screenNumber == 1) {\n\t\t\tif (refreshRate == nil) {\n\t\t\t\tlocalization = @\"BasicLanguage[441-8c]\";\n\t\t\t} else {\n\t\t\t\tlocalization = @\"BasicLanguage[vvt-zq]\";\n\t\t\t}\n\t\t} else {\n\t\t\tif (refreshRate == nil) {\n\t\t\t\tlocalization = @\"BasicLanguage[dd1-rp]\";\n\t\t\t} else {\n\t\t\t\tlocalization = @\"BasicLanguage[fys-ft]\";\n\t\t\t}\n\t\t}\n\n\t\tif (refreshRate == nil) {\n\t\t\trefreshRate = @\"\";\n\t\t}\n\n\t\t[resultString appendString:\n\t\t TPILocalizedString(localization,\n\t\t\tscreenNumber,\n\t\t\tscreen.screenResolutionString,\n\t\t\trefreshRate)];\n\t}];\n\n\treturn [resultString copy];\n}\n\n+ (NSString *)systemInformation\n{\n\tBOOL showCPUModel = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> CPU Model\"] == NO);\n\n#if TARGET_CPU_ARM64\n\tBOOL showGPUModel = NO;\n#elif TARGET_CPU_X86_64\n\tBOOL showGPUModel = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> GPU Model\"] == NO);\n#endif\n\n\tBOOL showDiskInfo = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> Disk Information\"] == NO);\n\tBOOL showMemory = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> Memory Information\"] == NO);\n\tBOOL showOperatingSystem = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> OS Version\"] == NO);\n\tBOOL showScreenResolution = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> Screen Resolution\"] == NO);\n\tBOOL showUptime = ([RZUserDefaults() boolForKey:@\"System Profiler Extension -> Feature Disabled -> System Uptime\"] == NO);\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[lxj-ha]\")];\n\n\tNSString *modelIdentifier = [TPI_SP_SysInfo modelIdentifier];\n\n\tif (modelIdentifier.length > 0) {\n\t\tNSString *modelsDictionaryPath = [TPIBundleFromClass() pathForResource:@\"MacintoshModels\" ofType:@\"plist\"];\n\n\t\tNSDictionary *modelsDictionary = [NSDictionary dictionaryWithContentsOfFile:modelsDictionaryPath];\n\n\t\tNSString *modelTitle = nil;\n\n\t\tif ([modelIdentifier hasPrefix:@\"VMware\"]) {\n\t\t\tmodelTitle = modelsDictionary[@\"VMware\"];\n\t\t} else if ([modelIdentifier hasPrefix:@\"Parallels\"]) {\n\t\t\tmodelTitle = modelsDictionary[@\"Parallels\"];\n\t\t} else {\n\t\t\tmodelTitle = modelsDictionary[modelIdentifier];\n\t\t}\n\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t\tif (modelTitle == nil) {\n\t\t\tmodelTitle = [XRSystemInformation systemModelName];\n\t\t}\nTEXTUAL_IGNORE_DEPRECATION_END\n\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[7g5-pf]\", modelTitle)];\n\t}\n\n\tif (showCPUModel) {\n\t\tNSString *_cpu_model = [TPI_SP_SysInfo processor];\n\n\t\tNSUInteger _cpu_count_p\t= [TPI_SP_SysInfo processorPhysicalCoreCount];\n\t\t\n#if TARGET_CPU_ARM64\n\t\t\n\t\tif (_cpu_model.length > 0) {\n\t\t\t[resultString appendString:\n\t\t\t TPILocalizedString(@\"BasicLanguage[ifk-s5]\",\n\t\t\t\t\t_cpu_model,\n\t\t\t\t\t_cpu_count_p)];\n\t\t}\n\t\t\n#elif TARGET_CPU_X86_64\n\n\t\tNSString *_cpu_speed = [TPI_SP_SysInfo processorClockSpeed];\n\n\t\tNSUInteger _cpu_count_v\t= [TPI_SP_SysInfo processorVirtualCoreCount];\n\n\t\t_cpu_model = [XRRegularExpression string:_cpu_model replacedByRegex:@\"(\\\\s*@.*)|CPU|\\\\(R\\\\)|\\\\(TM\\\\)\"\twithString:@\" \"];\n\t\t_cpu_model = [XRRegularExpression string:_cpu_model replacedByRegex:@\"\\\\s+\"\t\t\t\t\t\t\t\twithString:@\" \"];\n\n\t\t_cpu_model = _cpu_model.trim;\n\n\t\tif (_cpu_model.length > 0 && _cpu_speed.length > 0) {\n\t\t\t[resultString appendString:\n\t\t\t TPILocalizedString(@\"BasicLanguage[mnc-vx]\",\n\t\t\t\t\t_cpu_model,\n\t\t\t\t\t_cpu_count_v,\n\t\t\t\t\t_cpu_count_p,\n\t\t\t\t\t_cpu_speed)];\n\t\t}\n\n#endif\n\n\t}\n\n\tif (showMemory) {\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[1am-io]\",\n\t\t\t[TPI_SP_SysInfo formattedTotalMemorySize])];\n\t}\n\n\tif (showUptime) {\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[xb6-bh]\",\n\t\t\tTXHumanReadableTimeInterval([TPI_SP_SysInfo systemUptime], YES, 0))];\n\t}\n\n\tif (showDiskInfo) {\n\t\tNSString *_disk_info = [TPI_SP_SysInfo formattedLocalVolumeDiskUsage];\n\n\t\tif (_disk_info != nil) {\n\t\t\t[resultString appendString:\n\t\t\t TPILocalizedString(@\"BasicLanguage[yrc-6l]\", _disk_info)];\n\t\t}\n\t}\n\n\tif (showGPUModel) {\n\t\tNSString *_gpu_model = [TPI_SP_SysInfo formattedGraphicsCardInformation];\n\n\t\tif (_gpu_model != nil) {\n\t\t\t[resultString appendString:\n\t\t\t TPILocalizedString(@\"BasicLanguage[q5v-uq]\", _gpu_model)];\n\t\t}\n\t}\n\n\tif (showScreenResolution) {\n\t\tNSScreen *mainScreen = RZMainScreen();\n\n\t\tNSString *refreshRate = [TPI_SP_SysInfo refreshRateForScreen:mainScreen];\n\n\t\tif (refreshRate == nil) {\n\t\t\t[resultString appendString:\n\t\t     TPILocalizedString(@\"BasicLanguage[22o-rg]\",\n\t\t\t mainScreen.screenResolutionString)];\n\t\t} else {\n\t\t\t[resultString appendString:\n\t\t     TPILocalizedString(@\"BasicLanguage[b7c-qd]\",\n\t\t\t mainScreen.screenResolutionString,\n\t\t\t refreshRate)];\n\t\t}\n\t}\n\n\tif (showOperatingSystem) {\n\t\t[resultString appendString:\n\t\t TPILocalizedString(@\"BasicLanguage[g41-p7]\",\n\t\t\t[XRSystemInformation systemOperatingSystemName],\n\t\t\t[XRSystemInformation systemStandardVersion],\n\t\t\t[XRSystemInformation systemBuildVersion])];\n\t}\n\n\tif ([resultString hasSuffix:@\" \\002•\\002\"]) {\n\t\t[resultString deleteCharactersInRange:NSMakeRange((resultString.length - 4), 4)];\n\t}\n\n\treturn [resultString copy];\n}\n\n+ (NSString *)systemMemoryInformation\n{\n\tuint64_t totalMemory = [TPI_SP_SysInfo totalMemorySize];\n\tuint64_t freeMemory = [TPI_SP_SysInfo freeMemorySize];\n\n\tuint64_t usedMemory = (totalMemory - freeMemory);\n\n\tlong double memoryUsedPercent = (((long double)usedMemory / (long double)totalMemory) * 100.0);\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\t/* ======================================== */\n\n\t[resultString appendFormat:@\"%c04\", 0x03];\n\n\tNSUInteger leftCount = (memoryUsedPercent / 10);\n\n\tfor (NSUInteger i = 0; i <= leftCount; i++) {\n\t\t[resultString appendString:@\"❙\"];\n\t}\n\n\t/* ======================================== */\n\n\t[resultString appendFormat:@\"%c|%c03\", 0x03, 0x03];\n\n\t/* ======================================== */\n\n\tNSUInteger rightCount = (10 - leftCount);\n\n\tfor (NSUInteger i = 0; i <= rightCount; i++) {\n\t\t[resultString appendString:@\"❙\"];\n\t}\n\n\t[resultString appendFormat:@\"%c\", 0x03];\n\n\t/* ======================================== */\n\n\treturn TPILocalizedString(@\"BasicLanguage[cfs-b1]\",\n\t\t\t[TPI_SP_SysInfo formattedDiskSize:freeMemory],\n\t\t\t[TPI_SP_SysInfo formattedDiskSize:usedMemory],\n\t\t\t[TPI_SP_SysInfo formattedDiskSize:totalMemory],\n\t\t\t\t\tresultString);\n}\n\n+ (NSString *)systemNetworkInformation\n{\n\t/* Based off the source code of \"libtop.c\" */\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\tstruct ifaddrs *ifa_list = 0;\n\n\tif (getifaddrs(&ifa_list) == (-1)) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[li1-vn]\");\n\t}\n\n\tNSUInteger objectIndex = 0;\n\n\tfor (struct ifaddrs *ifa = ifa_list; ifa; ifa = ifa->ifa_next) {\n\t\tif ((AF_LINK == ifa->ifa_addr->sa_family) == NO) {\n\t\t\tcontinue;\n\t\t} else if ((ifa->ifa_flags & IFF_UP) == NO && (ifa->ifa_flags & IFF_RUNNING) == NO) {\n\t\t\tcontinue;\n\t\t} else if (ifa->ifa_data == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (strncmp(ifa->ifa_name, \"lo\", 2) == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tstruct if_data *if_data = (struct if_data *)ifa->ifa_data;\n\n\t\tif (if_data->ifi_ibytes < 20000000 || if_data->ifi_obytes < 2000000) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (objectIndex == 0) {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[ca4-25]\",\n\t\t\t\t\t\t\t\t\t\t @(ifa->ifa_name),\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:if_data->ifi_ibytes],\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:if_data->ifi_obytes])];\n\t\t} else {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[mjo-o0]\",\n\t\t\t\t\t\t\t\t\t\t @(ifa->ifa_name),\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:if_data->ifi_ibytes],\n\t\t\t\t\t\t\t\t\t\t [TPI_SP_SysInfo formattedDiskSize:if_data->ifi_obytes])];\n\t\t}\n\n\t\tobjectIndex += 1;\n\t}\n\n\tif (ifa_list) {\n\t\tfreeifaddrs(ifa_list);\n\t}\n\n\tif (resultString.length == 0) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[li1-vn]\");\n\t} else {\n\t\treturn TPILocalizedString(@\"BasicLanguage[9f8-ej]\", resultString);\n\t}\n\n\treturn resultString;\n}\n\n@end\n\n@implementation TPI_SP_SysInfo\n\n#pragma mark -\n#pragma mark Formatting/Processing \n\n+ (NSString *)formattedDiskSize:(uint64_t)diskSize\n{\n\treturn [NSByteCountFormatter stringFromByteCountWithPaddedDigits:diskSize];\n}\n\n+ (NSString *)formattedCPUFrequency:(double)frequency\n{\n\tif ((frequency / 1000000) >= 990) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[3iu-k8]\", ((frequency / 100000000.0) / 10.0));\n\t} else {\n\t\treturn TPILocalizedString(@\"BasicLanguage[jw7-sg]\", frequency);\n\t}\n}\n\n+ (NSString *)formattedTotalMemorySize\n{\n\treturn [self formattedDiskSize:[self totalMemorySize]];\n}\n\n+ (nullable NSString *)formattedLocalVolumeDiskUsage\n{\n\tNSDictionary *diskInfo = [RZFileManager() attributesOfFileSystemForPath:@\"/\" error:nil];\n\n\tif (diskInfo == nil) {\n\t\treturn nil;\n\t}\n\n\tuint64_t totalSpace = [diskInfo longLongForKey:NSFileSystemSize];\n\n\treturn [self formattedDiskSize:totalSpace];\n}\n\n+ (nullable NSString *)formattedGraphicsCardInformation\n{\n\tCFMutableDictionaryRef pciDevices = IOServiceMatching(\"IOPCIDevice\");\n\n\tio_iterator_t entryIterator;\n\n\tif (IOServiceGetMatchingServices(kIOMasterPortDefault, pciDevices, &entryIterator) != kIOReturnSuccess) {\n\t\treturn nil;\n\t}\n\n\tNSMutableArray<NSString *> *gpuModels = [NSMutableArray new];\n\n\tio_iterator_t serviceObject;\n\n\twhile ((serviceObject = IOIteratorNext(entryIterator))) {\n\t\tCFMutableDictionaryRef serviceDictionary;\n\n\t\tkern_return_t status =\n\t\tIORegistryEntryCreateCFProperties(serviceObject,\n\t\t\t\t\t\t\t\t\t\t  &serviceDictionary,\n\t\t\t\t\t\t\t\t\t\t  kCFAllocatorDefault,\n\t\t\t\t\t\t\t\t\t\t  kNilOptions);\n\n\t\tif (status != kIOReturnSuccess) {\n\t\t\tIOObjectRelease(serviceObject);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tBOOL cleanResult = YES;\n\n\t\tconst void *classCode = CFDictionaryGetValue(serviceDictionary, @\"class-code\");\n\n\t\tif (classCode == NULL) {\n\t\t\tcleanResult = NO;\n\t\t} if (CFGetTypeID(classCode) != CFDataGetTypeID()) {\n\t\t\tcleanResult = NO;\n\t\t} else if (CFDataGetLength(classCode) == 0) {\n\t\t\tcleanResult = NO;\n\t\t} else if (*(UInt32 *)CFDataGetBytePtr(classCode) != 0x30000) {\n\t\t\tcleanResult = NO;\n\t\t}\n\n\t\tconst void *model = CFDictionaryGetValue(serviceDictionary, @\"model\");\n\n\t\tif (model == NULL) {\n\t\t\tcleanResult = NO;\n\t\t} else if (CFGetTypeID(model) != CFDataGetTypeID()) {\n\t\t\tcleanResult = NO;\n\t\t} else if (CFDataGetLength(model) == 0) {\n\t\t\tcleanResult = NO;\n\t\t}\n\n\t\tif (cleanResult) {\n\t\t\tNSString *modelString = [NSString stringWithData:(__bridge NSData *)(CFDataRef)model encoding:NSASCIIStringEncoding];\n\n\t\t\tmodelString = [modelString stringByReplacingOccurrencesOfString:@\"\\0\" withString:@\"\"];\n\n\t\t\t[gpuModels addObject:modelString];\n\t\t}\n\n\t\tCFRelease(serviceDictionary);\n\t}\n\n\t// ---- //\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\t[gpuModels enumerateObjectsUsingBlock:^(NSString *gpuModel, NSUInteger index, BOOL *stop) {\n\t\tif (index == 0) {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[8nu-89]\", gpuModel)];\n\t\t} else {\n\t\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[cmk-ws]\", gpuModel)];\n\t\t}\n\t}];\n\n\treturn [resultString copy];\n}\n\n+ (NSString *)descriptionForSidebarAppearance\n{\n\tif (mainWindow().usingDarkAppearance) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[243-yt]\"); // Dark\n\t}\n\n\treturn TPILocalizedString(@\"BasicLanguage[890-au]\"); // Light\n}\n\n+ (NSString *)descriptionForThemeAppearance\n{\n\tTPCThemeAppearanceType appearance = themeController().theme.appearance;\n\n\treturn [self descriptionForThemeAppearance:appearance];\n}\n\n+ (NSString *)descriptionForThemeAppearance:(TPCThemeAppearanceType)appearance\n{\n\tif (appearance == TPCThemeAppearanceTypeDefault) {\n\t\tTXAppearance *appAppearance = [TXSharedApplication sharedAppearance];\n\n\t\tif (appAppearance.properties.isDarkAppearance) {\n\t\t\tappearance = TPCThemeAppearanceTypeDark;\n\t\t} else {\n\t\t\tappearance = TPCThemeAppearanceTypeLight;\n\t\t}\n\t}\n\n\tif (appearance == TPCThemeAppearanceTypeDark) {\n\t\treturn TPILocalizedString(@\"BasicLanguage[243-yt]\"); // Dark\n\t}\n\n\treturn TPILocalizedString(@\"BasicLanguage[890-au]\"); // Light\n}\n\n#pragma mark -\n#pragma mark System Information\n\n+ (NSTimeInterval)systemUptime\n{\n\tstruct timeval bootTime;\n\n\tsize_t bootTimeSize = sizeof(bootTime);\n\n\tif (sysctlbyname(\"kern.boottime\", &bootTime, &bootTimeSize, NULL, 0) != 0) {\n\t\tbootTime.tv_sec = 0;\n\t}\n\n\treturn [NSDate timeIntervalSinceNow:bootTime.tv_sec];\n}\n\n+ (NSTimeInterval)applicationUptime\n{\n\treturn [TPCApplicationInfo timeIntervalSinceApplicationLaunch];\n}\n\n+ (nullable NSString *)processor\n{\n\tchar buffer[256];\n\n\tsize_t bufferSize = sizeof(buffer);\n\n\tif (sysctlbyname(\"machdep.cpu.brand_string\", buffer, &bufferSize, NULL, 0) != 0) {\n\t\treturn nil;\n\t}\n\n\tbuffer[(bufferSize - 1)] = 0;\n\n\treturn @(buffer);\n}\n\n+ (nullable NSString *)modelIdentifier\n{\n\tchar buffer[256];\n\n\tsize_t bufferSize = sizeof(buffer);\n\n\tif (sysctlbyname(\"hw.model\", buffer, &bufferSize, NULL, 0) != 0) {\n\t\treturn nil;\n\t}\n\n\tbuffer[(bufferSize - 1)] = 0;\n\n\treturn @(buffer);\n}\n\n+ (NSUInteger)processorPhysicalCoreCount\n{\n\tu_int64_t coreCount = 0L;\n\n\tsize_t coreCountSize = sizeof(coreCount);\n\n\tif (sysctlbyname(\"hw.physicalcpu\", &coreCount, &coreCountSize, NULL, 0) != 0) {\n\t\treturn 0;\n\t}\n\n\treturn coreCount;\n}\n\n+ (NSUInteger)processorVirtualCoreCount\n{\n\tu_int64_t coreCount = 0L;\n\n\tsize_t coreCountSize = sizeof(coreCount);\n\n\tif (sysctlbyname(\"hw.logicalcpu\", &coreCount, &coreCountSize, NULL, 0) != 0) {\n\t\treturn 0;\n\t}\n\n\treturn coreCount;\n}\n\n+ (nullable NSString *)processorClockSpeed\n{\n\tu_int64_t clockSpeed = 0L;\n\n\tsize_t clockSpeedSize = sizeof(clockSpeed);\n\n\tif (sysctlbyname(\"hw.cpufrequency\", &clockSpeed, &clockSpeedSize, NULL, 0) != 0) {\n\t\treturn nil;\n\t}\n\n\treturn [self formattedCPUFrequency:clockSpeed];\n}\n\n+ (uint64_t)freeMemorySize\n{\n\tvm_size_t page_size;\n\n\thost_page_size(mach_host_self(), &page_size);\n\n\tvm_statistics_data_t host_info_out;\n\n\tmach_msg_type_number_t host_info_outCnt = (sizeof(vm_statistics_data_t) / sizeof(natural_t));\n\n\tif (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&host_info_out, &host_info_outCnt) != KERN_SUCCESS) {\n\t\treturn 0;\n\t}\n\n\treturn ((host_info_out.inactive_count + host_info_out.free_count) * page_size);\n}\n\n+ (uint64_t)totalMemorySize\n{\n\tuint64_t memoryTotal = 0L;\n\n\tsize_t memoryTotalSize = sizeof(memoryTotal);\n\n\tif (sysctlbyname(\"hw.memsize\", &memoryTotal, &memoryTotalSize, NULL, 0) != 0) {\n\t\treturn 0;\n\t}\n\n\treturn (memoryTotal / _systemMemoryDivisor);\n}\n\n+ (uint64_t)applicationMemoryInformation\n{\n\tpid_t processIdentifier = (pid_t)[NSProcessInfo processInfo].processIdentifier;\n\n\treturn [TPI_SP_SysInfo memoryUseForProcess:processIdentifier];\n}\n\n+ (uint64_t)memoryUseForProcess:(pid_t)processIdentifier\n{\n\tif (processIdentifier == 0) {\n\t\treturn 0;\n\t}\n\n\tint processLookupResult = 0;\n\n\tstruct proc_regioninfo processRegionInfo;\n\n\tuint64_t processAddress = 0;\n\n\tuint64_t memoryUse = 0;\n\n\tint memoryPageSize = getpagesize();\n\n\tdo {\n\t\tprocessLookupResult =\n\t\tproc_pidinfo(processIdentifier, PROC_PIDREGIONINFO, processAddress, &processRegionInfo, PROC_PIDREGIONINFO_SIZE);\n\n\t\tprocessAddress = (processRegionInfo.pri_address + processRegionInfo.pri_size);\n\n\t\tif (processRegionInfo.pri_share_mode == SM_PRIVATE) {\n\t\t\tmemoryUse += (processRegionInfo.pri_private_pages_resident * memoryPageSize);\n\t\t}\n\t} while (processLookupResult > 0);\n\n\treturn memoryUse;\n}\n\n+ (NSArray<TPI_SP_WebViewProcessInfo *> *)webViewProcessIdentifiers\n{\n\t/* Create a dictionary with key as identifier and value as an array of \n\t views managed by the process. */\n\tNSMutableDictionary<NSNumber *, __kindof NSArray *> *webViewProcesses = [NSMutableDictionary dictionary];\n\n\tvoid (^_addEntry)(IRCTreeItem *) = ^void (IRCTreeItem *treeItem)\n\t{\n\t\tpid_t processIdentifier = [TPI_SP_SysInfo webViewProcessIdentifierForTreeItem:treeItem];\n\n\t\tif (processIdentifier == 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSNumber *processIdentifierObj = @(processIdentifier);\n\n\t\tNSMutableArray<NSString *> *viewArray = webViewProcesses[processIdentifierObj];\n\n\t\tif (viewArray == nil) {\n\t\t\tviewArray = [NSMutableArray array];\n\n\t\t\twebViewProcesses[processIdentifierObj] = viewArray;\n\t\t}\n\n\t\tif (treeItem.isClient) {\n\t\t\treturn;\n\t\t}\n\n\t\t[viewArray addObject:treeItem.name];\n\t};\n\n\tfor (IRCClient *u in worldController().clientList) {\n\t\t_addEntry(u);\n\n\t\tfor (IRCChannel *c in u.channelList) {\n\t\t\t_addEntry(c);\n\t\t}\n\t}\n\n\t/* Create array of TPI_SP_WebViewProcessInfo objects */\n\tNSMutableArray<TPI_SP_WebViewProcessInfo *> *webViewProcessObjects =\n\t[NSMutableArray arrayWithCapacity:webViewProcesses.count];\n\n\t[webViewProcesses enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL *stop) {\n\t\t/* Object values */\n\t\tpid_t processIdentifier = [key intValue];\n\n\t\tuint64_t processMemoryUse = [TPI_SP_SysInfo memoryUseForProcess:processIdentifier];\n\n\t\tNSArray *processViewNames = [object sortedArrayUsingSelector:@selector(compare:)];\n\n\t\t/* Set values */\n\t\tTPI_SP_WebViewProcessInfo *processInfoObject = [TPI_SP_WebViewProcessInfo new];\n\n\t\tprocessInfoObject.processIdentifier = processIdentifier;\n\n\t\tprocessInfoObject.processMemoryUse = processMemoryUse;\n\n\t\tprocessInfoObject.processViewNames = processViewNames;\n\n\t\t/* Add object */\n\t\t[webViewProcessObjects addObject:processInfoObject];\n\t}];\n\n\t/* Sort objects based on memory use (highest to lowest) */\n\t[webViewProcessObjects sortUsingComparator:^NSComparisonResult(id object1, id object2) {\n\t\tuint64_t processMemoryUse1 = [object1 processMemoryUse];\n\t\tuint64_t processMemoryUse2 = [object2 processMemoryUse];\n\n\t\tif (processMemoryUse1 > processMemoryUse2) {\n\t\t\treturn NSOrderedAscending;\n\t\t} else if (processMemoryUse1 < processMemoryUse2) {\n\t\t\treturn NSOrderedDescending;\n\t\t}\n\n\t\treturn NSOrderedSame;\n\t}];\n\n\t/* Return a copy of mutable array */\n\treturn [webViewProcessObjects copy];\n}\n\n+ (pid_t)webViewProcessIdentifierForTreeItem:(IRCTreeItem *)treeItem\n{\n\tTVCLogView *backingView = treeItem.viewController.backingView;\n\n\tid webView = backingView.webView;\n\n\tif ([webView respondsToSelector:@selector(_webProcessIdentifier)]) {\n\t\treturn [webView _webProcessIdentifier];\n\t}\n\n\treturn 0;\n}\n\n+ (nullable NSString *)refreshRateForScreen:(NSScreen *)screen\n{\n\tNSParameterAssert(screen != nil);\n\n\tCGFloat refreshRate = screen.screenRefreshRate;\n\n\t/* Only return a formatted refresh rate if not 60.\n\t Everyone has 60. That's not interesting info. */\n\t/* Edited June 2024: Some displays are actually 59.\n\t It annoyed me having this information displayed.\n\t The values I picked below for excluding this information\n\t were picked arbitrarily and do not reflect any real\n\t world testing. */\n//\tif (fabs(refreshRate) == 60.0) {\n\tif (refreshRate > 58.5 && refreshRate < 61.5) {\n\t\treturn nil;\n\t}\n\n\treturn TPILocalizedString(@\"BasicLanguage[zpt-sx]\", refreshRate);\n}\n\n@end\n\n#pragma mark -\n\n@implementation TPI_SP_WebViewProcessInfo\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2012 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Preferences pane name. */\n\"dff-13\" = \"System Information\";\n\n/* Screen refresh rate - shared by /sysinfo/ and /screens/ */\n\"zpt-sx\" = \"%.0f Hz\";\n\n/* /sysinfo/ command. */\n\"lxj-ha\" = \"System Information:\";\n\"7g5-pf\" = \" \\002Model:\\002 %@ \\002•\\002\";\n\"mnc-vx\" = \" \\002CPU:\\002 %1$@ (%2$lu Threads, %3$lu Cores) @ %4$@ \\002•\\002\";\n\"ifk-s5\" = \" \\002CPU:\\002 %1$@ (%2$lu Cores) \\002•\\002\";\n\"1am-io\" = \" \\002Memory:\\002 %@ \\002•\\002\";\n\"xb6-bh\" = \" \\002Uptime:\\002 %@ \\002•\\002\";\n\"yrc-6l\" = \" \\002Space:\\002 %@ \\002•\\002\";\n\"q5v-uq\" = \" \\002Graphics:\\002 %@ \\002•\\002\";\n\"22o-rg\" = \" \\002Display:\\002 %1$@ \\002•\\002\";\n\"b7c-qd\" = \" \\002Display:\\002 %1$@ at %2$@ \\002•\\002\";\n\"g41-p7\" = \" \\002OS:\\002 %1$@ (Version %2$@, Build %3$@)\";\n\n\"8nu-89\" = \"%@\";\n\"cmk-ws\" = \", %@\";\n\n\"3iu-k8\" = \"%.2f GHz\";\n\"jw7-sg\" = \"%.2f MHz\"; // really?\n\n/* /memory/ command. */\n\"scn-br\" = \"Memory use of Textual: %1$@ • Visible lines: %2$@\";\n\"ioy-qc\" = \"\\002Top Process (WebKit):\\002 Process #%1$i, which is assigned to %2$@, is using %3$@ of memory\";\n\"a00-8n\" = \"\\002Top Process (WebKit):\\002 Process #%1$i, which is assigned to %2$@; is using %3$@ of memory\";\n\"a5u-m1\" = \"\\002All Processes (WebKit):\\002 Process count: %1$lu • Memory use: %2$@\";\n\n/* /diskspace/ command. */\n\"n6i-xd\" = \"\\002Mounted Drives:\\002 %@\";\n\"bvr-wz\" = \"%1$@: Total: %2$@; Free: %3$@\";\n\"lct-7h\" = \" — %1$@: Total: %2$@; Free: %3$@\";\n\"ler-a5\" = \"Error: Unable to find any mounted drives.\"; // what are we running on?\n\n/* /netstats/ command. */\n\"9f8-ej\" = \"\\002Network Traffic:\\002%@\";\n\"ca4-25\" = \" [%1$@]: %2$@ in, %3$@ out\";\n\"mjo-o0\" = \" — [%1$@]: %2$@ in, %3$@ out\";\n\"li1-vn\" = \"Error: Unable to locate any network statistics.\";\n\n/* /style/ command. */\n\"z37-85\" = \"\\002Current Style:\\002 %1$@ (%2$@) \\002•\\002 %3$@\";\n\"614-dj\" = \"\\002Appearance:\\002 %@\";\n\"843-z4\" = \"\\002Chat Appearance:\\002 %1$@ \\002•\\002 \\002Sidebar Appearance:\\002 %2$@\";\n\"890-au\" = \"Light\";\n\"243-yt\" = \"Dark\";\n\n/* /screens/ command. */\n\"vvt-zq\" = \"\\002Display Resolution:\\002 #%1$lu: %2$@ at %3$@\";\n\"441-8c\" = \"\\002Display Resolution:\\002 #%1$lu: %2$@\";\n\"fys-ft\" = \"; #%1$lu: %2$@ at %3$@\";\n\"dd1-rp\" = \"; #%1$lu: %2$@\";\n\n/* Misc., one line commands. */\n\"v03-jx\" = \"System Uptime: %1$@ \\002•\\002 Textual Uptime: %2$@\";\n\"cfs-b1\" = \"\\002System Memory:\\002 Free: %1$@; Used: %2$@; Total: %3$@; — [%4$@]\";\n\"6fn-xh\" = \"Textual has been opened \\002%1$@\\002 times with a total runtime of %2$@\";\n\"rua-9r\" = \"Textual has sent \\002%1$@\\002 commands since startup with a total of \\002%2$@\\002 commands received. The last command received on this connection occurred %3$@ ago. This equals roughly \\002%4$@ in\\002 and \\002%5$@ out\\002 worth of bandwidth.\";\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.1</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2012 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPISystemProfiler</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Resources/Property Lists/MacintoshModels.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Mac13,1</key>\n\t<string>Mac Studio (2022)</string>\n\t<key>Mac13,2</key>\n\t<string>Mac Studio (2022)</string>\n\t<key>Mac14,2</key>\n\t<string>MacBook Air (13-inch, 2022)</string>\n\t<key>Mac14,3</key>\n\t<string>Mac mini (2023)</string>\n\t<key>Mac14,5</key>\n\t<string>MacBook Pro (14-inch, Early 2023)</string>\n\t<key>Mac14,6</key>\n\t<string>MacBook Pro (16-inch, Early 2023)</string>\n\t<key>Mac14,7</key>\n\t<string>MacBook Pro (13-inch, 2022)</string>\n\t<key>Mac14,8</key>\n\t<string>Mac Pro (2023)</string>\n\t<key>Mac14,9</key>\n\t<string>MacBook Pro (14-inch, Early 2023)</string>\n\t<key>Mac14,10</key>\n\t<string>MacBook Pro (16-inch, Early 2023)</string>\n\t<key>Mac14,12</key>\n\t<string>Mac mini (2023)</string>\n\t<key>Mac14,13</key>\n\t<string>Mac Studio (2023)</string>\n\t<key>Mac14,14</key>\n\t<string>Mac Studio (2023)</string>\n\t<key>Mac14,15</key>\n\t<string>MacBook Air (15-inch, 2023)</string>\n\t<key>Mac15,3</key>\n\t<string>MacBook Pro (14-inch, Late 2023)</string>\n\t<key>Mac15,4</key>\n\t<string>iMac (24-inch, 2023)</string>\n\t<key>Mac15,5</key>\n\t<string>iMac (24-inch, 2023)</string>\n\t<key>Mac15,6</key>\n\t<string>MacBook Pro (14-inch, Late 2023)</string>\n\t<key>Mac15,7</key>\n\t<string>MacBook Pro (16-inch, Late 2023)</string>\n\t<key>Mac15,8</key>\n\t<string>MacBook Pro (14-inch, Late 2023)</string>\n\t<key>Mac15,9</key>\n\t<string>MacBook Pro (16-inch, Late 2023)</string>\n\t<key>Mac15,10</key>\n\t<string>MacBook Pro (14-inch, Late 2023)</string>\n\t<key>Mac15,11</key>\n\t<string>MacBook Pro (16-inch, Late 2023)</string>\n\t<key>Mac15,12</key>\n\t<string>MacBook Air (13-inch, 2024)</string>\n\t<key>Mac15,13</key>\n\t<string>MacBook Air (15-inch, 2024)</string>\n\t<key>Mac15,14</key>\n\t<string>Mac Studio (2025)</string>\n\t<key>Mac16,1</key>\n\t<string>MacBook Pro (14-inch, 2024)</string>\n\t<key>Mac16,2</key>\n\t<string>iMac (24-inch, 2024)</string>\n\t<key>Mac16,3</key>\n\t<string>iMac (24-inch, 2024)</string>\n\t<key>Mac16,5</key>\n\t<string>MacBook Pro (16-inch, 2024)</string>\n\t<key>Mac16,6</key>\n\t<string>MacBook Pro (14-inch, 2024)</string>\n\t<key>Mac16,7</key>\n\t<string>MacBook Pro (16-inch, 2024)</string>\n\t<key>Mac16,8</key>\n\t<string>MacBook Pro (14-inch, 2024)</string>\n\t<key>Mac16,9</key>\n\t<string>Mac Studio (2025)</string>\n\t<key>Mac16,10</key>\n\t<string>Mac mini (2024)</string>\n\t<key>Mac16,11</key>\n\t<string>Mac mini (2024)</string>\n\t<key>Mac16,12</key>\n\t<string>MacBook Air (13-inch, 2025)</string>\n\t<key>Mac16,13</key>\n\t<string>MacBook Air (15-inch, 2025)</string>\n\t<key>MacBook6,1</key>\n\t<string>MacBook (13-inch, Late 2009)</string>\n\t<key>MacBook7,1</key>\n\t<string>MacBook (13-inch, 2010)</string>\n\t<key>MacBook8,1</key>\n\t<string>MacBook (12-inch, 2015)</string>\n\t<key>MacBook9,1</key>\n\t<string>MacBook (12-inch, Early 2016)</string>\n\t<key>MacBook10,1</key>\n\t<string>MacBook (12-inch, 2017)</string>\n\t<key>MacBookAir3,1</key>\n\t<string>MacBook Air (11-inch, 2010)</string>\n\t<key>MacBookAir3,2</key>\n\t<string>MacBook Air (13-inch, 2010)</string>\n\t<key>MacBookAir4,1</key>\n\t<string>MacBook Air (11-inch, 2011)</string>\n\t<key>MacBookAir4,2</key>\n\t<string>MacBook Air (13-inch, 2011)</string>\n\t<key>MacBookAir5,1</key>\n\t<string>MacBook Air (11-inch, 2012)</string>\n\t<key>MacBookAir5,2</key>\n\t<string>MacBook Air (13-inch, 2012)</string>\n\t<key>MacBookAir6,1</key>\n\t<string>MacBook Air (11-inch, 2013)</string>\n\t<key>MacBookAir6,2</key>\n\t<string>MacBook Air (13-inch, 2013)</string>\n\t<key>MacBookAir7,1</key>\n\t<string>MacBook Air (11-inch, 2015)</string>\n\t<key>MacBookAir7,2</key>\n\t<string>MacBook Air (13-inch, 2015)</string>\n\t<key>MacBookAir8,1</key>\n\t<string>MacBook Air (13-inch, 2018)</string>\n\t<key>MacBookAir9,1</key>\n\t<string>MacBook Air (13-inch, Early 2020)</string>\n\t<key>MacBookAir10,1</key>\n\t<string>MacBook Air (13-inch, Late 2020)</string>\n\t<key>MacBookPro6,1</key>\n\t<string>MacBook Pro (17-inch, Mid-2010)</string>\n\t<key>MacBookPro6,2</key>\n\t<string>MacBook Pro (15-inch, Mid-2010)</string>\n\t<key>MacBookPro7,1</key>\n\t<string>MacBook Pro (13-inch, Mid-2010)</string>\n\t<key>MacBookPro8,1</key>\n\t<string>MacBook Pro (13-inch, 2011)</string>\n\t<key>MacBookPro8,2</key>\n\t<string>MacBook Pro (15-inch, 2011)</string>\n\t<key>MacBookPro8,3</key>\n\t<string>MacBook Pro (17-inch, 2011)</string>\n\t<key>MacBookPro9,2</key>\n\t<string>MacBook Pro (13-inch, 2012)</string>\n\t<key>MacBookPro9,1</key>\n\t<string>MacBook Pro (15-inch, 2012)</string>\n\t<key>MacBookPro10,1</key>\n\t<string>MacBook Pro (15-inch, 2012)</string>\n\t<key>MacBookPro10,2</key>\n\t<string>MacBook Pro (13-inch, 2012)</string>\n\t<key>MacBookPro11,1</key>\n\t<string>MacBook Pro (13-inch, 2013)</string>\n\t<key>MacBookPro11,2</key>\n\t<string>MacBook Pro (15-inch, 2013)</string>\n\t<key>MacBookPro11,3</key>\n\t<string>MacBook Pro (15-inch, 2013)</string>\n\t<key>MacBookPro11,4</key>\n\t<string>MacBook Pro (15-inch, Mid-2015)</string>\n\t<key>MacBookPro11,5</key>\n\t<string>MacBook Pro (15-inch, Mid-2015)</string>\n\t<key>MacBookPro12,1</key>\n\t<string>MacBook Pro (13-inch, Early 2015)</string>\n\t<key>MacBookPro13,1</key>\n\t<string>MacBook Pro (13-inch, 2016)</string>\n\t<key>MacBookPro13,2</key>\n\t<string>MacBook Pro (13-inch, 2016)</string>\n\t<key>MacBookPro13,3</key>\n\t<string>MacBook Pro (15-inch, 2016)</string>\n\t<key>MacBookPro14,1</key>\n\t<string>MacBook Pro (13-inch, 2017)</string>\n\t<key>MacBookPro14,2</key>\n\t<string>MacBook Pro (13-inch, 2017)</string>\n\t<key>MacBookPro14,3</key>\n\t<string>MacBook Pro (15-inch, 2017)</string>\n\t<key>MacBookPro15,1</key>\n\t<string>MacBook Pro (15-inch, 2018)</string>\n\t<key>MacBookPro15,2</key>\n\t<string>MacBook Pro (13-inch, 2018)</string>\n\t<key>MacBookPro15,3</key>\n\t<string>MacBook Pro (15-inch, 2019)</string>\n\t<key>MacBookPro16,1</key>\n\t<string>MacBook Pro (16-inch, 2019)</string>\n\t<key>MacBookPro16,2</key>\n\t<string>MacBook Pro (13-inch, 2020)</string>\n\t<key>MacBookPro16,3</key>\n\t<string>MacBook Pro (13-inch, 2020)</string>\n\t<key>MacBookPro17,1</key>\n\t<string>MacBook Pro (13-inch, 2020)</string>\n\t<key>MacBookPro18,1</key>\n\t<string>MacBook Pro (16-inch, 2021)</string>\n\t<key>MacBookPro18,2</key>\n\t<string>MacBook Pro (16-inch, 2021)</string>\n\t<key>MacBookPro18,3</key>\n\t<string>MacBook Pro (14-inch, 2021)</string>\n\t<key>MacBookPro18,4</key>\n\t<string>MacBook Pro (14-inch, 2021)</string>\n\t<key>MacPro5,1</key>\n\t<string>Mac Pro (2010)</string>\n\t<key>MacPro6,1</key>\n\t<string>Mac Pro (2013)</string>\n\t<key>MacPro7,1</key>\n\t<string>Mac Pro (2019)</string>\n\t<key>Macmini4,1</key>\n\t<string>Mac Mini (2010)</string>\n\t<key>Macmini5,1</key>\n\t<string>Mac Mini (2011)</string>\n\t<key>Macmini5,2</key>\n\t<string>Mac Mini (2011)</string>\n\t<key>Macmini5,3</key>\n\t<string>Mac Mini Server (2011)</string>\n\t<key>Macmini6,1</key>\n\t<string>Mac Mini (2012)</string>\n\t<key>Macmini6,2</key>\n\t<string>Mac Mini (2012)</string>\n\t<key>Macmini7,1</key>\n\t<string>Mac Mini (2014)</string>\n\t<key>Macmini8,1</key>\n\t<string>Mac Mini (2018)</string>\n\t<key>Macmini9,1</key>\n\t<string>Mac Mini (2020)</string>\n\t<key>iMac10,1</key>\n\t<string>iMac (Late 2009)</string>\n\t<key>iMac11,1</key>\n\t<string>iMac (Late 2009)</string>\n\t<key>iMac11,2</key>\n\t<string>iMac (21.5-inch, 2010)</string>\n\t<key>iMac11,3</key>\n\t<string>iMac (27-inch, 2010)</string>\n\t<key>iMac12,1</key>\n\t<string>iMac (21.5-inch, 2011)</string>\n\t<key>iMac12,2</key>\n\t<string>iMac (27-inch, 2011)</string>\n\t<key>iMac13,1</key>\n\t<string>iMac (21.5-inch, 2012)</string>\n\t<key>iMac13,2</key>\n\t<string>iMac (27-inch, 2012)</string>\n\t<key>iMac14,1</key>\n\t<string>iMac (21.5-inch, 2013)</string>\n\t<key>iMac14,2</key>\n\t<string>iMac (27-inch, 2013)</string>\n\t<key>iMac14,3</key>\n\t<string>iMac (21.5-inch, 2013)</string>\n\t<key>iMac14,4</key>\n\t<string>iMac (21.5-inch, 2014)</string>\n\t<key>iMac15,1</key>\n\t<string>iMac (27-inch, 2014)</string>\n\t<key>iMac16,1</key>\n\t<string>iMac (21.5-Inch, 2015)</string>\n\t<key>iMac16,2</key>\n\t<string>iMac (21.5-Inch, 2015)</string>\n\t<key>iMac17,1</key>\n\t<string>iMac (27-inch, 2015)</string>\n\t<key>iMac18,1</key>\n\t<string>iMac (21.5-Inch, 2017)</string>\n\t<key>iMac18,2</key>\n\t<string>iMac (21.5-Inch, 2017)</string>\n\t<key>iMac18,3</key>\n\t<string>iMac (27-inch, 2017)</string>\n\t<key>iMac19,1</key>\n\t<string>iMac (27-inch, 2019)</string>\n\t<key>iMac19,2</key>\n\t<string>iMac (21.5-inch, 2019)</string>\n\t<key>iMac20,1</key>\n\t<string>iMac (27-inch, 2020)</string>\n\t<key>iMac20,2</key>\n\t<string>iMac (27-inch, 2020)</string>\n\t<key>iMac21,1</key>\n\t<string>iMac (24-inch, 2021)</string>\n\t<key>iMac21,2</key>\n\t<string>iMac (24-inch, 2021)</string>\n\t<key>iMacPro1,1</key>\n\t<string>iMac (27-inch, 2017)</string>\n\t<key>Parallels</key>\n\t<string>Parallels Desktop Virtual Machine</string>\n\t<key>VMware</key>\n\t<string>VMware Fusion Virtual Machine</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/Resources/User Interface/en.lproj/TPISystemProfiler.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"21507\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"21507\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPISystemProfiler\">\n            <connections>\n                <outlet property=\"preferencePaneView\" destination=\"1\" id=\"2\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"292\"/>\n            <userGuides>\n                <userLayoutGuide location=\"432\" affinity=\"minY\"/>\n                <userLayoutGuide location=\"380\" affinity=\"minY\"/>\n            </userGuides>\n            <subviews>\n                <textField translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Tag-MJ-P9h\">\n                    <rect key=\"frame\" x=\"130\" y=\"246\" width=\"411\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" title=\"Select each item to appear in the output of the “sysinfo” command:\" id=\"Mun-t6-pSD\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <stackView distribution=\"equalSpacing\" orientation=\"vertical\" alignment=\"leading\" spacing=\"14\" verticalStackHuggingPriority=\"250\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cFu-gB-YZX\">\n                    <rect key=\"frame\" x=\"217\" y=\"30\" width=\"237\" height=\"196\"/>\n                    <subviews>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3\">\n                            <rect key=\"frame\" x=\"-2\" y=\"179\" width=\"239\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"CPU model and related information\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"4\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; CPU Model\" id=\"119\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5\">\n                            <rect key=\"frame\" x=\"-2\" y=\"149\" width=\"124\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"System memory\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"6\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; Memory Information\" id=\"Z3t-Rb-FgZ\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"12\">\n                            <rect key=\"frame\" x=\"-2\" y=\"119\" width=\"179\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Operating system uptime\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"13\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; System Uptime\" id=\"yeE-rE-0DI\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"14\">\n                            <rect key=\"frame\" x=\"-2\" y=\"89\" width=\"203\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Boot volume disk information\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"15\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; Disk Information\" id=\"VwK-aB-tHR\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"16\">\n                            <rect key=\"frame\" x=\"-2\" y=\"59\" width=\"111\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Graphics card\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"17\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; GPU Model\" id=\"rqk-4j-e6W\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"18\">\n                            <rect key=\"frame\" x=\"-2\" y=\"29\" width=\"218\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Active display screen resolution\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"19\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; Screen Resolution\" id=\"FyL-Q6-iAG\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                        <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"22\">\n                            <rect key=\"frame\" x=\"-2\" y=\"-1\" width=\"181\" height=\"18\"/>\n                            <buttonCell key=\"cell\" type=\"check\" title=\"Operating system version\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"23\">\n                                <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                                <font key=\"font\" metaFont=\"system\"/>\n                            </buttonCell>\n                            <connections>\n                                <binding destination=\"114\" name=\"value\" keyPath=\"values.System Profiler Extension -&gt; Feature Disabled -&gt; OS Version\" id=\"Uzm-ov-IK8\">\n                                    <dictionary key=\"options\">\n                                        <string key=\"NSValueTransformerName\">NSNegateBoolean</string>\n                                    </dictionary>\n                                </binding>\n                            </connections>\n                        </button>\n                    </subviews>\n                    <visibilityPriorities>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                        <integer value=\"1000\"/>\n                    </visibilityPriorities>\n                    <customSpacing>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                        <real value=\"3.4028234663852886e+38\"/>\n                    </customSpacing>\n                </stackView>\n            </subviews>\n            <constraints>\n                <constraint firstAttribute=\"bottom\" secondItem=\"22\" secondAttribute=\"bottom\" constant=\"30\" id=\"HdJ-FX-u6w\"/>\n                <constraint firstItem=\"Tag-MJ-P9h\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"IhP-Fe-PaF\"/>\n                <constraint firstItem=\"cFu-gB-YZX\" firstAttribute=\"top\" secondItem=\"Tag-MJ-P9h\" secondAttribute=\"bottom\" constant=\"20\" id=\"gib-9x-L1K\"/>\n                <constraint firstItem=\"cFu-gB-YZX\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"ttS-NT-YIm\"/>\n                <constraint firstItem=\"Tag-MJ-P9h\" firstAttribute=\"top\" secondItem=\"1\" secondAttribute=\"top\" constant=\"30\" id=\"ziw-vl-9X4\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"115\" y=\"393.5\"/>\n        </customView>\n        <userDefaultsController id=\"114\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n    </objects>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/System Profiler/System Profiler Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C06DE7A20EC45D10055D09A /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C06DE7920EC45D10055D09A /* IOKit.framework */; };\n\t\t4C36AAD420F27C9E007CA939 /* TPISystemProfiler.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAD220F27C9E007CA939 /* TPISystemProfiler.xib */; };\n\t\t4C36AAD920F27CC5007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAD720F27CC5007CA939 /* BasicLanguage.strings */; };\n\t\t4C46A08920EC6ABD00094EA4 /* MacintoshModels.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4C46A08220EC6ABD00094EA4 /* MacintoshModels.plist */; };\n\t\t4C46A09520EC6AD700094EA4 /* TPI_SP_SysInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A08F20EC6AD700094EA4 /* TPI_SP_SysInfo.m */; };\n\t\t4C46A09720EC6AD700094EA4 /* TPISystemProfiler.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A09120EC6AD700094EA4 /* TPISystemProfiler.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C06DE7920EC45D10055D09A /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };\n\t\t4C36AAD320F27C9E007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPISystemProfiler.xib; sourceTree = \"<group>\"; };\n\t\t4C36AAD820F27CC5007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C46A08220EC6ABD00094EA4 /* MacintoshModels.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = MacintoshModels.plist; sourceTree = \"<group>\"; };\n\t\t4C46A08320EC6ABD00094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A08E20EC6AD700094EA4 /* TPISystemProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPISystemProfiler.h; sourceTree = \"<group>\"; };\n\t\t4C46A08F20EC6AD700094EA4 /* TPI_SP_SysInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_SP_SysInfo.m; sourceTree = \"<group>\"; };\n\t\t4C46A09120EC6AD700094EA4 /* TPISystemProfiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPISystemProfiler.m; sourceTree = \"<group>\"; };\n\t\t4C46A09220EC6AD700094EA4 /* SystemProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemProfiler.h; sourceTree = \"<group>\"; };\n\t\t4C46A09420EC6AD700094EA4 /* TPI_SP_SysInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_SP_SysInfo.h; sourceTree = \"<group>\"; };\n\t\t4CE1439920EBF551000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1439A20EBF551000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1439E20EBF551000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143AC20EBF551000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE143AD20EBF551000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143AE20EBF551000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143B020EBF551000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE143B320EBF551000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143C120EBF551000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE143C220EBF551000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143C620EBF551000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* System Info.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"System Info.bundle\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06DE7A20EC45D10055D09A /* IOKit.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BlowfishCommandLine */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A08D20EC6AD700094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BlowfishCommandLine;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06DE7920EC45D10055D09A /* IOKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C69188E16E3276200BDE3A8 /* Configurations */,\n\t\t\t\t4C46A08720EC6ABD00094EA4 /* Language Files */,\n\t\t\t\t4C46A08120EC6ABD00094EA4 /* Property Lists */,\n\t\t\t\t4C46A08420EC6ABD00094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* System Info.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A08120EC6ABD00094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A08220EC6ABD00094EA4 /* MacintoshModels.plist */,\n\t\t\t\t4C46A08320EC6ABD00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A08420EC6ABD00094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAD220F27C9E007CA939 /* TPISystemProfiler.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A08720EC6ABD00094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAD720F27CC5007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A08D20EC6AD700094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A09220EC6AD700094EA4 /* SystemProfiler.h */,\n\t\t\t\t4C46A09420EC6AD700094EA4 /* TPI_SP_SysInfo.h */,\n\t\t\t\t4C46A08F20EC6AD700094EA4 /* TPI_SP_SysInfo.m */,\n\t\t\t\t4C46A08E20EC6AD700094EA4 /* TPISystemProfiler.h */,\n\t\t\t\t4C46A09120EC6AD700094EA4 /* TPISystemProfiler.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C69188E16E3276200BDE3A8 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1439520EBF551000E01C9 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4CE1439520EBF551000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE143A920EBF551000E01C9 /* Common */,\n\t\t\t\t4CE143BE20EBF551000E01C9 /* Debug */,\n\t\t\t\t4CE1439620EBF551000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1439620EBF551000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1439E20EBF551000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1439A20EBF551000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE1439920EBF551000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE143A920EBF551000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE143B320EBF551000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE143B020EBF551000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE143AD20EBF551000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE143AE20EBF551000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE143AC20EBF551000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE143BE20EBF551000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE143C620EBF551000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE143C220EBF551000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE143C120EBF551000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* System Profiler Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"System Profiler Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4CD69D80131E2BB500F4618E /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"System Profiler Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BlowfishCommandLine;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* System Info.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"System Profiler Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BlowfishCommandLine */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* System Profiler Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4CD69D80131E2BB500F4618E /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A08920EC6ABD00094EA4 /* MacintoshModels.plist in Resources */,\n\t\t\t\t4C36AAD420F27C9E007CA939 /* TPISystemProfiler.xib in Resources */,\n\t\t\t\t4C36AAD920F27CC5007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A09520EC6AD700094EA4 /* TPI_SP_SysInfo.m in Sources */,\n\t\t\t\t4C46A09720EC6AD700094EA4 /* TPISystemProfiler.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAD220F27C9E007CA939 /* TPISystemProfiler.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAD320F27C9E007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPISystemProfiler.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AAD720F27CC5007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAD820F27CC5007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SystemProfiler\";\n\t\t\t\tPRODUCT_NAME = \"System Info\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SystemProfiler\";\n\t\t\t\tPRODUCT_NAME = \"System Info\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE143C220EBF551000E01C9 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1439A20EBF551000E01C9 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C95801E1FA41F6D00F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4C95801F1FA41F6D00F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-SystemProfiler\";\n\t\t\t\tPRODUCT_NAME = \"System Info\";\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"System Profiler Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4C95801F1FA41F6D00F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"System Profiler Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4C95801E1FA41F6D00F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/User Insights/Classes/TPIUserInsights.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPIUserInsights : NSObject <THOPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/User Insights/Classes/TPIUserInsights.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPIUserInsights.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPIUserInsights\n\n#pragma mark -\n#pragma mark User Input\n\n- (void)userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t  commandString:(NSString *)commandString\n\t\t\t\t\t\t  messageString:(NSString *)messageString\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _userInputCommandInvokedOnClient:client \n\t\t\t\t\t\t\t\t commandString:commandString\n\t\t\t\t\t\t\t\t messageString:messageString];\n\t});\n}\n\n- (void)_userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t   commandString:(NSString *)commandString\n\t\t\t\t\t\t   messageString:(NSString *)messageString\n{\n\tIRCChannel *channel = mainWindow().selectedChannel;\n\t\n\t/* We can brag in private messages so add above if statement */\n\tif ([commandString isEqualToString:@\"BRAG\"]) {\n\t\t[self bragInChannel:channel onClient:client];\n\n\t\treturn;\n\t}\n\n\tif (channel.isChannel == NO) {\n\t\treturn;\n\t}\n\n\tmessageString = messageString.trim;\n\n\tif ([commandString isEqualToString:@\"CLONES\"]) {\n\t\t[self findAllClonesInChannel:channel onClient:client];\n\t} else if ([commandString isEqualToString:@\"NAMEL\"]) {\n\t\t[self buildListOfUsersInChannel:channel onClient:client parameters:messageString];\n\t} else if ([commandString isEqualToString:@\"FINDUSER\"]) {\n\t\t[self findAllUsersMatchingString:messageString inChannel:channel onClient:client];\n\t}\n}\n\n- (NSArray *)subscribedUserInputCommands\n{\n\treturn @[@\"clones\", @\"namel\", @\"finduser\", @\"brag\"];\n}\n\n- (void)buildListOfUsersInChannel:(IRCChannel *)channel onClient:(IRCClient *)client parameters:(NSString *)parameters\n{\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(client != nil);\n\tNSParameterAssert(parameters != nil);\n\n\tNSArray *memberList = channel.memberList;\n\n\tif (memberList.count == 0) {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[5dx-rs]\", channel.name) inChannel:channel];\n\n\t\treturn;\n\t}\n\n\t/* Process parameters */\n\tBOOL displayRank = NO;\n\tBOOL sortByRank = NO;\n\n\tif ([parameters hasPrefix:@\"-\"]) {\n\t\tNSString *flagsString = [parameters substringFromIndex:1];\n\n\t\tNSArray *flags = flagsString.characterStringBuffer;\n\n\t\tdisplayRank = [flags containsObject:@\"d\"];\n\t\tsortByRank = [flags containsObject:@\"r\"];\n\t}\n\n\t/* -memberList returns a list sorted by rank by default.\n\t If we are not sorting by rank, then we have to first get\n\t the member list then sort it another way. */\n\tif (sortByRank == NO) {\n\t\t/* Sort user objects alphabetically by comparing nicknames */\n\n\t\tmemberList =\n\t\t[memberList sortedArrayUsingComparator:^NSComparisonResult(IRCChannelUser *member1, IRCChannelUser *member2) {\n\t\t\tNSString *nickname1 = member1.user.nickname;\n\t\t\tNSString *nickname2 = member2.user.nickname;\n\n\t\t\treturn [nickname1 caseInsensitiveCompare:nickname2];\n\t\t}];\n\t}\n\n\t/* Join user objects into string */\n\tNSMutableString *resultString = [NSMutableString string];\n\n\tfor (IRCChannelUser *member in memberList) {\n\t\tif (displayRank) {\n\t\t\t[resultString appendString:member.mark];\n\t\t}\n\n\t\t[resultString appendString:member.user.nickname];\n\n\t\t[resultString appendString:@\" \"];\n\t}\n\n\t[client printDebugInformation:[resultString copy] inChannel:channel];\n}\n\n- (void)findAllUsersMatchingString:(NSString *)matchString inChannel:(IRCChannel *)channel onClient:(IRCClient *)client\n{\n\tNSParameterAssert(matchString != nil);\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(client != nil);\n\n\tBOOL hasSearchCondition = (matchString.length > 0);\n\n\tNSArray *memberList = channel.memberList;\n\n\tif (memberList.count == 0) {\n\t\tif (hasSearchCondition) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[n1j-tp]\", channel.name, matchString) inChannel:channel];\n\t\t} else {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[1ab-27]\", channel.name) inChannel:channel];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tNSMutableArray<IRCChannelUser *> *membersMatched = [NSMutableArray array];\n\n\tfor (IRCChannelUser *member in memberList) {\n\t\tNSString *hostmask = member.user.hostmask;\n\n\t\tif (hostmask == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hasSearchCondition) {\n\t\t\tif ([hostmask containsIgnoringCase:matchString] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t[membersMatched addObject:member];\n\t}\n\n\tif (membersMatched.count <= 0) {\n\t\tif (hasSearchCondition) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[n1j-tp]\", channel.name, matchString) inChannel:channel];\n\t\t} else {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[1ab-27]\", channel.name) inChannel:channel];\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (hasSearchCondition) {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[oq7-mg]\", membersMatched.count, channel.name, matchString) inChannel:channel];\n\t} else {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[nn7-6s]\", membersMatched.count, channel.name) inChannel:channel];\n\t}\n\n\t[membersMatched sortUsingComparator:^NSComparisonResult(IRCChannelUser *member1, IRCChannelUser *member2) {\n\t\tNSString *nickname1 = member1.user.nickname;\n\t\tNSString *nickname2 = member2.user.nickname;\n\n\t\treturn [nickname1 caseInsensitiveCompare:nickname2];\n\t}];\n\n\tfor (IRCChannelUser *member in membersMatched) {\n\t\tNSString *resultString = [NSString stringWithFormat:@\"%@ -> %@\", member.user.nickname, member.user.hostmask];\n\n\t\t[client printDebugInformation:resultString inChannel:channel];\n\t}\n}\n\n- (void)findAllClonesInChannel:(IRCChannel *)channel onClient:(IRCClient *)client\n{\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(client != nil);\n\n\tNSMutableDictionary<NSString *, NSArray *> *members = [NSMutableDictionary dictionary];\n\n\t/* Populate our list by matching an array of users to that of the address. */\n\tfor (IRCChannelUser *member in channel.memberList) {\n\t\tNSString *address = member.user.address;\n\n\t\tif (address == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *nickname = member.user.nickname;\n\n\t\tNSArray *clones = members[address];\n\n\t\tif (clones) {\n\t\t\tclones = [clones arrayByAddingObject:nickname];\n\n\t\t\tmembers[address] = clones;\n\t\t} else {\n\t\t\tmembers[address] = @[nickname];\n\t\t}\n\t}\n\n\t/* Filter the new list by removing users with less than two matches. */\n\tNSArray *memberHosts = members.allKeys;\n\n\tfor (NSString *memberHost in memberHosts) {\n\t\tNSArray *clones = [members arrayForKey:memberHost];\n\n\t\tif (clones.count < 2) {\n\t\t\t[members removeObjectForKey:memberHost];\n\t\t}\n\t}\n\n\t/* No clones found */\n\tif (members.count == 0) {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[gxq-47]\") inChannel:channel];\n\n\t\treturn;\n\t}\n\n\t/* Build result string */\n\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[iaa-5v]\", members.count, channel.name) inChannel:channel];\n\n\tfor (NSString *memberHost in members) {\n\t\tNSArray *clones = [members arrayForKey:memberHost];\n\n\t\tNSString *clonesString = [clones componentsJoinedByString:@\", \"];\n\n\t\tNSString *resultString = [NSString stringWithFormat:@\"*!*@%@ -> %@\", memberHost, clonesString];\n\n\t\t[client printDebugInformation:resultString inChannel:channel];\n\t}\n}\n\n- (void)appendPluralOrSingular:(NSMutableString *)resultString valueToken:(NSString *)valueToken value:(NSInteger)value\n{\n\tNSParameterAssert(resultString != nil);\n\tNSParameterAssert(valueToken != nil);\n\n\tNSString *valueKey = nil;\n\n\tif (value == 1) {\n\t\tvalueKey = [NSString stringWithFormat:@\"BasicLanguage[%@-1]\", valueToken];\n\t} else {\n\t\tvalueKey = [NSString stringWithFormat:@\"BasicLanguage[%@-2]\", valueToken];\n\t}\n\n\t[resultString appendString:TPILocalizedString(valueKey, value)];\n}\n\n- (void)bragInChannel:(IRCChannel *)channel onClient:(IRCClient *)client\n{\n\tNSParameterAssert(channel != nil);\n\tNSParameterAssert(client != nil);\n\n\tNSUInteger operCount = 0;\n\tNSUInteger channelOpCount = 0;\n\tNSUInteger channelHalfopCount = 0;\n\tNSUInteger channelVoiceCount = 0;\n\tNSUInteger channelCount = 0;\n\tNSUInteger networkCount = 0;\n\tNSUInteger powerOverCount = 0;\n\n\tfor (IRCClient *cl in worldController().clientList) {\n\t\tif (cl.isConnected == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tnetworkCount++;\n\n\t\tIRCUser *localUser = cl.myself;\n\n\t\tif (cl.userIsIRCop || localUser.isIRCop) {\n\t\t\toperCount++;\n\t\t}\n\n\t\tNSMutableArray<NSString *> *trackedUsers = [NSMutableArray new];\n\n\t\tfor (IRCChannel *ch in cl.channelList) {\n\t\t\tif (ch.isActive == NO || ch.isChannel == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tchannelCount += 1;\n\n\t\t\tIRCChannelUser *myself = [ch findMember:cl.userNickname];\n\n\t\t\tIRCUserRank myRanks = myself.ranks;\n\n\t\t\tBOOL IHaveModeQ = ((myRanks & IRCUserRankChannelOwner) == IRCUserRankChannelOwner);\n\t\t\tBOOL IHaveModeA = ((myRanks & IRCUserRankSuperOperator) == IRCUserRankSuperOperator);\n\t\t\tBOOL IHaveModeO = ((myRanks & IRCUserRankNormalOperator) == IRCUserRankNormalOperator);\n\t\t\tBOOL IHaveModeH = ((myRanks & IRCUserRankHalfOperator) == IRCUserRankHalfOperator);\n\t\t\tBOOL IHaveModeV = ((myRanks & IRCUserRankVoiced) == IRCUserRankVoiced);\n\n\t\t\tif (IHaveModeQ || IHaveModeA || IHaveModeO) {\n\t\t\t\tchannelOpCount++;\n\t\t\t} else if (IHaveModeH) {\n\t\t\t\tchannelHalfopCount++;\n\t\t\t} else if (IHaveModeV) {\n\t\t\t\tchannelVoiceCount++;\n\t\t\t}\n\n\t\t\tfor (IRCChannelUser *member in ch.memberList) {\n\t\t\t\tif ([member isEqual:myself]) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tBOOL addUser = NO;\n\n\t\t\t\tIRCUserRank userRanks = member.ranks;\n\n\t\t\t\tBOOL UserHasModeQ = ((userRanks & IRCUserRankChannelOwner) == IRCUserRankChannelOwner);\n\t\t\t\tBOOL UserHasModeA = ((userRanks & IRCUserRankSuperOperator) == IRCUserRankSuperOperator);\n\t\t\t\tBOOL UserHasModeO = ((userRanks & IRCUserRankNormalOperator) == IRCUserRankNormalOperator);\n\t\t\t\tBOOL UserHasModeH = ((userRanks & IRCUserRankHalfOperator) == IRCUserRankHalfOperator);\n\n\t\t\t\tif (cl.userIsIRCop && member.user.isIRCop == NO) {\n\t\t\t\t\taddUser = YES;\n\t\t\t\t} else if (IHaveModeQ && UserHasModeQ == NO) {\n\t\t\t\t\taddUser = YES;\n\t\t\t\t} else if (IHaveModeA && UserHasModeQ == NO && UserHasModeA == NO) {\n\t\t\t\t\taddUser = YES;\n\t\t\t\t} else if (IHaveModeO && UserHasModeQ == NO && UserHasModeA == NO && UserHasModeO == NO) {\n\t\t\t\t\taddUser = YES;\n\t\t\t\t} else if (IHaveModeH && UserHasModeQ == NO && UserHasModeA == NO && UserHasModeO == NO && UserHasModeH == NO) {\n\t\t\t\t\taddUser = YES;\n\t\t\t\t}\n\n\t\t\t\tif (addUser) {\n\t\t\t\t\tNSString *nickname = member.user.nickname;\n\n\t\t\t\t\tif ([trackedUsers containsObject:nickname] == NO) {\n\t\t\t\t\t\t[trackedUsers addObject:nickname];\n\n\t\t\t\t\t\tpowerOverCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tNSMutableString *resultString = [NSMutableString string];\n\n\t[self appendPluralOrSingular:resultString valueToken:@\"30l-sx\" value:channelCount];\n\t[self appendPluralOrSingular:resultString valueToken:@\"rks-0t\" value:networkCount];\n\n\tif (powerOverCount == 0) {\n\t\t[resultString appendString:TPILocalizedString(@\"BasicLanguage[jpi-po]\")];\n\t} else {\n\t\t[self appendPluralOrSingular:resultString valueToken:@\"614-ac\" value:operCount];\n\t\t[self appendPluralOrSingular:resultString valueToken:@\"qne-b5\" value:channelOpCount];\n\t\t[self appendPluralOrSingular:resultString valueToken:@\"431-yv\" value:channelHalfopCount];\n\t\t[self appendPluralOrSingular:resultString valueToken:@\"x1m-jp\" value:channelVoiceCount];\n\t\t[self appendPluralOrSingular:resultString valueToken:@\"ny4-wd\" value:powerOverCount];\n\t}\n\n\t[client sendPrivmsg:[resultString copy] toChannel:channel];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/User Insights/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2013 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"5dx-rs\" = \"No users found in %@\";\n\"gxq-47\" = \"No clones found\";\n\"iaa-5v\" = \"%1$lu clone(s) found in %2$@\";\n\n\"r6x-ih\" = \"Bad input\";\n\n\"nn7-6s\" = \"%1$lu user(s) found in %2$@ with a cached hostmask.\";\n\"oq7-mg\" = \"%1$lu user(s) found in %2$@ with a cached hostmask containing the search string “%3$@”\";\n\"1ab-27\" = \"No users found in %@ with a cached hostmask.\";\n\"n1j-tp\" = \"No users found in %1$@ with a cached hostmask containing the search string “%2$@”\";\n\n\"30l-sx-1\" = \"I am in %ld channel while connected to \";\n\"30l-sx-2\" = \"I am in %ld channels while connected to \";\n\n\"rks-0t-1\" = \"%ld network. \";\n\"rks-0t-2\" = \"%ld networks. \";\n\n\"614-ac-1\" = \"I have %ld o:line, \";\n\"614-ac-2\" = \"I have %ld o:lines, \";\n\n\"qne-b5-1\" = \"%ld op, \";\n\"qne-b5-2\" = \"%ld ops, \";\n\n\"431-yv-1\" = \"%ld halfop, \";\n\"431-yv-2\" = \"%ld halfops, \";\n\n\"x1m-jp-1\" = \"and %ld voice \";\n\"x1m-jp-2\" = \"and %ld voices \";\n\n\"ny4-wd-1\" = \"with power over %ld user.\";\n\"ny4-wd-2\" = \"with power over %ld unique users.\";\n\n\"jpi-po\" = \"I have no power whatsoever.\";\n"
  },
  {
    "path": "Sources/Plugins/User Insights/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.1</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2013 - 2018 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPIUserInsights</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/User Insights/User Insights Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C06DE7C20EC45F10055D09A /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C06DE7B20EC45F10055D09A /* CoreFoundation.framework */; };\n\t\t4C36AADC20F27CFA007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AADA20F27CFA007CA939 /* BasicLanguage.strings */; };\n\t\t4C46A09B20EC6B0900094EA4 /* TPIUserInsights.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A09920EC6B0900094EA4 /* TPIUserInsights.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C06DE7B20EC45F10055D09A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };\n\t\t4C36AADB20F27CFA007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C46A09920EC6B0900094EA4 /* TPIUserInsights.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPIUserInsights.m; sourceTree = \"<group>\"; };\n\t\t4C46A09A20EC6B0900094EA4 /* TPIUserInsights.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPIUserInsights.h; sourceTree = \"<group>\"; };\n\t\t4C46A09F20EC6B1800094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4CE1433920EBF4F3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1433A20EBF4F3000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1433E20EBF4F3000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1434C20EBF4F3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1434D20EBF4F3000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1434E20EBF4F3000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1435020EBF4F3000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1435320EBF4F3000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1436120EBF4F3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1436220EBF4F3000E01C9 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1436620EBF4F3000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* User Insights.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"User Insights.bundle\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C06DE7C20EC45F10055D09A /* CoreFoundation.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BragSpam */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A09820EC6B0900094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BragSpam;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C06DE7B20EC45F10055D09A /* CoreFoundation.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C6918A016E3277A00BDE3A8 /* Configurations */,\n\t\t\t\t4C46A09C20EC6B1800094EA4 /* Language Files */,\n\t\t\t\t4C46A09E20EC6B1800094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* User Insights.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A09820EC6B0900094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A09A20EC6B0900094EA4 /* TPIUserInsights.h */,\n\t\t\t\t4C46A09920EC6B0900094EA4 /* TPIUserInsights.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A09C20EC6B1800094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AADA20F27CFA007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A09E20EC6B1800094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A09F20EC6B1800094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C6918A016E3277A00BDE3A8 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1433520EBF4F3000E01C9 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4CE1433520EBF4F3000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1434920EBF4F3000E01C9 /* Common */,\n\t\t\t\t4CE1435E20EBF4F3000E01C9 /* Debug */,\n\t\t\t\t4CE1433620EBF4F3000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1433620EBF4F3000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1433E20EBF4F3000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1433A20EBF4F3000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE1433920EBF4F3000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1434920EBF4F3000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1435320EBF4F3000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE1435020EBF4F3000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE1434D20EBF4F3000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE1434E20EBF4F3000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE1434C20EBF4F3000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1435E20EBF4F3000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1436620EBF4F3000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1436220EBF4F3000E01C9 /* Textual Extensions.xcconfig */,\n\t\t\t\t4CE1436120EBF4F3000E01C9 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* User Insights Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"User Insights Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"User Insights Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BragSpam;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* User Insights.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"User Insights Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BragSpam */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* User Insights Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AADC20F27CFA007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A09B20EC6B0900094EA4 /* TPIUserInsights.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AADA20F27CFA007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AADB20F27CFA007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-UserInsights\";\n\t\t\t\tPRODUCT_NAME = \"User Insights\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-UserInsights\";\n\t\t\t\tPRODUCT_NAME = \"User Insights\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1436220EBF4F3000E01C9 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1433A20EBF4F3000E01C9 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C9580181FA41EE300F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4C9580191FA41EE300F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-UserInsights\";\n\t\t\t\tPRODUCT_NAME = \"User Insights\";\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"User Insights Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4C9580191FA41EE300F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"User Insights Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4C9580181FA41EE300F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Classes/TPIWikiStyleLinkParser.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\n@interface TPIWikiStyleLinkParser : NSObject <THOPluginProtocol, NSTableViewDataSource, NSTableViewDelegate>\n@end\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Classes/TPIWikiStyleLinkParser.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPIWikiStyleLinkParser.h\"\n\n/* Link prefix storage is a remnant of older times.\n There are better ways to store them other than an array with specific\n index values, but because this plugin is optional and rarely needs any\n maintaining, its not a priority to make it any better. */\n#define _indexChannelId\t\t\t\t0\n#define _indexLinkPrefix\t\t\t1\n\n#define _linkMatchRegex             @\"\\\\[\\\\[([^\\\\]]+)\\\\]\\\\]\"\n\n@interface TPIWikiStyleLinkParser ()\n@property (nonatomic, copy) NSArray *linkPrefixes;\n@property (nonatomic, strong) IBOutlet NSView *preferencePane;\n@property (nonatomic, strong) IBOutlet NSWindow *rnewConditionWindow;\n@property (nonatomic, weak) IBOutlet TVCValidatedTextField *rnewConditionLinkPrefixField;\n@property (nonatomic, weak) IBOutlet NSPopUpButton *rnewConditionChannelPopup;\n@property (nonatomic, weak) IBOutlet NSButton *rnewConditionSaveButton;\n@property (nonatomic, weak) IBOutlet NSButton *rnewConditionCancelButton;\n@property (nonatomic, weak) IBOutlet NSButton *addConditionButton;\n@property (nonatomic, weak) IBOutlet NSButton *removeConditionButton;\n@property (nonatomic, weak) IBOutlet NSTableView *linkPrefixesTable;\n\n- (void)addCondition:(id)sender;\n- (void)removeCondition:(id)sender;\n\n- (void)saveNewCondition:(id)sender;\n- (void)cancelNewCondition:(id)sender;\n\n- (void)updateNewConditionWindowSaveButton:(id)sender;\n@end\n\n@implementation TPIWikiStyleLinkParser\n\n#pragma mark -\n#pragma mark Init\n\n- (void)pluginLoadedIntoMemory\n{\n\t[self performBlockOnMainThread:^{\n\t\t[self linkPrefixesStorageRead];\n\n\t\t[TPIBundleFromClass() loadNibNamed:@\"TPIWikiStyleLinkParser\" owner:self topLevelObjects:nil];\n\n\t\t[self.rnewConditionLinkPrefixField setStringValueIsInvalidOnEmpty:YES];\n\n\t\t[self.rnewConditionLinkPrefixField setTextDidChangeCallback:self];\n\n\t\t[self.rnewConditionLinkPrefixField setValidationBlock:^NSString *(NSString *currentValue) {\n\t\t\tNSURL *URLValue = [NSURL URLWithString:currentValue];\n\n\t\t\tif (URLValue == nil) {\n\t\t\t\treturn TPILocalizedString(@\"BasicLanguage[535-5j]\");\n\t\t\t}\n\n\t\t\treturn nil;\n\t\t}];\n\n\t\t[self updateRemoveConditionButton];\n\t}];\n}\n\n#pragma mark -\n#pragma mark Server Input.\n\n- (NSString *)willRenderMessage:(NSString *)newMessage forViewController:(TVCLogController *)logController lineType:(TVCLogLineType)lineType memberType:(TVCLogLineMemberType)memberType\n{\n\tif ([self processWikiStyleLinks] == NO) {\n\t\treturn nil;\n\t}\n\t\n\t/* Only work on plain text messages */\n\tif (lineType == TVCLogLineTypePrivateMessage ||\n\t\tlineType == TVCLogLineTypeAction)\n\t{\n\t\tIRCChannel *channel = [logController associatedChannel];\n\t\t\n\t\tNSString *linkPrefix = [self linkPrefixFromId:[channel uniqueIdentifier]];\n\n\t\tif (linkPrefix == nil) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSMutableString *muteString = [newMessage mutableCopy];\n\t\t\n\t\twhile (1 == 1) {\n\t\t\tNSRange linkRange = [XRRegularExpression string:muteString rangeOfRegex:_linkMatchRegex];\n\n\t\t\tif (linkRange.location == NSNotFound) {\n\t\t\t\tbreak;\n\t\t\t} else if (linkRange.length < 5) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t\n\t\t\t/* Get inside of brackets */\n\t\t\tNSRange cutRange = NSMakeRange((linkRange.location + 2),\n\t\t\t\t\t\t\t\t\t\t   (linkRange.length - 4));\n\t\t\t\n\t\t\tNSString *linkInside = [muteString substringWithRange:cutRange];\n\t\t\t\n\t\t\t/* Get the left side */\n\t\t\tNSInteger insideBarPosition = [linkInside stringPosition:@\"|\"];\n\n\t\t\tif (insideBarPosition > 0) {\n\t\t\t\tlinkInside = [linkInside substringToIndex:insideBarPosition];\n\n\t\t\t\tlinkInside = [linkInside trim];\n\t\t\t}\n\n\t\t\tlinkInside = [linkInside percentEncodedString];\n\n\t\t\tlinkInside = [linkPrefix stringByAppendingString:linkInside];\n\t\t\t\n\t\t\t[muteString replaceCharactersInRange:linkRange withString:linkInside];\n\t\t}\n\t\t\n\t\treturn muteString;\n\t}\n\t\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark Preference Pane.\n\n- (NSString *)pluginPreferencesPaneMenuItemName\n{\n    return TPILocalizedString(@\"BasicLanguage[0vq-yu]\");\n}\n\n- (NSView *)pluginPreferencesPaneView\n{\n    return self.preferencePane;\n}\n\n#pragma mark -\n#pragma mark Table View delegate\n\n- (void)tableViewSelectionDidChange:(NSNotification *)notification\n{\n\t[self updateRemoveConditionButton];\n}\n\n- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView\n{\n\treturn [self.linkPrefixes count];\n}\n\n- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row\n{\n\tNSString *columnId = [tableColumn identifier];\n\n\tNSArray *entryInfo = self.linkPrefixes[row];\n\n\tif ([columnId isEqualToString:@\"channel\"]) {\n\t\tNSString *entryName = [self channelNameFromId:entryInfo[_indexChannelId]];\n\n\t\tif (entryName == nil) {\n\t\t\treturn TPILocalizedString(@\"BasicLanguage[sb5-c9]\");\n\t\t}\n\n\t\treturn entryName;\n\t} else if ([columnId isEqualToString:@\"link\"]) {\n\t\treturn entryInfo[_indexLinkPrefix];\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark Table View Actions\n\n- (void)removeCondition:(id)sender\n{\n\tNSInteger selectedRow = [self.linkPrefixesTable selectedRow];\n\n\tif (selectedRow < 0) {\n\t\treturn;\n\t}\n\n\tNSMutableArray *linkPrefixes = [self.linkPrefixes mutableCopy];\n\n\t[linkPrefixes removeObjectAtIndex:selectedRow];\n\n\tself.linkPrefixes = linkPrefixes;\n\n\t[self linkPrefixesStorageSave];\n\n\t[self.linkPrefixesTable reloadData];\n}\n\n- (void)updateRemoveConditionButton\n{\n\tNSInteger selectedRow = [self.linkPrefixesTable selectedRow];\n\n\t[self.removeConditionButton setEnabled:(selectedRow >= 0)];\n}\n\n#pragma mark -\n#pragma mark Condition Management\n\n- (void)validatedTextFieldTextDidChange:(id)sender\n{\n\tif (sender == self.rnewConditionLinkPrefixField) {\n\t\t[self updateNewConditionWindowSaveButton:nil];\n\t}\n}\n\n- (void)addCondition:(id)sender\n{\n\t[self.rnewConditionLinkPrefixField setStringValue:NSStringEmptyPlaceholder];\n\n\t[self.rnewConditionChannelPopup removeAllItems];\n\n\t[self.addConditionButton setEnabled:NO];\n\t[self.removeConditionButton setEnabled:NO];\n\n\tNSMutableArray *listOfTrackedIds = [NSMutableArray array];\n\n\tfor (NSArray *entry in self.linkPrefixes) {\n\t\t[listOfTrackedIds addObject:entry[_indexChannelId]];\n\t}\n\n\tfor (IRCClient *u in [worldController() clientList]) {\n\t\t/* Record information about the channel list */\n\t\tNSArray *channelList = [u channelList];\n\n\t\tNSInteger channelCount = [channelList count];\n\n\t\tif (channelCount == 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* Create new menu item for client */\n\t\tNSMenuItem *clientMenuItem = [NSMenuItem new];\n\n\t\t[clientMenuItem setEnabled:NO];\n\n\t\t[clientMenuItem setTitle:[u name]];\n\n\t\t[[self.rnewConditionChannelPopup menu] addItem:clientMenuItem];\n\n\t\t/* Filter channel list */\n\t\tfor (IRCChannel *c in channelList) {\n\t\t\tif ([c isChannel] == NO) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tNSString *channelId = [c uniqueIdentifier];\n\t\t\t\n\t\t\t/* Do we already track it? */\n\t\t\tBOOL channelTracked = [listOfTrackedIds containsObject:channelId];\n\n\t\t\tif (channelTracked) {\n\t\t\t\tchannelCount -= 1; // Decrease channel count by one\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t/* Create new menu item for channel */\n\t\t\tNSString *channelName = [NSString stringWithFormat:@\"    %@\", [c name]];\n\n\t\t\tNSMenuItem *channelMenuItem = [NSMenuItem new];\n\n\t\t\t[channelMenuItem setEnabled:YES];\n\n\t\t\t[channelMenuItem setTitle:channelName];\n\n\t\t\t[channelMenuItem setUserInfo:channelId];\n\n\t\t\t[[self.rnewConditionChannelPopup menu] addItem:channelMenuItem];\n\t\t}\n\n\t\t/* Remove the client title? */\n\t\tif (channelCount <= 0) {\n\t\t\t[[self.rnewConditionChannelPopup menu] removeItem:clientMenuItem];\n\t\t}\n\t}\n\n\tlistOfTrackedIds = nil;\n\n\t/* Present window */\n\t[NSApp beginSheet:self.rnewConditionWindow\n\t   modalForWindow:[NSApp keyWindow]\n\t\tmodalDelegate:self\n\t   didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)\n\t\t  contextInfo:nil];\n\n\t[self.rnewConditionWindow makeFirstResponder:self.rnewConditionLinkPrefixField];\n}\n\n- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo\n{\n\t[sheet close];\n}\n\n- (void)saveNewCondition:(id)sender\n{\n\tif ([self validateLinkPrefix] == NO) {\n\t\treturn;\n\t}\n\n\tNSMutableArray *linkPrefixes = [self.linkPrefixes mutableCopy];\n\n\tNSString *linkPrefix = [self.rnewConditionLinkPrefixField stringValue];\n\n\tNSMenuItem *channelMenuItem = [self.rnewConditionChannelPopup selectedItem];\n\tNSString *channelId = [channelMenuItem userInfo];\n\n\t[linkPrefixes addObjectWithoutDuplication:@[channelId, linkPrefix]];\n\n\tself.linkPrefixes = linkPrefixes;\n\n\t[self linkPrefixesStorageSave];\n\n\t[self.linkPrefixesTable reloadData];\n\n\t[self cancelNewCondition:nil];\n}\n\n- (void)cancelNewCondition:(id)sender\n{\n\t[self.addConditionButton setEnabled:YES];\n\t[self.removeConditionButton setEnabled:YES];\n\n\t[NSApp endSheet:self.rnewConditionWindow];\n\n\t[self updateRemoveConditionButton];\n}\n\n- (void)updateNewConditionWindowSaveButton:(id)sender\n{\n\tBOOL condition2 = [[self.rnewConditionChannelPopup selectedItem] isEnabled];\n\n\t[self.rnewConditionSaveButton setEnabled:condition2];\n}\n\n- (BOOL)validateLinkPrefix\n{\n\tBOOL condition1 = [self.rnewConditionLinkPrefixField valueIsValid];\n\n\tif (condition1 == NO) {\n\t\t[self.rnewConditionLinkPrefixField showValidationErrorPopover];\n\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (BOOL)processWikiStyleLinks\n{\n    return [RZUserDefaults() boolForKey:@\"Wiki-style Link Parser Extension -> Service Enabled\"];\n}\n\n- (void)linkPrefixesStorageRead\n{\n\tNSArray *linkPrefixes = [RZUserDefaults() arrayForKey:@\"Wiki-style Link Parser Extension -> Link Prefixes\"];\n\n\tif (linkPrefixes == nil) {\n\t\tlinkPrefixes = @[];\n\t}\n\n\tself.linkPrefixes = linkPrefixes;\n}\n\n- (void)linkPrefixesStorageSave\n{\n\t[RZUserDefaults() setObject:self.linkPrefixes forKey:@\"Wiki-style Link Parser Extension -> Link Prefixes\"];\n}\n\n- (NSString *)channelNameFromId:(NSString *)itemId\n{\n\tfor (IRCClient *u in [worldController() clientList]) {\n\t\tfor (IRCChannel *c in [u channelList]) {\n\t\t\tif ([[c uniqueIdentifier] isEqualToString:itemId]) {\n\t\t\t\treturn [c name];\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n- (NSString *)linkPrefixFromId:(NSString *)itemId\n{\n\tfor (NSArray *entry in self.linkPrefixes) {\n\t\tif ([entry[_indexChannelId] isEqualToString:itemId]) {\n\t\t\treturn entry[_indexLinkPrefix];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n@end\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2015 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Next unused key: 1004 */\n\n\"0vq-yu\" = \"Wiki-style Link Parser\";\n\"sb5-c9\" = \"Channel Does Not Exist\";\n\"535-5j\" = \"Please enter a properly formatted URL.\";\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.9</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2015 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPIWikiStyleLinkParser</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Resources/User Interface/en.lproj/TPIWikiStyleLinkParser.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.Cocoa.XIB\" version=\"3.0\" toolsVersion=\"17503.1\" targetRuntime=\"MacOSX.Cocoa\" propertyAccessControl=\"none\" useAutolayout=\"YES\">\n    <dependencies>\n        <deployment identifier=\"macosx\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.CocoaPlugin\" version=\"17503.1\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <customObject id=\"-2\" userLabel=\"File's Owner\" customClass=\"TPIWikiStyleLinkParser\">\n            <connections>\n                <outlet property=\"addConditionButton\" destination=\"284\" id=\"305\"/>\n                <outlet property=\"linkPrefixesTable\" destination=\"274\" id=\"299\"/>\n                <outlet property=\"preferencePane\" destination=\"1\" id=\"293\"/>\n                <outlet property=\"removeConditionButton\" destination=\"286\" id=\"304\"/>\n                <outlet property=\"rnewConditionCancelButton\" destination=\"260\" id=\"298\"/>\n                <outlet property=\"rnewConditionChannelPopup\" destination=\"262\" id=\"296\"/>\n                <outlet property=\"rnewConditionLinkPrefixField\" destination=\"244\" id=\"295\"/>\n                <outlet property=\"rnewConditionSaveButton\" destination=\"258\" id=\"297\"/>\n                <outlet property=\"rnewConditionWindow\" destination=\"224\" id=\"294\"/>\n            </connections>\n        </customObject>\n        <customObject id=\"-1\" userLabel=\"First Responder\" customClass=\"FirstResponder\"/>\n        <customObject id=\"-3\" userLabel=\"Application\" customClass=\"NSObject\"/>\n        <customView translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"670\" height=\"456\"/>\n            <subviews>\n                <button translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"64\">\n                    <rect key=\"frame\" x=\"79\" y=\"277\" width=\"109\" height=\"18\"/>\n                    <buttonCell key=\"cell\" type=\"check\" title=\"Enable parser\" bezelStyle=\"regularSquare\" imagePosition=\"left\" state=\"on\" inset=\"2\" id=\"65\">\n                        <behavior key=\"behavior\" changeContents=\"YES\" doesNotDimImage=\"YES\" lightByContents=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <binding destination=\"ak5-9U-7uX\" name=\"value\" keyPath=\"values.Wiki-style Link Parser Extension -&gt; Service Enabled\" id=\"EcC-nM-5pe\"/>\n                    </connections>\n                </button>\n                <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"68\">\n                    <rect key=\"frame\" x=\"79\" y=\"242\" width=\"85\" height=\"16\"/>\n                    <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Link Prefixes:\" id=\"69\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n                <scrollView autohidesScrollers=\"YES\" horizontalLineScroll=\"19\" horizontalPageScroll=\"10\" verticalLineScroll=\"19\" verticalPageScroll=\"10\" usesPredominantAxisScrolling=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"273\">\n                    <rect key=\"frame\" x=\"81\" y=\"58\" width=\"508\" height=\"176\"/>\n                    <clipView key=\"contentView\" id=\"K0X-dB-5Eh\">\n                        <rect key=\"frame\" x=\"1\" y=\"1\" width=\"506\" height=\"174\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <tableView verticalHuggingPriority=\"750\" allowsExpansionToolTips=\"YES\" columnAutoresizingStyle=\"lastColumnOnly\" alternatingRowBackgroundColors=\"YES\" columnReordering=\"NO\" multipleSelection=\"NO\" autosaveColumns=\"NO\" typeSelect=\"NO\" headerView=\"276\" id=\"274\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"506\" height=\"151\"/>\n                                <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                                <size key=\"intercellSpacing\" width=\"3\" height=\"2\"/>\n                                <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <color key=\"gridColor\" name=\"gridColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                <tableColumns>\n                                    <tableColumn identifier=\"channel\" editable=\"NO\" width=\"120.55560302734375\" minWidth=\"40\" maxWidth=\"1000\" id=\"279\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Channel\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" white=\"0.33333298560000002\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"280\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                    <tableColumn identifier=\"link\" editable=\"NO\" width=\"370.34393310546875\" minWidth=\"10\" maxWidth=\"3.4028234663852886e+38\" id=\"282\">\n                                        <tableHeaderCell key=\"headerCell\" lineBreakMode=\"truncatingTail\" borderStyle=\"border\" alignment=\"left\" title=\"Link Prefix\">\n                                            <color key=\"textColor\" name=\"headerTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"headerColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </tableHeaderCell>\n                                        <textFieldCell key=\"dataCell\" lineBreakMode=\"truncatingTail\" selectable=\"YES\" editable=\"YES\" alignment=\"left\" title=\"Text Cell\" id=\"283\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"controlBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <tableColumnResizingMask key=\"resizingMask\" resizeWithTable=\"YES\" userResizable=\"YES\"/>\n                                    </tableColumn>\n                                </tableColumns>\n                                <connections>\n                                    <binding destination=\"ak5-9U-7uX\" name=\"enabled\" keyPath=\"values.Wiki-style Link Parser Extension -&gt; Service Enabled\" id=\"TbJ-2e-ZVP\"/>\n                                    <outlet property=\"dataSource\" destination=\"-2\" id=\"289\"/>\n                                    <outlet property=\"delegate\" destination=\"-2\" id=\"290\"/>\n                                </connections>\n                            </tableView>\n                        </subviews>\n                    </clipView>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"176\" id=\"5gT-nk-eUH\"/>\n                    </constraints>\n                    <scroller key=\"horizontalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"YES\" id=\"275\">\n                        <rect key=\"frame\" x=\"1\" y=\"159\" width=\"506\" height=\"16\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <scroller key=\"verticalScroller\" hidden=\"YES\" wantsLayer=\"YES\" verticalHuggingPriority=\"750\" horizontal=\"NO\" id=\"277\">\n                        <rect key=\"frame\" x=\"478\" y=\"23\" width=\"16\" height=\"0.0\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </scroller>\n                    <tableHeaderView key=\"headerView\" wantsLayer=\"YES\" id=\"276\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"506\" height=\"23\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                    </tableHeaderView>\n                </scrollView>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"284\">\n                    <rect key=\"frame\" x=\"81\" y=\"29\" width=\"30\" height=\"22\"/>\n                    <constraints>\n                        <constraint firstAttribute=\"height\" constant=\"20\" id=\"1l7-Ov-5ZI\"/>\n                        <constraint firstAttribute=\"width\" constant=\"30\" id=\"FlJ-4n-sQu\"/>\n                    </constraints>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSAddTemplate\" imagePosition=\"overlaps\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"285\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"addCondition:\" target=\"-2\" id=\"291\"/>\n                        <binding destination=\"ak5-9U-7uX\" name=\"enabled\" keyPath=\"values.Wiki-style Link Parser Extension -&gt; Service Enabled\" id=\"ExP-nb-61m\"/>\n                    </connections>\n                </button>\n                <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"286\">\n                    <rect key=\"frame\" x=\"112\" y=\"29\" width=\"30\" height=\"22\"/>\n                    <buttonCell key=\"cell\" type=\"smallSquare\" bezelStyle=\"smallSquare\" image=\"NSRemoveTemplate\" imagePosition=\"overlaps\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"287\">\n                        <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                        <font key=\"font\" metaFont=\"system\"/>\n                    </buttonCell>\n                    <connections>\n                        <action selector=\"removeCondition:\" target=\"-2\" id=\"292\"/>\n                        <binding destination=\"ak5-9U-7uX\" name=\"enabled\" keyPath=\"values.Wiki-style Link Parser Extension -&gt; Service Enabled\" id=\"8iU-1p-dSO\"/>\n                    </connections>\n                </button>\n                <textField verticalHuggingPriority=\"750\" horizontalCompressionResistancePriority=\"250\" setsMaxLayoutWidthAtFirstLayout=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qFq-B6-Sdv\">\n                    <rect key=\"frame\" x=\"79\" y=\"314\" width=\"512\" height=\"112\"/>\n                    <textFieldCell key=\"cell\" selectable=\"YES\" id=\"m2E-Ta-egB\">\n                        <font key=\"font\" metaFont=\"system\"/>\n                        <string key=\"title\">This addon replaces Wiki-markup title blocks, similar to [[&lt;title&gt;]], with a link to the article they represent.\n\nEach channel is assigned a “Link Prefix” which is the URL prepended to the title of the article that will be linked to.\n\nReplaced title blocks are only visible to you.</string>\n                        <color key=\"textColor\" name=\"labelColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                        <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                    </textFieldCell>\n                </textField>\n            </subviews>\n            <constraints>\n                <constraint firstItem=\"284\" firstAttribute=\"leading\" secondItem=\"273\" secondAttribute=\"leading\" id=\"2WC-Lo-2fz\"/>\n                <constraint firstItem=\"68\" firstAttribute=\"leading\" secondItem=\"273\" secondAttribute=\"leading\" id=\"C5s-UU-9dL\"/>\n                <constraint firstItem=\"286\" firstAttribute=\"firstBaseline\" secondItem=\"284\" secondAttribute=\"firstBaseline\" id=\"C69-dS-W8g\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"284\" secondAttribute=\"bottom\" constant=\"30\" id=\"G6R-Uv-lcI\"/>\n                <constraint firstItem=\"286\" firstAttribute=\"width\" secondItem=\"284\" secondAttribute=\"width\" id=\"Gqx-fv-H1t\"/>\n                <constraint firstItem=\"64\" firstAttribute=\"top\" secondItem=\"qFq-B6-Sdv\" secondAttribute=\"bottom\" constant=\"20\" id=\"OOw-0e-jCs\"/>\n                <constraint firstItem=\"286\" firstAttribute=\"leading\" secondItem=\"284\" secondAttribute=\"trailing\" constant=\"1\" id=\"Oty-ql-PE0\"/>\n                <constraint firstItem=\"284\" firstAttribute=\"top\" secondItem=\"273\" secondAttribute=\"bottom\" constant=\"8\" id=\"QPW-qE-PSp\"/>\n                <constraint firstItem=\"273\" firstAttribute=\"top\" secondItem=\"68\" secondAttribute=\"bottom\" constant=\"8\" symbolic=\"YES\" id=\"TUc-iM-2d5\"/>\n                <constraint firstItem=\"286\" firstAttribute=\"height\" secondItem=\"284\" secondAttribute=\"height\" id=\"Zck-bD-8Jd\"/>\n                <constraint firstItem=\"68\" firstAttribute=\"leading\" secondItem=\"64\" secondAttribute=\"leading\" id=\"gBt-IL-Ihl\"/>\n                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"64\" secondAttribute=\"trailing\" constant=\"20\" id=\"jkb-3Q-SkS\"/>\n                <constraint firstItem=\"64\" firstAttribute=\"leading\" secondItem=\"qFq-B6-Sdv\" secondAttribute=\"leading\" id=\"mIH-qW-iRM\"/>\n                <constraint firstItem=\"68\" firstAttribute=\"trailing\" relation=\"lessThanOrEqual\" secondItem=\"273\" secondAttribute=\"trailing\" id=\"nQx-1v-XfB\"/>\n                <constraint firstItem=\"qFq-B6-Sdv\" firstAttribute=\"centerX\" secondItem=\"1\" secondAttribute=\"centerX\" id=\"pLH-QH-EYT\"/>\n                <constraint firstItem=\"qFq-B6-Sdv\" firstAttribute=\"top\" secondItem=\"1\" secondAttribute=\"top\" constant=\"30\" id=\"uYO-VT-br3\"/>\n                <constraint firstItem=\"68\" firstAttribute=\"top\" secondItem=\"64\" secondAttribute=\"bottom\" constant=\"20\" id=\"uzQ-tN-oSt\"/>\n                <constraint firstItem=\"273\" firstAttribute=\"leading\" relation=\"lessThanOrEqual\" secondItem=\"286\" secondAttribute=\"trailing\" id=\"xkR-8E-Fa4\"/>\n                <constraint firstItem=\"273\" firstAttribute=\"trailing\" secondItem=\"qFq-B6-Sdv\" secondAttribute=\"trailing\" id=\"zF7-IU-IQm\"/>\n            </constraints>\n            <point key=\"canvasLocation\" x=\"593\" y=\"460\"/>\n        </customView>\n        <window title=\"New Condition\" allowsToolTipsWhenApplicationIsInactive=\"NO\" autorecalculatesKeyViewLoop=\"NO\" restorable=\"NO\" releasedWhenClosed=\"NO\" visibleAtLaunch=\"NO\" animationBehavior=\"default\" id=\"224\">\n            <windowStyleMask key=\"styleMask\" titled=\"YES\" closable=\"YES\"/>\n            <windowPositionMask key=\"initialPositionMask\" leftStrut=\"YES\" rightStrut=\"YES\" topStrut=\"YES\" bottomStrut=\"YES\"/>\n            <rect key=\"contentRect\" x=\"283\" y=\"305\" width=\"448\" height=\"127\"/>\n            <rect key=\"screenRect\" x=\"0.0\" y=\"0.0\" width=\"2560\" height=\"1415\"/>\n            <view key=\"contentView\" id=\"225\">\n                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"448\" height=\"127\"/>\n                <autoresizingMask key=\"autoresizingMask\"/>\n                <subviews>\n                    <stackView distribution=\"fill\" orientation=\"vertical\" alignment=\"leading\" spacing=\"6\" horizontalStackHuggingPriority=\"249.99998474121094\" verticalStackHuggingPriority=\"249.99998474121094\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GxG-ac-8fm\">\n                        <rect key=\"frame\" x=\"20\" y=\"60\" width=\"410\" height=\"47\"/>\n                        <subviews>\n                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"249.99998474121094\" verticalStackHuggingPriority=\"249.99998474121094\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0qA-7x-CeJ\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"26\" width=\"410\" height=\"21\"/>\n                                <subviews>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"242\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"114\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"Use the link prefix\" id=\"243\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"244\" customClass=\"TVCValidatedTextField\">\n                                        <rect key=\"frame\" x=\"118\" y=\"0.0\" width=\"292\" height=\"21\"/>\n                                        <textFieldCell key=\"cell\" scrollable=\"YES\" lineBreakMode=\"clipping\" selectable=\"YES\" editable=\"YES\" sendsActionOnEndEditing=\"YES\" state=\"on\" borderStyle=\"bezel\" placeholderString=\"https://en.wikipedia.org/wiki/\" id=\"245\" customClass=\"TVCValidatedTextFieldCell\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"controlTextColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                        <connections>\n                                            <action selector=\"updateNewConditionWindowSaveButton:\" target=\"-2\" id=\"300\"/>\n                                        </connections>\n                                    </textField>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                            <stackView distribution=\"fill\" orientation=\"horizontal\" alignment=\"firstBaseline\" horizontalStackHuggingPriority=\"249.99998474121094\" verticalStackHuggingPriority=\"249.99998474121094\" detachesHiddenViews=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yR3-ER-cgo\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"410\" height=\"20\"/>\n                                <subviews>\n                                    <textField verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"246\">\n                                        <rect key=\"frame\" x=\"-2\" y=\"3\" width=\"89\" height=\"16\"/>\n                                        <textFieldCell key=\"cell\" lineBreakMode=\"truncatingTail\" sendsActionOnEndEditing=\"YES\" title=\"in the channel\" id=\"247\">\n                                            <font key=\"font\" metaFont=\"system\"/>\n                                            <color key=\"textColor\" name=\"textColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                            <color key=\"backgroundColor\" name=\"textBackgroundColor\" catalog=\"System\" colorSpace=\"catalog\"/>\n                                        </textFieldCell>\n                                    </textField>\n                                    <popUpButton horizontalHuggingPriority=\"249\" verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"262\">\n                                        <rect key=\"frame\" x=\"90\" y=\"-4\" width=\"324\" height=\"25\"/>\n                                        <popUpButtonCell key=\"cell\" type=\"push\" bezelStyle=\"rounded\" alignment=\"left\" lineBreakMode=\"truncatingTail\" borderStyle=\"borderAndBezel\" imageScaling=\"proportionallyDown\" inset=\"2\" autoenablesItems=\"NO\" id=\"263\">\n                                            <behavior key=\"behavior\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                                            <font key=\"font\" metaFont=\"menu\"/>\n                                            <menu key=\"menu\" title=\"OtherViews\" autoenablesItems=\"NO\" id=\"264\"/>\n                                        </popUpButtonCell>\n                                        <connections>\n                                            <action selector=\"updateNewConditionWindowSaveButton:\" target=\"-2\" id=\"309\"/>\n                                        </connections>\n                                    </popUpButton>\n                                </subviews>\n                                <visibilityPriorities>\n                                    <integer value=\"1000\"/>\n                                    <integer value=\"1000\"/>\n                                </visibilityPriorities>\n                                <customSpacing>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                    <real value=\"3.4028234663852886e+38\"/>\n                                </customSpacing>\n                            </stackView>\n                        </subviews>\n                        <visibilityPriorities>\n                            <integer value=\"1000\"/>\n                            <integer value=\"1000\"/>\n                        </visibilityPriorities>\n                        <customSpacing>\n                            <real value=\"3.4028234663852886e+38\"/>\n                            <real value=\"3.4028234663852886e+38\"/>\n                        </customSpacing>\n                    </stackView>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"258\">\n                        <rect key=\"frame\" x=\"373\" y=\"13\" width=\"64\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Save\" bezelStyle=\"rounded\" alignment=\"center\" state=\"on\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"259\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nDQ\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"saveNewCondition:\" target=\"-2\" id=\"307\"/>\n                        </connections>\n                    </button>\n                    <button verticalHuggingPriority=\"750\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"260\">\n                        <rect key=\"frame\" x=\"299\" y=\"13\" width=\"76\" height=\"32\"/>\n                        <buttonCell key=\"cell\" type=\"push\" title=\"Cancel\" bezelStyle=\"rounded\" alignment=\"center\" borderStyle=\"border\" imageScaling=\"proportionallyDown\" inset=\"2\" id=\"261\">\n                            <behavior key=\"behavior\" pushIn=\"YES\" lightByBackground=\"YES\" lightByGray=\"YES\"/>\n                            <font key=\"font\" metaFont=\"system\"/>\n                            <string key=\"keyEquivalent\" base64-UTF8=\"YES\">\nGw\n</string>\n                        </buttonCell>\n                        <connections>\n                            <action selector=\"cancelNewCondition:\" target=\"-2\" id=\"306\"/>\n                        </connections>\n                    </button>\n                </subviews>\n                <constraints>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"258\" secondAttribute=\"trailing\" constant=\"20\" id=\"3K6-md-ogp\"/>\n                    <constraint firstItem=\"GxG-ac-8fm\" firstAttribute=\"top\" secondItem=\"225\" secondAttribute=\"top\" constant=\"20\" id=\"Hbo-RH-CLI\"/>\n                    <constraint firstAttribute=\"bottom\" secondItem=\"258\" secondAttribute=\"bottom\" constant=\"20\" id=\"ISX-Ln-AKB\"/>\n                    <constraint firstAttribute=\"trailing\" secondItem=\"GxG-ac-8fm\" secondAttribute=\"trailing\" constant=\"20\" id=\"MDt-ef-feW\"/>\n                    <constraint firstItem=\"GxG-ac-8fm\" firstAttribute=\"leading\" secondItem=\"225\" secondAttribute=\"leading\" constant=\"20\" id=\"Tjs-bL-sW7\"/>\n                    <constraint firstItem=\"258\" firstAttribute=\"leading\" secondItem=\"260\" secondAttribute=\"trailing\" constant=\"12\" symbolic=\"YES\" id=\"aFj-4x-amE\"/>\n                    <constraint firstItem=\"258\" firstAttribute=\"top\" secondItem=\"GxG-ac-8fm\" secondAttribute=\"bottom\" constant=\"20\" id=\"ej6-TM-tKi\"/>\n                    <constraint firstItem=\"260\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"225\" secondAttribute=\"leading\" constant=\"20\" id=\"oc0-NC-bRR\"/>\n                    <constraint firstItem=\"260\" firstAttribute=\"firstBaseline\" secondItem=\"258\" secondAttribute=\"firstBaseline\" id=\"qhq-pI-9ag\"/>\n                </constraints>\n            </view>\n            <point key=\"canvasLocation\" x=\"165.5\" y=\"110.5\"/>\n        </window>\n        <userDefaultsController id=\"ak5-9U-7uX\" customClass=\"TPCPreferencesUserDefaultsController\"/>\n    </objects>\n    <resources>\n        <image name=\"NSAddTemplate\" width=\"14\" height=\"13\"/>\n        <image name=\"NSRemoveTemplate\" width=\"14\" height=\"4\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Wiki-style Link Parser Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AACB20F27B2E007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAC920F27B2E007CA939 /* BasicLanguage.strings */; };\n\t\t4C36AACE20F27B85007CA939 /* TPIWikiStyleLinkParser.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AACC20F27B85007CA939 /* TPIWikiStyleLinkParser.xib */; };\n\t\t4C46A14720EC6E4E00094EA4 /* TPIWikiStyleLinkParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A14520EC6E4D00094EA4 /* TPIWikiStyleLinkParser.m */; };\n\t\t4CBE7B481A9146E2008FB230 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBE7B471A9146E2008FB230 /* CocoaExtensions.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C36AACA20F27B2E007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C36AACD20F27B85007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/TPIWikiStyleLinkParser.xib; sourceTree = \"<group>\"; };\n\t\t4C46A0E420EC6DD900094EA4 /* Inherited.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Inherited.entitlements; sourceTree = \"<group>\"; };\n\t\t4C46A0E820EC6DD900094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A0E920EC6DD900094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0ED20EC6DD900094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0F020EC6DD900094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A0F120EC6DD900094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0F520EC6DD900094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0F920EC6DD900094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A0FA20EC6DD900094EA4 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0FB20EC6DD900094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A0FD20EC6DD900094EA4 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A10020EC6DD900094EA4 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A10420EC6DD900094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A10520EC6DD900094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A10920EC6DD900094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A10C20EC6DD900094EA4 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C46A10D20EC6DD900094EA4 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A11120EC6DD900094EA4 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C46A13B20EC6E3C00094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A14520EC6E4D00094EA4 /* TPIWikiStyleLinkParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPIWikiStyleLinkParser.m; sourceTree = \"<group>\"; };\n\t\t4C46A14620EC6E4D00094EA4 /* TPIWikiStyleLinkParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPIWikiStyleLinkParser.h; sourceTree = \"<group>\"; };\n\t\t4CBE7B471A9146E2008FB230 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = \"<group>\"; };\n\t\t8D576316048677EA00EA77CD /* WikiStyleLinkParser.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WikiStyleLinkParser.bundle; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CBE7B481A9146E2008FB230 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BragSpam */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A14420EC6E4D00094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BragSpam;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBE7B471A9146E2008FB230 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0E120EC6DD900094EA4 /* Configurations */,\n\t\t\t\t4C46A13C20EC6E3C00094EA4 /* Language Files */,\n\t\t\t\t4C46A13A20EC6E3C00094EA4 /* Property Lists */,\n\t\t\t\t4C46A13E20EC6E3C00094EA4 /* User Interface */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* WikiStyleLinkParser.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0E120EC6DD900094EA4 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0E520EC6DD900094EA4 /* Build */,\n\t\t\t\t4C46A0E320EC6DD900094EA4 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C46A0E320EC6DD900094EA4 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0E420EC6DD900094EA4 /* Inherited.entitlements */,\n\t\t\t);\n\t\t\tpath = Sandbox;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0E520EC6DD900094EA4 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0EE20EC6DD900094EA4 /* App Store Release */,\n\t\t\t\t4C46A0F720EC6DD900094EA4 /* Common */,\n\t\t\t\t4C46A10A20EC6DD900094EA4 /* Debug */,\n\t\t\t\t4C46A0E620EC6DD900094EA4 /* Standard Release */,\n\t\t\t\t4C46A10220EC6DD900094EA4 /* Standard Release Sandboxed */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0E620EC6DD900094EA4 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0ED20EC6DD900094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A0E920EC6DD900094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A0E820EC6DD900094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0EE20EC6DD900094EA4 /* App Store Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A0F520EC6DD900094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A0F120EC6DD900094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A0F020EC6DD900094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"App Store Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A0F720EC6DD900094EA4 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A10020EC6DD900094EA4 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C46A0FD20EC6DD900094EA4 /* Foundation.xcconfig */,\n\t\t\t\t4C46A0FA20EC6DD900094EA4 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C46A0FB20EC6DD900094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A0F920EC6DD900094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A10220EC6DD900094EA4 /* Standard Release Sandboxed */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A10920EC6DD900094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A10520EC6DD900094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A10420EC6DD900094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release Sandboxed\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A10A20EC6DD900094EA4 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A11120EC6DD900094EA4 /* Enabled Features.xcconfig */,\n\t\t\t\t4C46A10D20EC6DD900094EA4 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C46A10C20EC6DD900094EA4 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A13A20EC6E3C00094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A13B20EC6E3C00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A13C20EC6E3C00094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAC920F27B2E007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A13E20EC6E3C00094EA4 /* User Interface */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AACC20F27B85007CA939 /* TPIWikiStyleLinkParser.xib */,\n\t\t\t);\n\t\t\tpath = \"User Interface\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A14420EC6E4D00094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A14620EC6E4D00094EA4 /* TPIWikiStyleLinkParser.h */,\n\t\t\t\t4C46A14520EC6E4D00094EA4 /* TPIWikiStyleLinkParser.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* Wiki-style Link Parser Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Wiki-style Link Parser Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Wiki-style Link Parser Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BragSpam;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* WikiStyleLinkParser.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastUpgradeCheck = 1100;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Wiki-style Link Parser Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BragSpam */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* Wiki-style Link Parser Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AACE20F27B85007CA939 /* TPIWikiStyleLinkParser.xib in Resources */,\n\t\t\t\t4C36AACB20F27B2E007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A14720EC6E4E00094EA4 /* TPIWikiStyleLinkParser.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAC920F27B2E007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AACA20F27B2E007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C36AACC20F27B85007CA939 /* TPIWikiStyleLinkParser.xib */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AACD20F27B85007CA939 /* en */,\n\t\t\t);\n\t\t\tname = TPIWikiStyleLinkParser.xib;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-WikiStyleLinkParser\";\n\t\t\t\tPRODUCT_NAME = WikiStyleLinkParser;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-WikiStyleLinkParser\";\n\t\t\t\tPRODUCT_NAME = WikiStyleLinkParser;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A10D20EC6DD900094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A0E920EC6DD900094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C9580241FA41FA800F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C46A0F120EC6DD900094EA4 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4C9580251FA41FA800F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-WikiStyleLinkParser\";\n\t\t\t\tPRODUCT_NAME = WikiStyleLinkParser;\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"Wiki-style Link Parser Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4C9580251FA41FA800F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"Wiki-style Link Parser Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4C9580241FA41FA800F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Plugins/Wiki Link Parser/Wiki-style Link Parser Extension.xcodeproj/xcshareddata/xcschemes/Wiki-style Link Parser Extension.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1000\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n               BuildableName = \"WikiStyleLinkParser.bundle\"\n               BlueprintName = \"Wiki-style Link Parser Extension\"\n               ReferencedContainer = \"container:Wiki-style Link Parser Extension.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Release\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"WikiStyleLinkParser.bundle\"\n            BlueprintName = \"Wiki-style Link Parser Extension\"\n            ReferencedContainer = \"container:Wiki-style Link Parser Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <AdditionalOptions>\n      </AdditionalOptions>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"8D57630D048677EA00EA77CD\"\n            BuildableName = \"WikiStyleLinkParser.bundle\"\n            BlueprintName = \"Wiki-style Link Parser Extension\"\n            ReferencedContainer = \"container:Wiki-style Link Parser Extension.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Release\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Sources/Plugins/ZNC Additions/Classes/TPI_ZNCAdditions.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2011 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"Textual.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPI_ZNCAdditions : NSObject <THOPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/ZNC Additions/Classes/TPI_ZNCAdditions.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2011 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <SecurityInterface/SFCertificateTrustPanel.h>\n\n#import \"TPI_ZNCAdditions.h\"\n\n#import \"IRCClientPrivate.h\"\n#import \"TVCMainWindowPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPI_ZNCAdditions\n\n#pragma mark -\n#pragma mark Plugin API\n\n- (void)didReceiveServerInput:(THOPluginDidReceiveServerInputConcreteObject *)inputObject onClient:(IRCClient *)client\n{\n\tif (client.isConnectedToZNC == NO) {\n\t\treturn;\n\t}\n\n\tNSString *sender = inputObject.senderNickname;\n\n\tNSString *message = inputObject.messageSequence;\n\n\tif ([client nickname:sender isZNCUser:@\"status\"] && [message hasPrefix:@\"Disconnected from IRC\"]) {\n\t\t/* We listen for ZNC disconnects so that we can terminate channels when we\n\t\t disconnect from the server ZNC was connected to. ZNC does not localize \n\t\t itself so detecting these disconnects is not very hard... */\n\n\t\tXRPerformBlockSynchronouslyOnMainQueue(^{\n\t\t\t[self handleIRCSideDisconnect:client];\n\t\t});\n\t}\n}\n\n- (void)userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t  commandString:(NSString *)commandString\n\t\t\t\t\t\t  messageString:(NSString *)messageString\n{\n\tXRPerformBlockAsynchronouslyOnMainQueue(^{\n\t\t[self _userInputCommandInvokedOnClient:client\n\t\t\t\t\t\t\t\t commandString:commandString\n\t\t\t\t\t\t\t\t messageString:messageString];\n\t});\n}\n\n- (void)_userInputCommandInvokedOnClient:(IRCClient *)client\n\t\t\t\t\t\t   commandString:(NSString *)commandString\n\t\t\t\t\t\t   messageString:(NSString *)messageString\n{\n\t/* Throw error if user tries to invoke a command that requires the\n\t user to be connected to a ZNC bouncer */\n\tif (client.isConnectedToZNC == NO) {\n\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[xex-nl]\")];\n\n\t\treturn;\n\t}\n\n\t/* Process commands */\n\tif ([commandString isEqualToStringIgnoringCase:@\"ZNCCERT\"])\n\t{\n\t\t/* Textual is designed not to import partial content. It will either\n\t\t return the complete certificate chain at this point, or nil. */\n\t\tNSData *certificateData = client.zncBouncerCertificateChainData;\n\n\t\tif (certificateData == nil) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[moh-hg]\")];\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Given the raw, base64 encoded data, convert it into certificate objects. */\n\t\tSecItemImportExportKeyParameters importParameters;\n\n\t\timportParameters.flags = kSecKeyNoAccessControl;\n\t\timportParameters.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;\n\n\t\timportParameters.accessRef = NULL;\n\t\timportParameters.alertTitle = NULL;\n\t\timportParameters.alertPrompt = NULL;\n\t\timportParameters.passphrase = NULL;\n\n\t\timportParameters.keyAttributes = NULL;\n\t\timportParameters.keyUsage = NULL;\n\n\t\tSecExternalItemType itemType = kSecItemTypeCertificate;\n\n\t\tSecExternalFormat externalFormat = kSecFormatPEMSequence;\n\n\t\tint flags = 0;\n\n\t\tCFArrayRef certificateArray = NULL;\n\n\t\tOSStatus operationStatus =\n\t\tSecItemImport((__bridge CFDataRef)(certificateData), NULL, &externalFormat, &itemType, flags, &importParameters, NULL, &certificateArray);\n\n\t\t/* Display an error or hand the certificate chain off \n\t\t to Apple's own APIs to display them in a dialog. */\n\t\tif (operationStatus != noErr) {\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[wco-zv]\")];\n\n\t\t\treturn;\n\t\t}\n\n\t\tSFCertificateTrustPanel *panel = [SFCertificateTrustPanel new];\n\n\t\t[panel setDefaultButtonTitle:TXTLS(@\"Prompts[aqw-q1]\")];\n\n\t\t[panel setAlternateButtonTitle:nil];\n\n\t\t[panel beginSheetForWindow:[NSApp mainWindow]\n\t\t\t\t\t modalDelegate:nil\n\t\t\t\t\tdidEndSelector:NULL\n\t\t\t\t\t   contextInfo:NULL\n\t\t\t\t\t  certificates:(__bridge NSArray *)certificateArray\n\t\t\t\t\t\t showGroup:YES];\n\n\t\tCFRelease(certificateArray);\n\t}\n\n\t/* ------ */\n\n\telse if ([commandString isEqualToStringIgnoringCase:@\"DETACH\"] ||\n\t\t\t [commandString isEqualToStringIgnoringCase:@\"ATTACH\"])\n\t{\n\t\tmessageString = messageString.trim;\n\n\t\tIRCChannel *matchedChannel = nil;\n\n\t\tif ([client stringIsChannelName:messageString]) {\n\t\t\tmatchedChannel = [client findChannel:messageString];\n\t\t} else {\n\t\t\tmatchedChannel = mainWindow().selectedChannel;\n\t\t}\n\n\t\tif (matchedChannel == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tBOOL isAttachEvent = [commandString isEqualToStringIgnoringCase:@\"ATTACH\"];\n\n\t\tmatchedChannel.autoJoin = isAttachEvent;\n\n\t\tif (isAttachEvent) {\n\t\t\t[client joinUnlistedChannel:matchedChannel.name];\n\t\t} else {\n\t\t\t[client sendLine:[NSString stringWithFormat:@\"%@ %@\", commandString, matchedChannel.name]];\n\n\t\t\t[client printDebugInformation:TPILocalizedString(@\"BasicLanguage[0fr-kb]\", matchedChannel.name) inChannel:matchedChannel];\n\t\t}\n\t}\n}\n\n- (NSArray *)subscribedUserInputCommands\n{\n\treturn @[@\"detach\", @\"attach\", @\"znccert\"];\n}\n\n- (NSArray *)subscribedServerInputCommands\n{\n\treturn @[@\"privmsg\"];\n}\n\n- (nullable IRCMessage *)interceptBufferExtrasPlaybackModule:(IRCMessage *)input forClient:(IRCClient *)client\n{\n\tif ([client isCapabilityEnabled:ClientIRCv3SupportedCapabilityZNCPlaybackModule] == NO) {\n\t\treturn input;\n\t}\n\n\tNSString *stringIn = [input paramAt:1];\n\n\tif ([stringIn hasPrefix:@\"The playback buffer for [\"]\t&&\n\t\t[stringIn contains:@\"] channels matching [\"]\t\t&& // This is much cleaner than regular expression...\n\t\t[stringIn hasSuffix:@\"] has been cleared.\"])\n\t{\n\t\treturn nil; // Ignore this event\n\t}\n\n\treturn input;\n}\n\n- (nullable IRCMessage *)interceptBufferExtrasZNCModule:(IRCMessage *)input forClient:(IRCClient *)client\n{\n\t/* Define user information */\n\tNSMutableArray<NSString *> *paramsMutable = [input.params mutableCopy];\n\n\t/* We have to normalize spaces for input from buffextras because as of version\n\t 1.7, there are fixed width spaces in the incoming messages that throw off parser. */\n\tNSMutableString *stringIn = [paramsMutable[1].normalizeSpaces mutableCopy];\n\n\tNSString *hostmask = stringIn.token;\n\n\tif (hostmask.length == 0) {\n\t\treturn input; // Return original; bad input\n\t}\n\n\tIRCPrefixMutable *senderMutable = [input.sender mutableCopy];\n\n\tNSString *nicknameInt = nil;\n\tNSString *usernameInt = nil;\n\tNSString *addressInt = nil;\n\n\tif ([hostmask hostmaskComponents:&nicknameInt username:&usernameInt address:&addressInt onClient:client]) {\n\t\tif ([nicknameInt isEqualToString:client.userNickname]) {\n\t\t\treturn nil; // Do not post these events for self\n\t\t}\n\n\t\tsenderMutable.nickname = nicknameInt;\n\t\tsenderMutable.username = usernameInt;\n\t\tsenderMutable.address = addressInt;\n\n\t\tsenderMutable.isServer = NO;\n\t} else {\n\t\tsenderMutable.nickname = hostmask;\n\n\t\tsenderMutable.isServer = YES;\n\t}\n\n\tsenderMutable.hostmask = hostmask;\n\n\t/* Process string */\n\t/* The output of the buffextras module is not guaranteed.\n\t The ZNC author(s) have stated that they shouldn't be treated as such.\n\t ZNC 1.7 changed it so that the output of the module can be localized.\n\t We will ever only handle English here to reduce footprint. */\n\tIRCMessageMutable *inputMutable = [input mutableCopy];\n\t\n\tNSArray<NSString *> *stringInComponents = nil;\n\n\tif ([stringIn isEqualToString:@\"joined\"])\n\t{\n\t\t/* Begin channel join */\n\t\tinputMutable.command = @\"JOIN\";\n\t\t\n\t\t[paramsMutable removeObjectAtIndex:1];\n\t\t/* End channel join */\n\t}\n\telse if ([XRRegularExpression matches:&stringInComponents inString:stringIn withRegex:@\"^is now known as ([^\\\\s]+)$\" withoutCase:NO substringGroups:YES] == 2)\n\t{\n\t\t/* Begin nickname change */\n\t\tNSString *newNickname = stringInComponents[1];\n\n\t\tinputMutable.command = @\"NICK\";\n\n\t\t[paramsMutable removeObjectAtIndex:1];\n\n\t\t[paramsMutable addObject:newNickname];\n\t\t/* End nickname change */\n\t}\n\telse if ([XRRegularExpression matches:&stringInComponents inString:stringIn withRegex:@\"^(parted with message: \\\\[(.*)\\\\]|parted: (.*))$\" withoutCase:NO substringGroups:YES] == 3)\n\t{\n\t\t/* Begin part message */\n\t\tNSString *partMessage = stringInComponents[2];\n\t\n\t\tinputMutable.command = @\"PART\";\n\t\t\n\t\t[paramsMutable removeObjectAtIndex:1];\n\t\t\n\t\t[paramsMutable addObject:partMessage];\n\t\t/* End part message */\n\t}\n\telse if ([XRRegularExpression matches:&stringInComponents inString:stringIn withRegex:@\"^(quit with message: \\\\[(.*)\\\\]|quit: (.*))$\" withoutCase:NO substringGroups:YES] == 3)\n\t{\n\t\t/* Begin quit message */\n\t\tNSString *quitMessage = stringInComponents[2];\n\n\t\tinputMutable.command = @\"QUIT\";\n\t\t\n\t\t[paramsMutable removeObjectAtIndex:1];\n\t\t\n\t\t[paramsMutable addObject:quitMessage];\n\t\t/* End quit message */\n\t}\n\telse if ([XRRegularExpression matches:&stringInComponents inString:stringIn withRegex:@\"^(kicked ([^\\\\s]+) with reason: (.*)|kicked ([^\\\\s]+) Reason: \\\\[(.*)\\\\])$\" withoutCase:NO substringGroups:YES] == 4)\n\t{\n\t\t/* Begin kick message */\n\t\tNSString *kickedNickname = stringInComponents[2];\n\t\t\n\t\tNSString *kickReason = stringInComponents[3];\n\t\t\n\t\tinputMutable.command = @\"KICK\";\n\t\t\n\t\t[paramsMutable removeObjectAtIndex:1];\n\t\t\n\t\t[paramsMutable addObject:kickedNickname];\n\t\t\n\t\t[paramsMutable addObject:kickReason];\n\t\t/* End kick message. */\n\t}\n\telse if ([XRRegularExpression matches:&stringInComponents inString:stringIn withRegex:@\"^set mode: ([^\\\\s]+)( .*)?$\" withoutCase:NO substringGroups:YES] >= 2)\n\t{\n\t\t/* Begin mode processing */\n\t\tNSString *modeChanges = stringInComponents[1];\n\t\t\n\t\tif (stringInComponents.count == 3) {\n\t\t\tmodeChanges = [modeChanges stringByAppendingString:stringInComponents[2]];\n\t\t}\n\n\t\tinputMutable.command = @\"MODE\";\n\n\t\t[paramsMutable removeObjectAtIndex:1];\n\n\t\t[paramsMutable addObject:modeChanges];\n\t\t/* End mode processing */\n\t}\n\telse if ([stringIn hasPrefix:@\"changed the topic to: \"])\n\t{\n\t\t/* Begin topic change */\n\t\t/* We get the latest topic on join so we tell Textual to ignore this line. */\n\n\t\treturn nil;\n\t\t/* End topic change */\n\t}\n\n\t/* Return modified input */\n\tinputMutable.isPrintOnlyMessage = YES;\n\n\tinputMutable.params = paramsMutable;\n\n\tinputMutable.sender = senderMutable;\n\n\treturn inputMutable;\n}\n\n- (nullable IRCMessage *)interceptServerInput:(IRCMessage *)input for:(IRCClient *)client\n{\n\tif (input.paramsCount != 2) {\n\t\treturn input;\n\t}\n\n\tif (client.isConnectedToZNC == NO) {\n\t\treturn input;\n\t}\n\n\tif ([input.command isEqualToString:@\"PRIVMSG\"] == NO) {\n\t\treturn input;\n\t}\n\n\tIRCPrefix *senderInfo = input.sender;\n\n\tNSString *sender = senderInfo.nickname;\n\n\tif ([client nickname:sender isZNCUser:@\"buffextras\"]) {\n\t\treturn [self interceptBufferExtrasZNCModule:input forClient:client];\n\t} else if ([client nickname:sender isZNCUser:@\"playback\"]) {\n\t\treturn [self interceptBufferExtrasPlaybackModule:input forClient:client];\n\t}\n\n\treturn input;\n}\n\n#pragma mark -\n#pragma mark Private API\n\n- (void)handleIRCSideDisconnect:(IRCClient *)client\n{\n\tfor (IRCChannel *channel in client.channelList) {\n\t\tif (channel.isActive == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif ([channel.name hasPrefix:@\"~#\"]) { // Don't leave internal channels\n\t\t\tcontinue;\n\t\t}\n\n\t\t[channel deactivate];\n\t}\n\n\t[mainWindow() reloadTreeGroup:client];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Plugins/ZNC Additions/Resources/Language Files/en.lproj/BasicLanguage.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2011 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"xex-nl\" = \"This command is not available because you aren't connected to ZNC\";\n\"0fr-kb\" = \"The \\002detach\\002 command has been sent for the channel \\002%@\\002. Automatic join on connect for this channel has been disabled as well. Use the command \\002attach\\002 at any time to be returned to this channel and have automatic join turned back on.\";\n\n\"moh-hg\" = \"No information is available\";\n\"wco-zv\" = \"An error occurred while converting certificate information to a friendlier format\";\n"
  },
  {
    "path": "Sources/Plugins/ZNC Additions/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>${EXECUTABLE_NAME}</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>${PRODUCT_NAME}</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.1</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2011 - 2018 Codeux Software, LLC. All rights reserved.</string>\n\t<key>MinimumTextualVersion</key>\n\t<string>7.2.4</string>\n\t<key>NSPrincipalClass</key>\n\t<string>TPI_ZNCAdditions</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/Plugins/ZNC Additions/ZNC Additions Extension.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C36AAC820F27AB4007CA939 /* BasicLanguage.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C36AAC620F27AB4007CA939 /* BasicLanguage.strings */; };\n\t\t4C46A08020EC6A8200094EA4 /* TPI_ZNCAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A07F20EC6A8200094EA4 /* TPI_ZNCAdditions.m */; };\n\t\t4C661D491C2428DC001C2352 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C661D481C2428DC001C2352 /* Security.framework */; };\n\t\t4CF7B6C81C02836A00C986AA /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF7B6C71C02836A00C986AA /* SecurityInterface.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C1D102820EBF29F00E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D102920EBF29F00E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D102D20EBF29F00E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D103B20EBF29F00E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D103C20EBF29F00E72D80 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D103D20EBF29F00E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D103F20EBF29F00E72D80 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D104220EBF29F00E72D80 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D105020EBF29F00E72D80 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4C1D105120EBF29F00E72D80 /* Textual Extensions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Textual Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C1D105520EBF29F00E72D80 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4C36AAC720F27AB4007CA939 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/BasicLanguage.strings; sourceTree = \"<group>\"; };\n\t\t4C46A07A20EC6A5000094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A07E20EC6A8200094EA4 /* TPI_ZNCAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPI_ZNCAdditions.h; sourceTree = \"<group>\"; };\n\t\t4C46A07F20EC6A8200094EA4 /* TPI_ZNCAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPI_ZNCAdditions.m; sourceTree = \"<group>\"; };\n\t\t4C661D481C2428DC001C2352 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };\n\t\t4CF7B6C71C02836A00C986AA /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; };\n\t\t8D576316048677EA00EA77CD /* ZNC Additions.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"ZNC Additions.bundle\"; sourceTree = BUILT_PRODUCTS_DIR; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t8D576313048677EA00EA77CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C661D491C2428DC001C2352 /* Security.framework in Frameworks */,\n\t\t\t\t4CF7B6C81C02836A00C986AA /* SecurityInterface.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t089C166AFE841209C02AAC07 /* BragSpam */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A07D20EC6A8200094EA4 /* Classes */,\n\t\t\t\t089C167CFE841241C02AAC07 /* Resources */,\n\t\t\t\t089C1671FE841209C02AAC07 /* Frameworks */,\n\t\t\t\t19C28FB6FE9D52B211CA2CBB /* Products */,\n\t\t\t);\n\t\t\tname = BragSpam;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C1671FE841209C02AAC07 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C661D481C2428DC001C2352 /* Security.framework */,\n\t\t\t\t4CF7B6C71C02836A00C986AA /* SecurityInterface.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t089C167CFE841241C02AAC07 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C69188516E3275D00BDE3A8 /* Configurations */,\n\t\t\t\t4C46A07720EC6A5000094EA4 /* Language Files */,\n\t\t\t\t4C46A07920EC6A5000094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t19C28FB6FE9D52B211CA2CBB /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t8D576316048677EA00EA77CD /* ZNC Additions.bundle */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D102420EBF29F00E72D80 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D103820EBF29F00E72D80 /* Common */,\n\t\t\t\t4C1D104D20EBF29F00E72D80 /* Debug */,\n\t\t\t\t4C1D102520EBF29F00E72D80 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D102520EBF29F00E72D80 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D102D20EBF29F00E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D102920EBF29F00E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D102820EBF29F00E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D103820EBF29F00E72D80 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D104220EBF29F00E72D80 /* Foundation Debug.xcconfig */,\n\t\t\t\t4C1D103F20EBF29F00E72D80 /* Foundation.xcconfig */,\n\t\t\t\t4C1D103C20EBF29F00E72D80 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4C1D103D20EBF29F00E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D103B20EBF29F00E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1D104D20EBF29F00E72D80 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D105520EBF29F00E72D80 /* Enabled Features.xcconfig */,\n\t\t\t\t4C1D105120EBF29F00E72D80 /* Textual Extensions.xcconfig */,\n\t\t\t\t4C1D105020EBF29F00E72D80 /* Textual.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A07720EC6A5000094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAC620F27AB4007CA939 /* BasicLanguage.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A07920EC6A5000094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A07A20EC6A5000094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A07D20EC6A8200094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A07E20EC6A8200094EA4 /* TPI_ZNCAdditions.h */,\n\t\t\t\t4C46A07F20EC6A8200094EA4 /* TPI_ZNCAdditions.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C69188516E3275D00BDE3A8 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1D102420EBF29F00E72D80 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t8D57630D048677EA00EA77CD /* ZNC Additions Extension */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"ZNC Additions Extension\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t8D57630F048677EA00EA77CD /* Resources */,\n\t\t\t\t8D576313048677EA00EA77CD /* Frameworks */,\n\t\t\t\t8D576311048677EA00EA77CD /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"ZNC Additions Extension\";\n\t\t\tproductInstallPath = \"$(HOME)/Library/Bundles\";\n\t\t\tproductName = BragSpam;\n\t\t\tproductReference = 8D576316048677EA00EA77CD /* ZNC Additions.bundle */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t089C1669FE841209C02AAC07 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t8D57630D048677EA00EA77CD = {\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"ZNC Additions Extension\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 1;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 089C166AFE841209C02AAC07 /* BragSpam */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t8D57630D048677EA00EA77CD /* ZNC Additions Extension */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t8D57630F048677EA00EA77CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C36AAC820F27AB4007CA939 /* BasicLanguage.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t8D576311048677EA00EA77CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A08020EC6A8200094EA4 /* TPI_ZNCAdditions.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C36AAC620F27AB4007CA939 /* BasicLanguage.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C36AAC720F27AB4007CA939 /* en */,\n\t\t\t);\n\t\t\tname = BasicLanguage.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t1DEB911B08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ZNCAdditions\";\n\t\t\t\tPRODUCT_NAME = \"ZNC Additions\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB911C08733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ZNCAdditions\";\n\t\t\t\tPRODUCT_NAME = \"ZNC Additions\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t1DEB911F08733D790010E9CD /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D105120EBF29F00E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t1DEB912008733D790010E9CD /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4C1D102920EBF29F00E72D80 /* Textual Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C95802A1FA4204000F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n\t\t4C95802B1FA4204000F18BC8 /* Release (App Store) */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.textual-ZNCAdditions\";\n\t\t\t\tPRODUCT_NAME = \"ZNC Additions\";\n\t\t\t};\n\t\t\tname = \"Release (App Store)\";\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget \"ZNC Additions Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911B08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB911C08733D790010E9CD /* Release */,\n\t\t\t\t4C95802B1FA4204000F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t1DEB911E08733D790010E9CD /* Build configuration list for PBXProject \"ZNC Additions Extension\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t1DEB911F08733D790010E9CD /* Debug */,\n\t\t\t\t1DEB912008733D790010E9CD /* Release */,\n\t\t\t\t4C95802A1FA4204000F18BC8 /* Release (App Store) */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 089C1669FE841209C02AAC07 /* Project object */;\n}\n"
  },
  {
    "path": "Sources/Shared/Headers/External Libraries/GCDAsyncSocket.h",
    "content": "//  \n//  GCDAsyncSocket.h\n//  \n//  This class is in the public domain.\n//  Originally created by Robbie Hanson in Q3 2010.\n//  Updated and maintained by Deusty LLC and the Apple development community.\n//  \n//  https://github.com/robbiehanson/CocoaAsyncSocket\n//\n\n#import <Foundation/Foundation.h>\n#import <Security/Security.h>\n#import <Security/SecureTransport.h>\n#import <dispatch/dispatch.h>\n#import <Availability.h>\n\n#include <sys/socket.h> // AF_INET, AF_INET6\n\n@class GCDAsyncReadPacket;\n@class GCDAsyncWritePacket;\n@class GCDAsyncSocketPreBuffer;\n@protocol GCDAsyncSocketDelegate;\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSString *const GCDAsyncSocketException;\nextern NSString *const GCDAsyncSocketErrorDomain;\n\nextern NSString *const GCDAsyncSocketQueueName;\nextern NSString *const GCDAsyncSocketThreadName;\n\nextern NSString *const GCDAsyncSocketManuallyEvaluateTrust;\n#if TARGET_OS_IPHONE\nextern NSString *const GCDAsyncSocketUseCFStreamForTLS;\n#endif\n#define GCDAsyncSocketSSLPeerName     (NSString *)kCFStreamSSLPeerName\n#define GCDAsyncSocketSSLCertificates (NSString *)kCFStreamSSLCertificates\n#define GCDAsyncSocketSSLIsServer     (NSString *)kCFStreamSSLIsServer\nextern NSString *const GCDAsyncSocketSSLPeerID;\nextern NSString *const GCDAsyncSocketSSLProtocolVersionMin;\nextern NSString *const GCDAsyncSocketSSLProtocolVersionMax;\nextern NSString *const GCDAsyncSocketSSLSessionOptionFalseStart;\nextern NSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord;\nextern NSString *const GCDAsyncSocketSSLCipherSuites;\n#if !TARGET_OS_IPHONE\nextern NSString *const GCDAsyncSocketSSLDiffieHellmanParameters;\n#endif\n\n#define GCDAsyncSocketLoggingContext 65535\n\n\ntypedef NS_ENUM(NSInteger, GCDAsyncSocketError) {\n\tGCDAsyncSocketNoError = 0,           // Never used\n\tGCDAsyncSocketBadConfigError,        // Invalid configuration\n\tGCDAsyncSocketBadParamError,         // Invalid parameter was passed\n\tGCDAsyncSocketConnectTimeoutError,   // A connect operation timed out\n\tGCDAsyncSocketReadTimeoutError,      // A read operation timed out\n\tGCDAsyncSocketWriteTimeoutError,     // A write operation timed out\n\tGCDAsyncSocketReadMaxedOutError,     // Reached set maxLength without completing\n\tGCDAsyncSocketClosedError,           // The remote peer closed the connection\n\tGCDAsyncSocketOtherError,            // Description provided in userInfo\n};\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n\n@interface GCDAsyncSocket : NSObject\n\n/**\n * GCDAsyncSocket uses the standard delegate paradigm,\n * but executes all delegate callbacks on a given delegate dispatch queue.\n * This allows for maximum concurrency, while at the same time providing easy thread safety.\n * \n * You MUST set a delegate AND delegate dispatch queue before attempting to\n * use the socket, or you will get an error.\n * \n * The socket queue is optional.\n * If you pass NULL, GCDAsyncSocket will automatically create it's own socket queue.\n * If you choose to provide a socket queue, the socket queue must not be a concurrent queue.\n * If you choose to provide a socket queue, and the socket queue has a configured target queue,\n * then please see the discussion for the method markSocketQueueTargetQueue.\n * \n * The delegate queue and socket queue can optionally be the same.\n**/\n- (instancetype)init;\n- (instancetype)initWithSocketQueue:(nullable dispatch_queue_t)sq;\n- (instancetype)initWithDelegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq;\n- (instancetype)initWithDelegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq;\n\n/**\n * Create GCDAsyncSocket from already connect BSD socket file descriptor\n**/\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD socketQueue:(nullable dispatch_queue_t)sq error:(NSError**)error;\n\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq error:(NSError**)error;\n\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError **)error;\n\n#pragma mark Configuration\n\n@property (atomic, weak, readwrite, nullable) id<GCDAsyncSocketDelegate> delegate;\n#if OS_OBJECT_USE_OBJC\n@property (atomic, strong, readwrite, nullable) dispatch_queue_t delegateQueue;\n#else\n@property (atomic, assign, readwrite, nullable) dispatch_queue_t delegateQueue;\n#endif\n\n- (void)getDelegate:(id<GCDAsyncSocketDelegate> __nullable * __nullable)delegatePtr delegateQueue:(dispatch_queue_t __nullable * __nullable)delegateQueuePtr;\n- (void)setDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;\n\n/**\n * If you are setting the delegate to nil within the delegate's dealloc method,\n * you may need to use the synchronous versions below.\n**/\n- (void)synchronouslySetDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate;\n- (void)synchronouslySetDelegateQueue:(nullable dispatch_queue_t)delegateQueue;\n- (void)synchronouslySetDelegate:(nullable id<GCDAsyncSocketDelegate>)delegate delegateQueue:(nullable dispatch_queue_t)delegateQueue;\n\n/**\n * By default, both IPv4 and IPv6 are enabled.\n * \n * For accepting incoming connections, this means GCDAsyncSocket automatically supports both protocols,\n * and can simulataneously accept incoming connections on either protocol.\n * \n * For outgoing connections, this means GCDAsyncSocket can connect to remote hosts running either protocol.\n * If a DNS lookup returns only IPv4 results, GCDAsyncSocket will automatically use IPv4.\n * If a DNS lookup returns only IPv6 results, GCDAsyncSocket will automatically use IPv6.\n * If a DNS lookup returns both IPv4 and IPv6 results, the preferred protocol will be chosen.\n * By default, the preferred protocol is IPv4, but may be configured as desired.\n**/\n\n@property (atomic, assign, readwrite, getter=isIPv4Enabled) BOOL IPv4Enabled;\n@property (atomic, assign, readwrite, getter=isIPv6Enabled) BOOL IPv6Enabled;\n\n@property (atomic, assign, readwrite, getter=isIPv4PreferredOverIPv6) BOOL IPv4PreferredOverIPv6;\n\n/** \n * When connecting to both IPv4 and IPv6 using Happy Eyeballs (RFC 6555) https://tools.ietf.org/html/rfc6555\n * this is the delay between connecting to the preferred protocol and the fallback protocol.\n *\n * Defaults to 300ms.\n**/\n@property (atomic, assign, readwrite) NSTimeInterval alternateAddressDelay;\n\n/**\n * User data allows you to associate arbitrary information with the socket.\n * This data is not used internally by socket in any way.\n**/\n@property (atomic, strong, readwrite, nullable) id userData;\n\n/**\n * Whether the flag DISPATCH_TIMER_STRICT is set on internal timers,\n * thus negating the benefits of the \"App Nap\" feature of macOS.\n **/\n@property (atomic, assign, readwrite) BOOL useStrictTimers;\n\n#pragma mark Accepting\n\n/**\n * Tells the socket to begin listening and accepting connections on the given port.\n * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it,\n * and the socket:didAcceptNewSocket: delegate method will be invoked.\n * \n * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)\n**/\n- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr;\n\n/**\n * This method is the same as acceptOnPort:error: with the\n * additional option of specifying which interface to listen on.\n * \n * For example, you could specify that the socket should only accept connections over ethernet,\n * and not other interfaces such as wifi.\n * \n * The interface may be specified by name (e.g. \"en1\" or \"lo0\") or by IP address (e.g. \"192.168.4.34\").\n * You may also use the special strings \"localhost\" or \"loopback\" to specify that\n * the socket only accept connections from the local machine.\n * \n * You can see the list of interfaces via the command line utility \"ifconfig\",\n * or programmatically via the getifaddrs() function.\n * \n * To accept connections on any interface pass nil, or simply use the acceptOnPort:error: method.\n**/\n- (BOOL)acceptOnInterface:(nullable NSString *)interface port:(uint16_t)port error:(NSError **)errPtr;\n\n/**\n * Tells the socket to begin listening and accepting connections on the unix domain at the given url.\n * When a connection is accepted, a new instance of GCDAsyncSocket will be spawned to handle it,\n * and the socket:didAcceptNewSocket: delegate method will be invoked.\n *\n * The socket will listen on all available interfaces (e.g. wifi, ethernet, etc)\n **/\n- (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr;\n\n#pragma mark Connecting\n\n/**\n * Connects to the given host and port.\n * \n * This method invokes connectToHost:onPort:viaInterface:withTimeout:error:\n * and uses the default interface, and no timeout.\n**/\n- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port error:(NSError **)errPtr;\n\n/**\n * Connects to the given host and port with an optional timeout.\n * \n * This method invokes connectToHost:onPort:viaInterface:withTimeout:error: and uses the default interface.\n**/\n- (BOOL)connectToHost:(NSString *)host\n               onPort:(uint16_t)port\n          withTimeout:(NSTimeInterval)timeout\n                error:(NSError **)errPtr;\n\n/**\n * Connects to the given host & port, via the optional interface, with an optional timeout.\n * \n * The host may be a domain name (e.g. \"deusty.com\") or an IP address string (e.g. \"192.168.0.2\").\n * The host may also be the special strings \"localhost\" or \"loopback\" to specify connecting\n * to a service on the local machine.\n * \n * The interface may be a name (e.g. \"en1\" or \"lo0\") or the corresponding IP address (e.g. \"192.168.4.35\").\n * The interface may also be used to specify the local port (see below).\n * \n * To not time out use a negative time interval.\n * \n * This method will return NO if an error is detected, and set the error pointer (if one was given).\n * Possible errors would be a nil host, invalid interface, or socket is already connected.\n * \n * If no errors are detected, this method will start a background connect operation and immediately return YES.\n * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable.\n * \n * Since this class supports queued reads and writes, you can immediately start reading and/or writing.\n * All read/write operations will be queued, and upon socket connection,\n * the operations will be dequeued and processed in order.\n * \n * The interface may optionally contain a port number at the end of the string, separated by a colon.\n * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)\n * To specify both interface and local port: \"en1:8082\" or \"192.168.4.35:2424\".\n * To specify only local port: \":8082\".\n * Please note this is an advanced feature, and is somewhat hidden on purpose.\n * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.\n * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.\n * Local ports do NOT need to match remote ports. In fact, they almost never do.\n * This feature is here for networking professionals using very advanced techniques.\n**/\n- (BOOL)connectToHost:(NSString *)host\n               onPort:(uint16_t)port\n         viaInterface:(nullable NSString *)interface\n          withTimeout:(NSTimeInterval)timeout\n                error:(NSError **)errPtr;\n\n/**\n * Connects to the given address, specified as a sockaddr structure wrapped in a NSData object.\n * For example, a NSData object returned from NSNetService's addresses method.\n * \n * If you have an existing struct sockaddr you can convert it to a NSData object like so:\n * struct sockaddr sa  -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];\n * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];\n * \n * This method invokes connectToAdd\n**/\n- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr;\n\n/**\n * This method is the same as connectToAddress:error: with an additional timeout option.\n * To not time out use a negative time interval, or simply use the connectToAddress:error: method.\n**/\n- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;\n\n/**\n * Connects to the given address, using the specified interface and timeout.\n * \n * The address is specified as a sockaddr structure wrapped in a NSData object.\n * For example, a NSData object returned from NSNetService's addresses method.\n * \n * If you have an existing struct sockaddr you can convert it to a NSData object like so:\n * struct sockaddr sa  -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len];\n * struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len];\n * \n * The interface may be a name (e.g. \"en1\" or \"lo0\") or the corresponding IP address (e.g. \"192.168.4.35\").\n * The interface may also be used to specify the local port (see below).\n * \n * The timeout is optional. To not time out use a negative time interval.\n * \n * This method will return NO if an error is detected, and set the error pointer (if one was given).\n * Possible errors would be a nil host, invalid interface, or socket is already connected.\n * \n * If no errors are detected, this method will start a background connect operation and immediately return YES.\n * The delegate callbacks are used to notify you when the socket connects, or if the host was unreachable.\n * \n * Since this class supports queued reads and writes, you can immediately start reading and/or writing.\n * All read/write operations will be queued, and upon socket connection,\n * the operations will be dequeued and processed in order.\n * \n * The interface may optionally contain a port number at the end of the string, separated by a colon.\n * This allows you to specify the local port that should be used for the outgoing connection. (read paragraph to end)\n * To specify both interface and local port: \"en1:8082\" or \"192.168.4.35:2424\".\n * To specify only local port: \":8082\".\n * Please note this is an advanced feature, and is somewhat hidden on purpose.\n * You should understand that 99.999% of the time you should NOT specify the local port for an outgoing connection.\n * If you think you need to, there is a very good chance you have a fundamental misunderstanding somewhere.\n * Local ports do NOT need to match remote ports. In fact, they almost never do.\n * This feature is here for networking professionals using very advanced techniques.\n**/\n- (BOOL)connectToAddress:(NSData *)remoteAddr\n            viaInterface:(nullable NSString *)interface\n             withTimeout:(NSTimeInterval)timeout\n                   error:(NSError **)errPtr;\n/**\n * Connects to the unix domain socket at the given url, using the specified timeout.\n */\n- (BOOL)connectToUrl:(NSURL *)url withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;\n\n#pragma mark Disconnecting\n\n/**\n * Disconnects immediately (synchronously). Any pending reads or writes are dropped.\n * \n * If the socket is not already disconnected, an invocation to the socketDidDisconnect:withError: delegate method\n * will be queued onto the delegateQueue asynchronously (behind any previously queued delegate methods).\n * In other words, the disconnected delegate method will be invoked sometime shortly after this method returns.\n * \n * Please note the recommended way of releasing a GCDAsyncSocket instance (e.g. in a dealloc method)\n * [asyncSocket setDelegate:nil];\n * [asyncSocket disconnect];\n * [asyncSocket release];\n * \n * If you plan on disconnecting the socket, and then immediately asking it to connect again,\n * you'll likely want to do so like this:\n * [asyncSocket setDelegate:nil];\n * [asyncSocket disconnect];\n * [asyncSocket setDelegate:self];\n * [asyncSocket connect...];\n**/\n- (void)disconnect;\n\n/**\n * Disconnects after all pending reads have completed.\n * After calling this, the read and write methods will do nothing.\n * The socket will disconnect even if there are still pending writes.\n**/\n- (void)disconnectAfterReading;\n\n/**\n * Disconnects after all pending writes have completed.\n * After calling this, the read and write methods will do nothing.\n * The socket will disconnect even if there are still pending reads.\n**/\n- (void)disconnectAfterWriting;\n\n/**\n * Disconnects after all pending reads and writes have completed.\n * After calling this, the read and write methods will do nothing.\n**/\n- (void)disconnectAfterReadingAndWriting;\n\n#pragma mark Diagnostics\n\n/**\n * Returns whether the socket is disconnected or connected.\n * \n * A disconnected socket may be recycled.\n * That is, it can be used again for connecting or listening.\n * \n * If a socket is in the process of connecting, it may be neither disconnected nor connected.\n**/\n@property (atomic, readonly) BOOL isDisconnected;\n@property (atomic, readonly) BOOL isConnected;\n\n/**\n * Returns the local or remote host and port to which this socket is connected, or nil and 0 if not connected.\n * The host will be an IP address.\n**/\n@property (atomic, readonly, nullable) NSString *connectedHost;\n@property (atomic, readonly) uint16_t  connectedPort;\n@property (atomic, readonly, nullable) NSURL    *connectedUrl;\n\n@property (atomic, readonly, nullable) NSString *localHost;\n@property (atomic, readonly) uint16_t  localPort;\n\n/**\n * Returns the local or remote address to which this socket is connected,\n * specified as a sockaddr structure wrapped in a NSData object.\n * \n * @seealso connectedHost\n * @seealso connectedPort\n * @seealso localHost\n * @seealso localPort\n**/\n@property (atomic, readonly, nullable) NSData *connectedAddress;\n@property (atomic, readonly, nullable) NSData *localAddress;\n\n/**\n * Returns whether the socket is IPv4 or IPv6.\n * An accepting socket may be both.\n**/\n@property (atomic, readonly) BOOL isIPv4;\n@property (atomic, readonly) BOOL isIPv6;\n\n/**\n * Returns whether or not the socket has been secured via SSL/TLS.\n * \n * See also the startTLS method.\n**/\n@property (atomic, readonly) BOOL isSecure;\n\n#pragma mark Reading\n\n// The readData and writeData methods won't block (they are asynchronous).\n// \n// When a read is complete the socket:didReadData:withTag: delegate method is dispatched on the delegateQueue.\n// When a write is complete the socket:didWriteDataWithTag: delegate method is dispatched on the delegateQueue.\n// \n// You may optionally set a timeout for any read/write operation. (To not timeout, use a negative time interval.)\n// If a read/write opertion times out, the corresponding \"socket:shouldTimeout...\" delegate method\n// is called to optionally allow you to extend the timeout.\n// Upon a timeout, the \"socket:didDisconnectWithError:\" method is called\n// \n// The tag is for your convenience.\n// You can use it as an array index, step number, state id, pointer, etc.\n\n/**\n * Reads the first available bytes that become available on the socket.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n**/\n- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;\n\n/**\n * Reads the first available bytes that become available on the socket.\n * The bytes will be appended to the given byte buffer starting at the given offset.\n * The given buffer will automatically be increased in size if needed.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * If the buffer if nil, the socket will create a buffer for you.\n * \n * If the bufferOffset is greater than the length of the given buffer,\n * the method will do nothing, and the delegate will not be called.\n * \n * If you pass a buffer, you must not alter it in any way while the socket is using it.\n * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.\n * That is, it will reference the bytes that were appended to the given buffer via\n * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].\n**/\n- (void)readDataWithTimeout:(NSTimeInterval)timeout\n\t\t\t\t\t buffer:(nullable NSMutableData *)buffer\n\t\t\t   bufferOffset:(NSUInteger)offset\n\t\t\t\t\t\ttag:(long)tag;\n\n/**\n * Reads the first available bytes that become available on the socket.\n * The bytes will be appended to the given byte buffer starting at the given offset.\n * The given buffer will automatically be increased in size if needed.\n * A maximum of length bytes will be read.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * If the buffer if nil, a buffer will automatically be created for you.\n * If maxLength is zero, no length restriction is enforced.\n * \n * If the bufferOffset is greater than the length of the given buffer,\n * the method will do nothing, and the delegate will not be called.\n * \n * If you pass a buffer, you must not alter it in any way while the socket is using it.\n * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.\n * That is, it will reference the bytes that were appended to the given buffer  via\n * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].\n**/\n- (void)readDataWithTimeout:(NSTimeInterval)timeout\n                     buffer:(nullable NSMutableData *)buffer\n               bufferOffset:(NSUInteger)offset\n                  maxLength:(NSUInteger)length\n                        tag:(long)tag;\n\n/**\n * Reads the given number of bytes.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * \n * If the length is 0, this method does nothing and the delegate is not called.\n**/\n- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag;\n\n/**\n * Reads the given number of bytes.\n * The bytes will be appended to the given byte buffer starting at the given offset.\n * The given buffer will automatically be increased in size if needed.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * If the buffer if nil, a buffer will automatically be created for you.\n * \n * If the length is 0, this method does nothing and the delegate is not called.\n * If the bufferOffset is greater than the length of the given buffer,\n * the method will do nothing, and the delegate will not be called.\n * \n * If you pass a buffer, you must not alter it in any way while AsyncSocket is using it.\n * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.\n * That is, it will reference the bytes that were appended to the given buffer via\n * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].\n**/\n- (void)readDataToLength:(NSUInteger)length\n             withTimeout:(NSTimeInterval)timeout\n                  buffer:(nullable NSMutableData *)buffer\n            bufferOffset:(NSUInteger)offset\n                     tag:(long)tag;\n\n/**\n * Reads bytes until (and including) the passed \"data\" parameter, which acts as a separator.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * \n * If you pass nil or zero-length data as the \"data\" parameter,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * \n * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the \"data\" parameter.\n * If you're developing your own custom protocol, be sure your separator can not occur naturally as\n * part of the data between separators.\n * For example, imagine you want to send several small documents over a socket.\n * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.\n * In this particular example, it would be better to use a protocol similar to HTTP with\n * a header that includes the length of the document.\n * Also be careful that your separator cannot occur naturally as part of the encoding for a character.\n * \n * The given data (separator) parameter should be immutable.\n * For performance reasons, the socket will retain it, not copy it.\n * So if it is immutable, don't modify it while the socket is using it.\n**/\n- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;\n\n/**\n * Reads bytes until (and including) the passed \"data\" parameter, which acts as a separator.\n * The bytes will be appended to the given byte buffer starting at the given offset.\n * The given buffer will automatically be increased in size if needed.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * If the buffer if nil, a buffer will automatically be created for you.\n * \n * If the bufferOffset is greater than the length of the given buffer,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * \n * If you pass a buffer, you must not alter it in any way while the socket is using it.\n * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.\n * That is, it will reference the bytes that were appended to the given buffer via\n * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].\n * \n * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the \"data\" parameter.\n * If you're developing your own custom protocol, be sure your separator can not occur naturally as\n * part of the data between separators.\n * For example, imagine you want to send several small documents over a socket.\n * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.\n * In this particular example, it would be better to use a protocol similar to HTTP with\n * a header that includes the length of the document.\n * Also be careful that your separator cannot occur naturally as part of the encoding for a character.\n * \n * The given data (separator) parameter should be immutable.\n * For performance reasons, the socket will retain it, not copy it.\n * So if it is immutable, don't modify it while the socket is using it.\n**/\n- (void)readDataToData:(NSData *)data\n           withTimeout:(NSTimeInterval)timeout\n                buffer:(nullable NSMutableData *)buffer\n          bufferOffset:(NSUInteger)offset\n                   tag:(long)tag;\n\n/**\n * Reads bytes until (and including) the passed \"data\" parameter, which acts as a separator.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * \n * If maxLength is zero, no length restriction is enforced.\n * Otherwise if maxLength bytes are read without completing the read,\n * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError.\n * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.\n * \n * If you pass nil or zero-length data as the \"data\" parameter,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * If you pass a maxLength parameter that is less than the length of the data parameter,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * \n * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the \"data\" parameter.\n * If you're developing your own custom protocol, be sure your separator can not occur naturally as\n * part of the data between separators.\n * For example, imagine you want to send several small documents over a socket.\n * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.\n * In this particular example, it would be better to use a protocol similar to HTTP with\n * a header that includes the length of the document.\n * Also be careful that your separator cannot occur naturally as part of the encoding for a character.\n * \n * The given data (separator) parameter should be immutable.\n * For performance reasons, the socket will retain it, not copy it.\n * So if it is immutable, don't modify it while the socket is using it.\n**/\n- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag;\n\n/**\n * Reads bytes until (and including) the passed \"data\" parameter, which acts as a separator.\n * The bytes will be appended to the given byte buffer starting at the given offset.\n * The given buffer will automatically be increased in size if needed.\n * \n * If the timeout value is negative, the read operation will not use a timeout.\n * If the buffer if nil, a buffer will automatically be created for you.\n * \n * If maxLength is zero, no length restriction is enforced.\n * Otherwise if maxLength bytes are read without completing the read,\n * it is treated similarly to a timeout - the socket is closed with a GCDAsyncSocketReadMaxedOutError.\n * The read will complete successfully if exactly maxLength bytes are read and the given data is found at the end.\n * \n * If you pass a maxLength parameter that is less than the length of the data (separator) parameter,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * If the bufferOffset is greater than the length of the given buffer,\n * the method will do nothing (except maybe print a warning), and the delegate will not be called.\n * \n * If you pass a buffer, you must not alter it in any way while the socket is using it.\n * After completion, the data returned in socket:didReadData:withTag: will be a subset of the given buffer.\n * That is, it will reference the bytes that were appended to the given buffer via\n * the method [NSData dataWithBytesNoCopy:length:freeWhenDone:NO].\n * \n * To read a line from the socket, use the line separator (e.g. CRLF for HTTP, see below) as the \"data\" parameter.\n * If you're developing your own custom protocol, be sure your separator can not occur naturally as\n * part of the data between separators.\n * For example, imagine you want to send several small documents over a socket.\n * Using CRLF as a separator is likely unwise, as a CRLF could easily exist within the documents.\n * In this particular example, it would be better to use a protocol similar to HTTP with\n * a header that includes the length of the document.\n * Also be careful that your separator cannot occur naturally as part of the encoding for a character.\n * \n * The given data (separator) parameter should be immutable.\n * For performance reasons, the socket will retain it, not copy it.\n * So if it is immutable, don't modify it while the socket is using it.\n**/\n- (void)readDataToData:(NSData *)data\n           withTimeout:(NSTimeInterval)timeout\n                buffer:(nullable NSMutableData *)buffer\n          bufferOffset:(NSUInteger)offset\n             maxLength:(NSUInteger)length\n                   tag:(long)tag;\n\n/**\n * Returns progress of the current read, from 0.0 to 1.0, or NaN if no current read (use isnan() to check).\n * The parameters \"tag\", \"done\" and \"total\" will be filled in if they aren't NULL.\n**/\n- (float)progressOfReadReturningTag:(nullable long *)tagPtr bytesDone:(nullable NSUInteger *)donePtr total:(nullable NSUInteger *)totalPtr;\n\n#pragma mark Writing\n\n/**\n * Writes data to the socket, and calls the delegate when finished.\n * \n * If you pass in nil or zero-length data, this method does nothing and the delegate will not be called.\n * If the timeout value is negative, the write operation will not use a timeout.\n * \n * Thread-Safety Note:\n * If the given data parameter is mutable (NSMutableData) then you MUST NOT alter the data while\n * the socket is writing it. In other words, it's not safe to alter the data until after the delegate method\n * socket:didWriteDataWithTag: is invoked signifying that this particular write operation has completed.\n * This is due to the fact that GCDAsyncSocket does NOT copy the data. It simply retains it.\n * This is for performance reasons. Often times, if NSMutableData is passed, it is because\n * a request/response was built up in memory. Copying this data adds an unwanted/unneeded overhead.\n * If you need to write data from an immutable buffer, and you need to alter the buffer before the socket\n * completes writing the bytes (which is NOT immediately after this method returns, but rather at a later time\n * when the delegate method notifies you), then you should first copy the bytes, and pass the copy to this method.\n**/\n- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;\n\n/**\n * Returns progress of the current write, from 0.0 to 1.0, or NaN if no current write (use isnan() to check).\n * The parameters \"tag\", \"done\" and \"total\" will be filled in if they aren't NULL.\n**/\n- (float)progressOfWriteReturningTag:(nullable long *)tagPtr bytesDone:(nullable NSUInteger *)donePtr total:(nullable NSUInteger *)totalPtr;\n\n#pragma mark Security\n\n/**\n * Secures the connection using SSL/TLS.\n * \n * This method may be called at any time, and the TLS handshake will occur after all pending reads and writes\n * are finished. This allows one the option of sending a protocol dependent StartTLS message, and queuing\n * the upgrade to TLS at the same time, without having to wait for the write to finish.\n * Any reads or writes scheduled after this method is called will occur over the secured connection.\n *\n * ==== The available TOP-LEVEL KEYS are:\n * \n * - GCDAsyncSocketManuallyEvaluateTrust\n *     The value must be of type NSNumber, encapsulating a BOOL value.\n *     If you set this to YES, then the underlying SecureTransport system will not evaluate the SecTrustRef of the peer.\n *     Instead it will pause at the moment evaulation would typically occur,\n *     and allow us to handle the security evaluation however we see fit.\n *     So GCDAsyncSocket will invoke the delegate method socket:shouldTrustPeer: passing the SecTrustRef.\n *\n *     Note that if you set this option, then all other configuration keys are ignored.\n *     Evaluation will be completely up to you during the socket:didReceiveTrust:completionHandler: delegate method.\n *\n *     For more information on trust evaluation see:\n *     Apple's Technical Note TN2232 - HTTPS Server Trust Evaluation\n *     https://developer.apple.com/library/ios/technotes/tn2232/_index.html\n *     \n *     If unspecified, the default value is NO.\n *\n * - GCDAsyncSocketUseCFStreamForTLS (iOS only)\n *     The value must be of type NSNumber, encapsulating a BOOL value.\n *     By default GCDAsyncSocket will use the SecureTransport layer to perform encryption.\n *     This gives us more control over the security protocol (many more configuration options),\n *     plus it allows us to optimize things like sys calls and buffer allocation.\n *     \n *     However, if you absolutely must, you can instruct GCDAsyncSocket to use the old-fashioned encryption\n *     technique by going through the CFStream instead. So instead of using SecureTransport, GCDAsyncSocket\n *     will instead setup a CFRead/CFWriteStream. And then set the kCFStreamPropertySSLSettings property\n *     (via CFReadStreamSetProperty / CFWriteStreamSetProperty) and will pass the given options to this method.\n *     \n *     Thus all the other keys in the given dictionary will be ignored by GCDAsyncSocket,\n *     and will passed directly CFReadStreamSetProperty / CFWriteStreamSetProperty.\n *     For more infomation on these keys, please see the documentation for kCFStreamPropertySSLSettings.\n *\n *     If unspecified, the default value is NO.\n *\n * ==== The available CONFIGURATION KEYS are:\n *\n * - kCFStreamSSLPeerName\n *     The value must be of type NSString.\n *     It should match the name in the X.509 certificate given by the remote party.\n *     See Apple's documentation for SSLSetPeerDomainName.\n *\n * - kCFStreamSSLCertificates\n *     The value must be of type NSArray.\n *     See Apple's documentation for SSLSetCertificate.\n *\n * - kCFStreamSSLIsServer\n *     The value must be of type NSNumber, encapsulationg a BOOL value.\n *     See Apple's documentation for SSLCreateContext for iOS.\n *     This is optional for iOS. If not supplied, a NO value is the default.\n *     This is not needed for Mac OS X, and the value is ignored.\n *\n * - GCDAsyncSocketSSLPeerID\n *     The value must be of type NSData.\n *     You must set this value if you want to use TLS session resumption.\n *     See Apple's documentation for SSLSetPeerID.\n *\n * - GCDAsyncSocketSSLProtocolVersionMin\n * - GCDAsyncSocketSSLProtocolVersionMax\n *     The value(s) must be of type NSNumber, encapsulting a SSLProtocol value.\n *     See Apple's documentation for SSLSetProtocolVersionMin & SSLSetProtocolVersionMax.\n *     See also the SSLProtocol typedef.\n * \n * - GCDAsyncSocketSSLSessionOptionFalseStart\n *     The value must be of type NSNumber, encapsulating a BOOL value.\n *     See Apple's documentation for kSSLSessionOptionFalseStart.\n * \n * - GCDAsyncSocketSSLSessionOptionSendOneByteRecord\n *     The value must be of type NSNumber, encapsulating a BOOL value.\n *     See Apple's documentation for kSSLSessionOptionSendOneByteRecord.\n * \n * - GCDAsyncSocketSSLCipherSuites\n *     The values must be of type NSArray.\n *     Each item within the array must be a NSNumber, encapsulating\n *     See Apple's documentation for SSLSetEnabledCiphers.\n *     See also the SSLCipherSuite typedef.\n *\n * - GCDAsyncSocketSSLDiffieHellmanParameters (Mac OS X only)\n *     The value must be of type NSData.\n *     See Apple's documentation for SSLSetDiffieHellmanParams.\n * \n * ==== The following UNAVAILABLE KEYS are: (with throw an exception)\n * \n * - kCFStreamSSLAllowsAnyRoot (UNAVAILABLE)\n *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).\n *     Corresponding deprecated method: SSLSetAllowsAnyRoot\n * \n * - kCFStreamSSLAllowsExpiredRoots (UNAVAILABLE)\n *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).\n *     Corresponding deprecated method: SSLSetAllowsExpiredRoots\n *\n * - kCFStreamSSLAllowsExpiredCertificates (UNAVAILABLE)\n *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).\n *     Corresponding deprecated method: SSLSetAllowsExpiredCerts\n *\n * - kCFStreamSSLValidatesCertificateChain (UNAVAILABLE)\n *     You MUST use manual trust evaluation instead (see GCDAsyncSocketManuallyEvaluateTrust).\n *     Corresponding deprecated method: SSLSetEnableCertVerify\n *\n * - kCFStreamSSLLevel (UNAVAILABLE)\n *     You MUST use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMin instead.\n *     Corresponding deprecated method: SSLSetProtocolVersionEnabled\n *\n * \n * Please refer to Apple's documentation for corresponding SSLFunctions.\n *\n * If you pass in nil or an empty dictionary, the default settings will be used.\n * \n * IMPORTANT SECURITY NOTE:\n * The default settings will check to make sure the remote party's certificate is signed by a\n * trusted 3rd party certificate agency (e.g. verisign) and that the certificate is not expired.\n * However it will not verify the name on the certificate unless you\n * give it a name to verify against via the kCFStreamSSLPeerName key.\n * The security implications of this are important to understand.\n * Imagine you are attempting to create a secure connection to MySecureServer.com,\n * but your socket gets directed to MaliciousServer.com because of a hacked DNS server.\n * If you simply use the default settings, and MaliciousServer.com has a valid certificate,\n * the default settings will not detect any problems since the certificate is valid.\n * To properly secure your connection in this particular scenario you\n * should set the kCFStreamSSLPeerName property to \"MySecureServer.com\".\n * \n * You can also perform additional validation in socketDidSecure.\n**/\n- (void)startTLS:(nullable NSDictionary <NSString*,NSObject*>*)tlsSettings;\n\n#pragma mark Advanced\n\n/**\n * Traditionally sockets are not closed until the conversation is over.\n * However, it is technically possible for the remote enpoint to close its write stream.\n * Our socket would then be notified that there is no more data to be read,\n * but our socket would still be writeable and the remote endpoint could continue to receive our data.\n * \n * The argument for this confusing functionality stems from the idea that a client could shut down its\n * write stream after sending a request to the server, thus notifying the server there are to be no further requests.\n * In practice, however, this technique did little to help server developers.\n * \n * To make matters worse, from a TCP perspective there is no way to tell the difference from a read stream close\n * and a full socket close. They both result in the TCP stack receiving a FIN packet. The only way to tell\n * is by continuing to write to the socket. If it was only a read stream close, then writes will continue to work.\n * Otherwise an error will be occur shortly (when the remote end sends us a RST packet).\n * \n * In addition to the technical challenges and confusion, many high level socket/stream API's provide\n * no support for dealing with the problem. If the read stream is closed, the API immediately declares the\n * socket to be closed, and shuts down the write stream as well. In fact, this is what Apple's CFStream API does.\n * It might sound like poor design at first, but in fact it simplifies development.\n * \n * The vast majority of the time if the read stream is closed it's because the remote endpoint closed its socket.\n * Thus it actually makes sense to close the socket at this point.\n * And in fact this is what most networking developers want and expect to happen.\n * However, if you are writing a server that interacts with a plethora of clients,\n * you might encounter a client that uses the discouraged technique of shutting down its write stream.\n * If this is the case, you can set this property to NO,\n * and make use of the socketDidCloseReadStream delegate method.\n * \n * The default value is YES.\n**/\n@property (atomic, assign, readwrite) BOOL autoDisconnectOnClosedReadStream;\n\n/**\n * GCDAsyncSocket maintains thread safety by using an internal serial dispatch_queue.\n * In most cases, the instance creates this queue itself.\n * However, to allow for maximum flexibility, the internal queue may be passed in the init method.\n * This allows for some advanced options such as controlling socket priority via target queues.\n * However, when one begins to use target queues like this, they open the door to some specific deadlock issues.\n * \n * For example, imagine there are 2 queues:\n * dispatch_queue_t socketQueue;\n * dispatch_queue_t socketTargetQueue;\n * \n * If you do this (pseudo-code):\n * socketQueue.targetQueue = socketTargetQueue;\n * \n * Then all socketQueue operations will actually get run on the given socketTargetQueue.\n * This is fine and works great in most situations.\n * But if you run code directly from within the socketTargetQueue that accesses the socket,\n * you could potentially get deadlock. Imagine the following code:\n * \n * - (BOOL)socketHasSomething\n * {\n *     __block BOOL result = NO;\n *     dispatch_block_t block = ^{\n *         result = [self someInternalMethodToBeRunOnlyOnSocketQueue];\n *     }\n *     if (is_executing_on_queue(socketQueue))\n *         block();\n *     else\n *         dispatch_sync(socketQueue, block);\n *     \n *     return result;\n * }\n * \n * What happens if you call this method from the socketTargetQueue? The result is deadlock.\n * This is because the GCD API offers no mechanism to discover a queue's targetQueue.\n * Thus we have no idea if our socketQueue is configured with a targetQueue.\n * If we had this information, we could easily avoid deadlock.\n * But, since these API's are missing or unfeasible, you'll have to explicitly set it.\n * \n * IF you pass a socketQueue via the init method,\n * AND you've configured the passed socketQueue with a targetQueue,\n * THEN you should pass the end queue in the target hierarchy.\n * \n * For example, consider the following queue hierarchy:\n * socketQueue -> ipQueue -> moduleQueue\n *\n * This example demonstrates priority shaping within some server.\n * All incoming client connections from the same IP address are executed on the same target queue.\n * And all connections for a particular module are executed on the same target queue.\n * Thus, the priority of all networking for the entire module can be changed on the fly.\n * Additionally, networking traffic from a single IP cannot monopolize the module.\n * \n * Here's how you would accomplish something like that:\n * - (dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock\n * {\n *     dispatch_queue_t socketQueue = dispatch_queue_create(\"\", NULL);\n *     dispatch_queue_t ipQueue = [self ipQueueForAddress:address];\n *     \n *     dispatch_set_target_queue(socketQueue, ipQueue);\n *     dispatch_set_target_queue(iqQueue, moduleQueue);\n *     \n *     return socketQueue;\n * }\n * - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket\n * {\n *     [clientConnections addObject:newSocket];\n *     [newSocket markSocketQueueTargetQueue:moduleQueue];\n * }\n * \n * Note: This workaround is ONLY needed if you intend to execute code directly on the ipQueue or moduleQueue.\n * This is often NOT the case, as such queues are used solely for execution shaping.\n**/\n- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreConfiguredTargetQueue;\n- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketQueuesPreviouslyConfiguredTargetQueue;\n\n/**\n * It's not thread-safe to access certain variables from outside the socket's internal queue.\n * \n * For example, the socket file descriptor.\n * File descriptors are simply integers which reference an index in the per-process file table.\n * However, when one requests a new file descriptor (by opening a file or socket),\n * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor.\n * So if we're not careful, the following could be possible:\n * \n * - Thread A invokes a method which returns the socket's file descriptor.\n * - The socket is closed via the socket's internal queue on thread B.\n * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD.\n * - Thread A is now accessing/altering the file instead of the socket.\n * \n * In addition to this, other variables are not actually objects,\n * and thus cannot be retained/released or even autoreleased.\n * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct.\n * \n * Although there are internal variables that make it difficult to maintain thread-safety,\n * it is important to provide access to these variables\n * to ensure this class can be used in a wide array of environments.\n * This method helps to accomplish this by invoking the current block on the socket's internal queue.\n * The methods below can be invoked from within the block to access\n * those generally thread-unsafe internal variables in a thread-safe manner.\n * The given block will be invoked synchronously on the socket's internal queue.\n * \n * If you save references to any protected variables and use them outside the block, you do so at your own peril.\n**/\n- (void)performBlock:(dispatch_block_t)block;\n\n/**\n * These methods are only available from within the context of a performBlock: invocation.\n * See the documentation for the performBlock: method above.\n * \n * Provides access to the socket's file descriptor(s).\n * If the socket is a server socket (is accepting incoming connections),\n * it might actually have multiple internal socket file descriptors - one for IPv4 and one for IPv6.\n**/\n- (int)socketFD;\n- (int)socket4FD;\n- (int)socket6FD;\n\n#if TARGET_OS_IPHONE\n\n/**\n * These methods are only available from within the context of a performBlock: invocation.\n * See the documentation for the performBlock: method above.\n * \n * Provides access to the socket's internal CFReadStream/CFWriteStream.\n * \n * These streams are only used as workarounds for specific iOS shortcomings:\n * \n * - Apple has decided to keep the SecureTransport framework private is iOS.\n *   This means the only supplied way to do SSL/TLS is via CFStream or some other API layered on top of it.\n *   Thus, in order to provide SSL/TLS support on iOS we are forced to rely on CFStream,\n *   instead of the preferred and faster and more powerful SecureTransport.\n * \n * - If a socket doesn't have backgrounding enabled, and that socket is closed while the app is backgrounded,\n *   Apple only bothers to notify us via the CFStream API.\n *   The faster and more powerful GCD API isn't notified properly in this case.\n * \n * See also: (BOOL)enableBackgroundingOnSocket\n**/\n- (nullable CFReadStreamRef)readStream;\n- (nullable CFWriteStreamRef)writeStream;\n\n/**\n * This method is only available from within the context of a performBlock: invocation.\n * See the documentation for the performBlock: method above.\n * \n * Configures the socket to allow it to operate when the iOS application has been backgrounded.\n * In other words, this method creates a read & write stream, and invokes:\n * \n * CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);\n * CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);\n * \n * Returns YES if successful, NO otherwise.\n * \n * Note: Apple does not officially support backgrounding server sockets.\n * That is, if your socket is accepting incoming connections, Apple does not officially support\n * allowing iOS applications to accept incoming connections while an app is backgrounded.\n * \n * Example usage:\n * \n * - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port\n * {\n *     [asyncSocket performBlock:^{\n *         [asyncSocket enableBackgroundingOnSocket];\n *     }];\n * }\n**/\n- (BOOL)enableBackgroundingOnSocket;\n\n#endif\n\n/**\n * This method is only available from within the context of a performBlock: invocation.\n * See the documentation for the performBlock: method above.\n * \n * Provides access to the socket's SSLContext, if SSL/TLS has been started on the socket.\n**/\n- (nullable SSLContextRef)sslContext;\n\n#pragma mark Utilities\n\n/**\n * The address lookup utility used by the class.\n * This method is synchronous, so it's recommended you use it on a background thread/queue.\n * \n * The special strings \"localhost\" and \"loopback\" return the loopback address for IPv4 and IPv6.\n * \n * @returns\n *   A mutable array with all IPv4 and IPv6 addresses returned by getaddrinfo.\n *   The addresses are specifically for TCP connections.\n *   You can filter the addresses, if needed, using the other utility methods provided by the class.\n**/\n+ (nullable NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr;\n\n/**\n * Extracting host and port information from raw address data.\n**/\n\n+ (nullable NSString *)hostFromAddress:(NSData *)address;\n+ (uint16_t)portFromAddress:(NSData *)address;\n\n+ (BOOL)isIPv4Address:(NSData *)address;\n+ (BOOL)isIPv6Address:(NSData *)address;\n\n+ (BOOL)getHost:( NSString * __nullable * __nullable)hostPtr port:(nullable uint16_t *)portPtr fromAddress:(NSData *)address;\n\n+ (BOOL)getHost:(NSString * __nullable * __nullable)hostPtr port:(nullable uint16_t *)portPtr family:(nullable sa_family_t *)afPtr fromAddress:(NSData *)address;\n\n/**\n * A few common line separators, for use with the readDataToData:... methods.\n**/\n+ (NSData *)CRLFData;   // 0x0D0A\n+ (NSData *)CRData;     // 0x0D\n+ (NSData *)LFData;     // 0x0A\n+ (NSData *)ZeroData;   // 0x00\n\n@end\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n@protocol GCDAsyncSocketDelegate <NSObject>\n@optional\n\n/**\n * This method is called immediately prior to socket:didAcceptNewSocket:.\n * It optionally allows a listening socket to specify the socketQueue for a new accepted socket.\n * If this method is not implemented, or returns NULL, the new accepted socket will create its own default queue.\n * \n * Since you cannot autorelease a dispatch_queue,\n * this method uses the \"new\" prefix in its name to specify that the returned queue has been retained.\n * \n * Thus you could do something like this in the implementation:\n * return dispatch_queue_create(\"MyQueue\", NULL);\n * \n * If you are placing multiple sockets on the same queue,\n * then care should be taken to increment the retain count each time this method is invoked.\n * \n * For example, your implementation might look something like this:\n * dispatch_retain(myExistingQueue);\n * return myExistingQueue;\n**/\n- (nullable dispatch_queue_t)newSocketQueueForConnectionFromAddress:(NSData *)address onSocket:(GCDAsyncSocket *)sock;\n\n/**\n * Called when a socket accepts a connection.\n * Another socket is automatically spawned to handle it.\n * \n * You must retain the newSocket if you wish to handle the connection.\n * Otherwise the newSocket instance will be released and the spawned connection will be closed.\n * \n * By default the new socket will have the same delegate and delegateQueue.\n * You may, of course, change this at any time.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;\n\n/**\n * Called when a socket connects and is ready for reading and writing.\n * The host parameter will be an IP address, not a DNS name.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;\n\n/**\n * Called when a socket connects and is ready for reading and writing.\n * The host parameter will be an IP address, not a DNS name.\n **/\n- (void)socket:(GCDAsyncSocket *)sock didConnectToUrl:(NSURL *)url;\n\n/**\n * Called when a socket has completed reading the requested data into memory.\n * Not called if there is an error.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;\n\n/**\n * Called when a socket has read in data, but has not yet completed the read.\n * This would occur if using readToData: or readToLength: methods.\n * It may be used to for things such as updating progress bars.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didReadPartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;\n\n/**\n * Called when a socket has completed writing the requested data. Not called if there is an error.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;\n\n/**\n * Called when a socket has written some data, but has not yet completed the entire write.\n * It may be used to for things such as updating progress bars.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag;\n\n/**\n * Called if a read operation has reached its timeout without completing.\n * This method allows you to optionally extend the timeout.\n * If you return a positive time interval (> 0) the read's timeout will be extended by the given amount.\n * If you don't implement this method, or return a non-positive time interval (<= 0) the read will timeout as usual.\n * \n * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.\n * The length parameter is the number of bytes that have been read so far for the read operation.\n * \n * Note that this method may be called multiple times for a single read if you return positive numbers.\n**/\n- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag\n                                                                 elapsed:(NSTimeInterval)elapsed\n                                                               bytesDone:(NSUInteger)length;\n\n/**\n * Called if a write operation has reached its timeout without completing.\n * This method allows you to optionally extend the timeout.\n * If you return a positive time interval (> 0) the write's timeout will be extended by the given amount.\n * If you don't implement this method, or return a non-positive time interval (<= 0) the write will timeout as usual.\n * \n * The elapsed parameter is the sum of the original timeout, plus any additions previously added via this method.\n * The length parameter is the number of bytes that have been written so far for the write operation.\n * \n * Note that this method may be called multiple times for a single write if you return positive numbers.\n**/\n- (NSTimeInterval)socket:(GCDAsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag\n                                                                  elapsed:(NSTimeInterval)elapsed\n                                                                bytesDone:(NSUInteger)length;\n\n/**\n * Conditionally called if the read stream closes, but the write stream may still be writeable.\n * \n * This delegate method is only called if autoDisconnectOnClosedReadStream has been set to NO.\n * See the discussion on the autoDisconnectOnClosedReadStream method for more information.\n**/\n- (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock;\n\n/**\n * Called when a socket disconnects with or without error.\n * \n * If you call the disconnect method, and the socket wasn't already disconnected,\n * then an invocation of this delegate method will be enqueued on the delegateQueue\n * before the disconnect method returns.\n * \n * Note: If the GCDAsyncSocket instance is deallocated while it is still connected,\n * and the delegate is not also deallocated, then this method will be invoked,\n * but the sock parameter will be nil. (It must necessarily be nil since it is no longer available.)\n * This is a generally rare, but is possible if one writes code like this:\n * \n * asyncSocket = nil; // I'm implicitly disconnecting the socket\n * \n * In this case it may preferrable to nil the delegate beforehand, like this:\n * \n * asyncSocket.delegate = nil; // Don't invoke my delegate method\n * asyncSocket = nil; // I'm implicitly disconnecting the socket\n * \n * Of course, this depends on how your state machine is configured.\n**/\n- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err;\n\n/**\n * Called after the socket has successfully completed SSL/TLS negotiation.\n * This method is not called unless you use the provided startTLS method.\n * \n * If a SSL/TLS negotiation fails (invalid certificate, etc) then the socket will immediately close,\n * and the socketDidDisconnect:withError: delegate method will be called with the specific SSL error code.\n**/\n- (void)socketDidSecure:(GCDAsyncSocket *)sock;\n\n/**\n * Allows a socket delegate to hook into the TLS handshake and manually validate the peer it's connecting to.\n *\n * This is only called if startTLS is invoked with options that include:\n * - GCDAsyncSocketManuallyEvaluateTrust == YES\n *\n * Typically the delegate will use SecTrustEvaluate (and related functions) to properly validate the peer.\n * \n * Note from Apple's documentation:\n *   Because [SecTrustEvaluate] might look on the network for certificates in the certificate chain,\n *   [it] might block while attempting network access. You should never call it from your main thread;\n *   call it only from within a function running on a dispatch queue or on a separate thread.\n * \n * Thus this method uses a completionHandler block rather than a normal return value.\n * The completionHandler block is thread-safe, and may be invoked from a background queue/thread.\n * It is safe to invoke the completionHandler block even if the socket has been closed.\n**/\n- (void)socket:(GCDAsyncSocket *)sock didReceiveTrust:(SecTrustRef)trust\n                                    completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler;\n\n@end\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/External Libraries/GCDAsyncSocketExtensions.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"GCDAsyncSocket.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface GCDAsyncSocket (GCDsyncSocketExtensions)\n+ (instancetype)socketWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq;\n\n@property (readonly) tls_protocol_version_t tlsNegotiatedProtocol;\n@property (readonly) tls_ciphersuite_t tlsNegotiatedCipherSuite;\n@property (readonly) SecTrustRef tlsTrustRef;\n@property (readonly, copy, nullable) NSArray<NSData *> *tlsCertificateChainData;\n@property (readonly, copy, nullable) NSString *tlsPolicyName;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/IRCConnectionConfig.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define IRCConnectionConfigFloodControlDefaultDelayInterval\t\t\t\t\t2\n#define IRCConnectionConfigFloodControlMinimumDelayInterval\t\t\t\t\t1\n#define IRCConnectionConfigFloodControlMaximumDelayInterval\t\t\t\t\t60\n#define IRCConnectionConfigFloodControlDefaultMessageCount\t\t\t\t\t6\n#define IRCConnectionConfigFloodControlMinimumMessageCount\t\t\t\t\t1\n#define IRCConnectionConfigFloodControlMaximumMessageCount\t\t\t\t\t60\n\nTEXTUAL_EXTERN uint16_t const IRCConnectionDefaultServerPort;\nTEXTUAL_EXTERN uint16_t const IRCConnectionDefaultProxyPort;\n\ntypedef NS_ENUM(NSUInteger, IRCConnectionProxyType) {\n\tIRCConnectionProxyTypeNone = 0,\n\tIRCConnectionProxyTypeAutomatic = 1,\n\tIRCConnectionProxyTypeSocks4 = 4,\n\tIRCConnectionProxyTypeSocks5 = 5,\n\tIRCConnectionProxyTypeHTTP = 6,\n\tIRCConnectionProxyTypeHTTPS = 7,\n\tIRCConnectionProxyTypeTor = 8\n};\n\n/* Select specific protocol to use. This does not define preference.\n When a specific protocol is enabled, its counterpart is disabled. */\ntypedef NS_ENUM(NSUInteger, IRCConnectionAddressType)\n{\n\tIRCConnectionAddressTypeDefault = 0, // enable both\n\tIRCConnectionAddressTypeIPv4 NS_SWIFT_NAME(v4) = 1,\n\tIRCConnectionAddressTypeIPv6 NS_SWIFT_NAME(v6) = 2\n};\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface IRCConnectionConfig : XRPortablePropertyObject\n@property (readonly) BOOL connectionPrefersModernCiphersOnly;\n@property (readonly) BOOL connectionPrefersModernSockets;\n@property (readonly) BOOL connectionPrefersSecuredConnection;\n@property (readonly) BOOL connectionShouldValidateCertificateChain;\n@property (readonly) IRCConnectionAddressType addressType;\n@property (readonly) IRCConnectionProxyType proxyType;\n@property (readonly) NSUInteger floodControlDelayInterval;\n@property (readonly) NSUInteger floodControlMaximumMessages;\n@property (readonly) uint16_t proxyPort;\n@property (readonly) uint16_t serverPort;\n@property (readonly, copy) NSString *serverAddress;\n@property (readonly, copy, nullable) NSString *proxyAddress;\n@property (readonly, copy, nullable) NSString *proxyPassword;\n@property (readonly, copy, nullable) NSString *proxyUsername;\n@property (readonly, copy, nullable) NSData *identityClientSideCertificate;\n@property (readonly) NSStringEncoding primaryEncoding NS_UNAVAILABLE;\n@property (readonly) NSStringEncoding fallbackEncoding NS_UNAVAILABLE;\n@property (readonly) RCMCipherSuiteCollection cipherSuites;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface IRCConnectionConfigMutable : IRCConnectionConfig\n@property (nonatomic, assign, readwrite) BOOL connectionPrefersModernCiphersOnly;\n@property (nonatomic, assign, readwrite) BOOL connectionPrefersModernSockets;\n@property (nonatomic, assign, readwrite) BOOL connectionPrefersSecuredConnection;\n@property (nonatomic, assign, readwrite) BOOL connectionShouldValidateCertificateChain;\n@property (nonatomic, assign, readwrite) IRCConnectionAddressType addressType;\n@property (nonatomic, assign, readwrite) IRCConnectionProxyType proxyType;\n@property (nonatomic, assign, readwrite) NSUInteger floodControlDelayInterval;\n@property (nonatomic, assign, readwrite) NSUInteger floodControlMaximumMessages;\n@property (nonatomic, assign, readwrite) uint16_t proxyPort;\n@property (nonatomic, assign, readwrite) uint16_t serverPort;\n@property (nonatomic, copy, readwrite) NSString *serverAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyAddress;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyPassword;\n@property (nonatomic, copy, readwrite, nullable) NSString *proxyUsername;\n@property (nonatomic, copy, readwrite, nullable) NSData *identityClientSideCertificate;\n@property (nonatomic, assign, readwrite) NSStringEncoding primaryEncoding NS_UNAVAILABLE;\n@property (nonatomic, assign, readwrite) NSStringEncoding fallbackEncoding NS_UNAVAILABLE;\n@property (nonatomic, assign, readwrite) RCMCipherSuiteCollection cipherSuites;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/IRCConnectionErrors.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *     Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\nextern NSErrorDomain const IRCConnectionErrorDomain NS_SWIFT_NAME(ConnectionErrorDomain);\n\ntypedef NS_ENUM(NSUInteger, IRCConnectionErrorCode)\n{\n\tIRCConnectionErrorCodeSocket\t\t\t= 999,\n\tIRCConnectionErrorCodeOther\t\t\t\t= 1000,\n\tIRCConnectionErrorCodeBadCertificate\t= 1001,\n\tIRCConnectionErrorCodeUnableToSecure\t= 1002\n} NS_SWIFT_NAME(ConnectionErrorCode);\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/Internal/IRCConnectionConfigInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCConnectionConfig.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCConnectionConfig ()\n{\n@protected\n\tBOOL _connectionPrefersModernCiphersOnly;\n\tBOOL _connectionPrefersModernSockets;\n\tBOOL _connectionPrefersSecuredConnection;\n\tBOOL _connectionShouldValidateCertificateChain;\n\tIRCConnectionAddressType _addressType;\n\tIRCConnectionProxyType _proxyType;\n\tNSData *_identityClientSideCertificate;\n\tNSString *_proxyAddress;\n\tNSString *_proxyPassword;\n\tNSString *_proxyUsername;\n\tNSString *_serverAddress;\n\tNSUInteger _floodControlDelayInterval;\n\tNSUInteger _floodControlMaximumMessages;\n\tuint16_t _proxyPort;\n\tuint16_t _serverPort;\n\tNSStringEncoding _primaryEncoding;\n\tNSStringEncoding _fallbackEncoding;\n\tRCMCipherSuiteCollection _cipherSuites;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/Private/NSObjectHelperPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface NSObject (TXObjectHelper)\n- (void)applicationDidFinishLaunching;\n\n- (void)preferencesChanged;\n\n- (void)prepareInitialState;\n- (void)prepareForApplicationTermination;\n- (void)prepareForPermanentDestruction;\n\n+ (void)preferencesChanged;\n\n+ (void)prepareInitialState;\n+ (void)prepareForApplicationTermination;\n+ (void)prepareForPermanentDestruction;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/Private/TPCPreferencesPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferences ()\n+ (void)setInlineMediaMaxWidth:(NSUInteger)value;\n+ (void)setInlineMediaMaxHeight:(NSUInteger)value;\n\n+ (void)setInlineMediaLimitToBasics:(BOOL)inlineMediaLimitToBasics;\n+ (void)setInlineMediaLimitBasicsToFiles:(BOOL)inlineMediaLimitBasicsToFiles;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/Private/TPCPreferencesUserDefaultsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesUserDefaults.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferencesUserDefaults ()\n- (void)setObject:(nullable id)value forKey:(NSString *)defaultName postNotification:(BOOL)postNotification;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/Private/TVCLogLineXPCPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CoreData/CoreData.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TVCLogLineXPC : NSObject <NSCoding, NSSecureCoding>\n@property (copy, readonly) NSData *data;\n@property (copy, readonly) NSString *uniqueIdentifier;\n@property (copy, readonly) NSString *viewIdentifier;\n@property (readonly) NSUInteger sessionIdentifier;\n@property (readonly) NSTimeInterval creationDate;\n\n- (instancetype)initWithLogLineData:(NSData *)data\n\t\t\t\t   uniqueIdentifier:(NSString *)uniqueIdentifier\n\t\t\t\t\t viewIdentifier:(NSString *)viewIdentifier\n\t\t\t\t  sessionIdentifier:(NSUInteger)sessionIdentifier;\n\n- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/StaticDefinitions.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* Defines for operating system detection. */\n#define TXLoadMacOSVersionSpecificFeatures\t\t1\n\n/* Shortcut defines. */\n#define RZAnimationCurrentContext()\t\t\t\t[NSAnimationContext\tcurrentContext]\n#define RZAppearanceCurrentController()\t\t\t[NSAppearance currentAppearance]\n#define RZAppleEventManager()\t\t\t\t\t[NSAppleEventManager sharedAppleEventManager]\n#define RZCurrentCalendar()\t\t\t\t\t\t[NSCalendar currentCalendar]\n#define RZCurrentRunLoop()\t\t\t\t\t\t[NSRunLoop currentRunLoop]\n#define RZDistributedNotificationCenter()\t\t[NSDistributedNotificationCenter defaultCenter]\n#define RZFileManager()\t\t\t\t\t\t\t[NSFileManager defaultManager]\n#define RZFontManager()\t\t\t\t\t\t\t[NSFontManager sharedFontManager]\n#define RZGraphicsCurrentContext()\t\t\t\t[NSGraphicsContext currentContext]\n#define RZMainBundle()\t\t\t\t\t\t\t[NSBundle mainBundle]\n#define RZMainOperationQueue()\t\t\t\t\t[NSOperationQueue mainQueue]\n#define RZMainRunLoop()\t\t\t\t\t\t\t[NSRunLoop mainRunLoop]\n#define RZMainScreen()\t\t\t\t\t\t\t[NSScreen mainScreen]\n#define RZNotificationCenter()\t\t\t\t\t[NSNotificationCenter defaultCenter]\n#define RZPasteboard()\t\t\t\t\t\t\t[NSPasteboard generalPasteboard]\n#define RZProcessInfo()\t\t\t\t\t\t\t[NSProcessInfo processInfo]\n#define RZRunningApplication()\t\t\t\t\t[NSRunningApplication currentApplication]\n#define RZSharedApplication()\t\t\t\t\t[NSApplication sharedApplication]\n#define RZSpellChecker()\t\t\t\t\t\t[NSSpellChecker\tsharedSpellChecker]\n#define RZUbiquitousKeyValueStore()\t\t\t\t[NSUbiquitousKeyValueStore defaultStore]\n#define RZUserNotificationCenter()\t\t\t\t[UNUserNotificationCenter currentNotificationCenter]\n#define RZWorkspace()\t\t\t\t\t\t\t[NSWorkspace sharedWorkspace]\n#define RZWorkspaceNotificationCenter()\t\t\t[[NSWorkspace sharedWorkspace] notificationCenter]\n\n/* Misc. */\n#define NSInvertedComparisonResult(c)\t\t\t((c) * (-1))\n\n#define NSIsCurrentThreadMain()\t\t\t\t\t[[NSThread isMainThread]]\n\n/* Deprecation and symbol visibility. */\n#define TEXTUAL_EXTERN\t\t\t\t\t\t\textern\n\n#define TEXTUAL_SYMBOL_USED\t\t\t\t\t\t__attribute__((used))\n\n#define TEXTUAL_RUNNING_ON(version, name)\t\tCOCOA_EXTENSIONS_RUNNING_ON(version, name)\n#define TEXTUAL_RUNNING_ON_BIGSUR \t\t\t\tTEXTUAL_RUNNING_ON(11.0, BigSur)\n#define TEXTUAL_RUNNING_ON_MOJAVE \t\t\t\tTEXTUAL_RUNNING_ON(10.14, Mojave)\n#define TEXTUAL_RUNNING_ON_HIGHSIERRA \t\t\tTEXTUAL_RUNNING_ON(10.13, HighSierra)\n#define TEXTUAL_RUNNING_ON_SIERRA \t\t\t\tTEXTUAL_RUNNING_ON(10.12, Sierra)\n#define TEXTUAL_RUNNING_ON_ELCAPITAN \t\t\tTEXTUAL_RUNNING_ON(10.11, ElCapitan)\n#define TEXTUAL_RUNNING_ON_YOSEMITE \t\t\tTEXTUAL_RUNNING_ON(10.10, Yosemite)\n#define TEXTUAL_RUNNING_ON_MAVERICKS \t\t\tTEXTUAL_RUNNING_ON(10.9, Mavericks)\n\n#define TEXTUAL_DEPRECATED(reason)\t\t\t\tCOCOA_EXTENSIONS_DEPRECATED(reason)\n\n#define TEXTUAL_DEPRECATED_ASSERT\t\t\t\tCOCOA_EXTENSIONS_DEPRECATED_ASSERT\n#define TEXTUAL_DEPRECATED_ASSERT_C\t\t\t\tCOCOA_EXTENSIONS_DEPRECATED_ASSERT_C\n\n#define TEXTUAL_DEPRECATED_WARNING\t\t\t\tCOCOA_EXTENSIONS_DEPRECATED_WARNING\n\n#define TEXTUAL_IGNORE_DEPRECATION_BEGIN\t\tCOCOA_EXTENSIONS_IGNORE_DEPRECATION_BEGIN\n#define TEXTUAL_IGNORE_DEPRECATION_END\t\t\tCOCOA_EXTENSIONS_IGNORE_DEPRECATION_END\n\n#define TEXTUAL_IGNORE_AVAILABILITY_BEGIN\t\t_Pragma(\"clang diagnostic push\")\t\t\t\t\t\t\t\t\t\\\n\t\t\t\t\t\t\t\t\t\t\t\t_Pragma(\"clang diagnostic ignored \\\"-Wpartial-availability\\\"\")\n\n#define TEXTUAL_IGNORE_AVAILABILITY_END\t\t\t_Pragma(\"clang diagnostic pop\")\n\n/* WebView deprecation */\n/* The entirety of pre-WebKit2 code is deprecated by Apple.\n Textual uses a great deal of this code and if left unchecked, a large number\n of deprecation warnings will appear during build. It would be overwhelming\n to suppress every warning individually. Entire files have been marked to\n ignore deprecation warnings. As we cannot ignore WebKit specific deprecation\n warnings, this leaves the problem of unrelated deprecation warnings ignored.\n Modify the following flag routinely to check for unrelated deprecations. */\n#define TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS\t1\n\n#if TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS == 1\n\t#define TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN TEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t#define TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END TEXTUAL_IGNORE_DEPRECATION_END\n#else\n\t#define TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_BEGIN\n\t#define TEXTUAL_IGNORE_WEBKIT_DEPRECATIONS_END\n#endif\n\n/* Helper function */\n#define StringFromBOOL(value) ((value) ? @\"YES\" : @\"NO\")\n\n#define SetVariableIfNil(variable, value)\t\t\t\t\t\\\n\tif ((variable) == nil) {\t\t\t\t\t\t\t\t\\\n\t\t(variable) = (value);\t\t\t\t\t\t\t\t\\\n\t}\n\n#define SetVariableIfNilCopy(variable, value)\t\t\t\t\\\n\tSetVariableIfNil((variable), [(value) copy])\n\n/* Define features */\n#import \"FeatureFlags.h\"\n\n/* @end */\n"
  },
  {
    "path": "Sources/Shared/Headers/TLOLocalization.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\nTEXTUAL_EXTERN NSString *TXTLS(NSString *key, ...);\n\nTEXTUAL_EXTERN NSString *TXLocalizedString(NSBundle *bundle, NSString *key, va_list arguments) TEXTUAL_SYMBOL_USED;\nTEXTUAL_EXTERN NSString *TXLocalizedStringAlternative(NSBundle *bundle, NSString *key, ...) TEXTUAL_SYMBOL_USED;\n\n/* This function exists so that static analyzer doesn't warn\n certain static strings aren't localized. Some strings wont\n be localized because it is inappropriate (e.g. a number) */\n__attribute__((annotate(\"returns_localized_nsstring\")))\nstatic inline NSString *TXLocalizationNotNeeded(NSString *string)\n{\n\treturn string;\n}\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/TLOTimer.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TLOTimer;\n\ntypedef void (^TLOTimerActionBlock)(TLOTimer *sender);\n\n@interface TLOTimer : NSObject\n@property (readonly, copy) TLOTimerActionBlock actionBlock;\n@property (nonatomic, strong, nullable) dispatch_queue_t queue; // Defaults to main queue. Changed ignored while active.\n@property (nonatomic, strong, nullable) id context;\n\n@property (readonly) NSTimeInterval startTime;\n@property (readonly) NSTimeInterval timeRemaining;\n\n@property (readonly) NSTimeInterval interval;\n@property (readonly) BOOL timerIsActive;\n@property (readonly) BOOL repeatTimer;\n@property (readonly) NSUInteger iterations;\n\n@property (readonly) NSUInteger currentIteration;\n\n+ (instancetype)timerWithActionBlock:(TLOTimerActionBlock)actionBlock;\n+ (instancetype)timerWithActionBlock:(TLOTimerActionBlock)actionBlock onQueue:(dispatch_queue_t)queue;\n\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithActionBlock:(TLOTimerActionBlock)actionBlock;\n- (instancetype)initWithActionBlock:(TLOTimerActionBlock)actionBlock onQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER;\n\n- (void)start:(NSTimeInterval)interval; // repeatTimer = NO\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer; // iterations = 0\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations; // 0 iterations = infinite\n\n- (void)stop;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/TPCPreferences.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TPCPreferences : NSObject\n+ (uint64_t)inlineImagesMaxFilesize;\n\n+ (NSUInteger)inlineMediaMaxWidth;\n+ (NSUInteger)inlineMediaMaxHeight;\n\n+ (BOOL)inlineMediaLimitToBasics; // images & videos\n+ (BOOL)inlineMediaLimitBasicsToFiles; // Only hotlinked files and not services\n+ (BOOL)inlineMediaLimitInsecureContent; // No HTTP\n+ (BOOL)inlineMediaLimitNaughtyContent; // No NSFW\n+ (BOOL)inlineMediaLimitUnsafeContent; // No content that injects HTML\n\n // Check every single URL to find out if it is an image or video\n+ (BOOL)inlineMediaCheckEverything;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Headers/TPCPreferencesUserDefaults.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#define RZUserDefaults()\t\t\t\t\t\t[TPCPreferencesUserDefaults sharedUserDefaults]\n\n/* The user info dictionary of this notification contains the changed key. */\nTEXTUAL_EXTERN NSNotificationName const TPCPreferencesUserDefaultsDidChangeNotification;\n\n/* TPCPreferencesUserDefaults subclasses NSUserDefaults to allow Textual to fire off\n notifications for changed keys on a per-key basis so that the iCloud controller can\n know what keys change instead of having to sync every single key, every time that it\n performs an upstream sync. */\n@interface TPCPreferencesUserDefaults : NSUserDefaults\n+ (TPCPreferencesUserDefaults *)sharedUserDefaults;\n\n- (void)registerDefault:(id <NSCopying>)value forKey:(NSString *)defaultName;\n\n@property (copy, readonly) NSDictionary<NSString *, id> *registeredDefaults;\n@end\n\n/* Trying to create a new instance of TPCPreferencesUserDefaultsController will\n return the value of +sharedUserDefaultsController */\n@interface TPCPreferencesUserDefaultsController : NSUserDefaultsController\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Helpers/Cocoa (Objective-C)/NSObjectHelper.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation NSObject (TXObjectHelper)\n\n- (void)applicationDidFinishLaunching\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (void)preferencesChanged\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (void)prepareInitialState\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (void)prepareForApplicationTermination\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n- (void)prepareForPermanentDestruction\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n+ (void)preferencesChanged\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n+ (void)prepareInitialState\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n+ (void)prepareForApplicationTermination\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n+ (void)prepareForPermanentDestruction\n{\n\t[self doesNotRecognizeSelector:_cmd];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/IRC/IRCConnectionConfig.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCConnectionConfigInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nuint16_t const IRCConnectionDefaultServerPort = 6667;\nuint16_t const IRCConnectionDefaultProxyPort = 1080;\n\n@implementation IRCConnectionConfig\n\n- (instancetype)init\n{\n\tif ((self = [super init])) {\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self->_serverAddress == nil) {\n\t\tself->_serverAddress = @\"\";\n\t}\n\n\tif (self->_proxyPort == 0) {\n\t\tself->_proxyPort = IRCConnectionDefaultProxyPort;\n\t}\n\n\tif (self->_serverPort == 0) {\n\t\tself->_serverPort = IRCConnectionDefaultServerPort;\n\t}\n\n\tif (self->_floodControlDelayInterval == 0) {\n\t\tself->_floodControlDelayInterval = IRCConnectionConfigFloodControlDefaultDelayInterval;\n\t}\n\n\tif (self->_floodControlMaximumMessages == 0) {\n\t\tself->_floodControlMaximumMessages = IRCConnectionConfigFloodControlDefaultMessageCount;\n\t}\n}\n\n- (BOOL)populateWithDecoder:(NSCoder *)aDecoder\n{\n\tself->_addressType = [aDecoder decodeUnsignedIntegerForKey:@\"addressType\"];\n\tself->_connectionPrefersModernCiphersOnly = [aDecoder decodeBoolForKey:@\"connectionPrefersModernCiphersOnly\"];\n\tself->_connectionPrefersModernSockets = [aDecoder decodeBoolForKey:@\"connectionPrefersModernSockets\"];\n\tself->_connectionPrefersSecuredConnection = [aDecoder decodeBoolForKey:@\"connectionPrefersSecuredConnection\"];\n\tself->_connectionShouldValidateCertificateChain = [aDecoder decodeBoolForKey:@\"connectionShouldValidateCertificateChain\"];\n\tself->_floodControlDelayInterval = [aDecoder decodeUnsignedIntegerForKey:@\"floodControlDelayInterval\"];\n\tself->_floodControlMaximumMessages = [aDecoder decodeUnsignedIntegerForKey:@\"floodControlMaximumMessages\"];\n\tself->_identityClientSideCertificate = [aDecoder decodeDataForKey:@\"identityClientSideCertificate\"];\n\tself->_proxyAddress = [aDecoder decodeStringForKey:@\"proxyAddress\"];\n\tself->_proxyPassword = [aDecoder decodeStringForKey:@\"proxyPassword\"];\n\tself->_proxyPort = [aDecoder decodeUnsignedShortForKey:@\"proxyPort\"];\n\tself->_proxyType = [aDecoder decodeUnsignedIntegerForKey:@\"proxyType\"];\n\tself->_proxyUsername = [aDecoder decodeStringForKey:@\"proxyUsername\"];\n\tself->_serverAddress = [aDecoder decodeStringForKey:@\"serverAddress\"];\n\tself->_serverPort = [aDecoder decodeUnsignedShortForKey:@\"serverPort\"];\n\tself->_primaryEncoding = [aDecoder decodeUnsignedIntegerForKey:@\"primaryEncoding\"];\n\tself->_fallbackEncoding = [aDecoder decodeUnsignedIntegerForKey:@\"fallbackEncoding\"];\n\tself->_cipherSuites = [aDecoder decodeUnsignedIntegerForKey:@\"cipherSuites\"];\n\n\treturn YES;\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder\n{\n\tNSParameterAssert(aCoder != nil);\n\n\t[aCoder encodeUnsignedInteger:self->_addressType forKey:@\"addressType\"];\n\t[aCoder encodeBool:self->_connectionPrefersModernCiphersOnly forKey:@\"connectionPrefersModernCiphersOnly\"];\n\t[aCoder encodeBool:self->_connectionPrefersModernSockets forKey:@\"connectionPrefersModernSockets\"];\n\t[aCoder encodeBool:self->_connectionPrefersSecuredConnection forKey:@\"connectionPrefersSecuredConnection\"];\n\t[aCoder encodeBool:self->_connectionShouldValidateCertificateChain forKey:@\"connectionShouldValidateCertificateChain\"];\n\t[aCoder encodeUnsignedInteger:self->_floodControlDelayInterval forKey:@\"floodControlDelayInterval\"];\n\t[aCoder encodeUnsignedInteger:self->_floodControlMaximumMessages forKey:@\"floodControlMaximumMessages\"];\n\t[aCoder maybeEncodeObject:self->_identityClientSideCertificate forKey:@\"identityClientSideCertificate\"];\n\t[aCoder maybeEncodeObject:self->_proxyAddress forKey:@\"proxyAddress\"];\n\t[aCoder maybeEncodeObject:self->_proxyPassword forKey:@\"proxyPassword\"];\n\t[aCoder encodeUnsignedShort:self->_proxyPort forKey:@\"proxyPort\"];\n\t[aCoder encodeUnsignedInteger:self->_proxyType forKey:@\"proxyType\"];\n\t[aCoder maybeEncodeObject:self->_proxyUsername forKey:@\"proxyUsername\"];\n\t[aCoder encodeString:self->_serverAddress forKey:@\"serverAddress\"];\n\t[aCoder encodeUnsignedShort:self->_serverPort forKey:@\"serverPort\"];\n\t[aCoder encodeUnsignedInteger:self->_primaryEncoding forKey:@\"primaryEncoding\"];\n\t[aCoder encodeUnsignedInteger:self->_fallbackEncoding forKey:@\"fallbackEncoding\"];\n\t[aCoder encodeUnsignedInteger:self->_cipherSuites forKey:@\"cipherSuites\"];\n}\n\n+ (BOOL)supportsSecureCoding\n{\n\treturn YES;\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tIRCConnectionConfig *object = [self allocForCopyAsMutable:mutableCopy];\n\n\tobject->_addressType = self->_addressType;\n\tobject->_connectionPrefersModernCiphersOnly = self->_connectionPrefersModernCiphersOnly;\n\tobject->_connectionPrefersModernSockets = self->_connectionPrefersModernSockets;\n\tobject->_connectionPrefersSecuredConnection = self->_connectionPrefersSecuredConnection;\n\tobject->_connectionShouldValidateCertificateChain = self->_connectionShouldValidateCertificateChain;\n\tobject->_floodControlDelayInterval = self->_floodControlDelayInterval;\n\tobject->_floodControlMaximumMessages = self->_floodControlMaximumMessages;\n\tobject->_identityClientSideCertificate = self->_identityClientSideCertificate;\n\tobject->_proxyAddress = self->_proxyAddress;\n\tobject->_proxyPassword = self->_proxyPassword;\n\tobject->_proxyPort = self->_proxyPort;\n\tobject->_proxyType = self->_proxyType;\n\tobject->_proxyUsername = self->_proxyUsername;\n\tobject->_serverAddress = self->_serverAddress;\n\tobject->_serverPort = self->_serverPort;\n\tobject->_primaryEncoding = self->_primaryEncoding;\n\tobject->_fallbackEncoding = self->_fallbackEncoding;\n\tobject->_cipherSuites = self->_cipherSuites;\n\n\treturn [object initOnCopy];\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [IRCConnectionConfigMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation IRCConnectionConfigMutable\n\n@dynamic addressType;\n@dynamic connectionPrefersModernCiphersOnly;\n@dynamic connectionPrefersModernSockets;\n@dynamic connectionPrefersSecuredConnection;\n@dynamic connectionShouldValidateCertificateChain;\n@dynamic floodControlDelayInterval;\n@dynamic floodControlMaximumMessages;\n@dynamic identityClientSideCertificate;\n@dynamic proxyAddress;\n@dynamic proxyPassword;\n@dynamic proxyPort;\n@dynamic proxyType;\n@dynamic proxyUsername;\n@dynamic serverAddress;\n@dynamic serverPort;\n@dynamic primaryEncoding;\n@dynamic fallbackEncoding;\n@dynamic cipherSuites;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [IRCConnectionConfig self];\n}\n\n- (void)setConnectionPrefersModernCiphersOnly:(BOOL)connectionPrefersModernCiphersOnly\n{\n\tif (self->_connectionPrefersModernCiphersOnly != connectionPrefersModernCiphersOnly) {\n\t\tself->_connectionPrefersModernCiphersOnly = connectionPrefersModernCiphersOnly;\n\t}\n}\n\n- (void)setConnectionPrefersModernSockets:(BOOL)connectionPrefersModernSockets\n{\n\tif (self->_connectionPrefersModernSockets != connectionPrefersModernSockets) {\n\t\tself->_connectionPrefersModernSockets = connectionPrefersModernSockets;\n\t}\n}\n\n- (void)setConnectionPrefersSecuredConnection:(BOOL)connectionPrefersSecuredConnection\n{\n\tif (self->_connectionPrefersSecuredConnection != connectionPrefersSecuredConnection) {\n\t\tself->_connectionPrefersSecuredConnection = connectionPrefersSecuredConnection;\n\t}\n}\n\n- (void)setConnectionShouldValidateCertificateChain:(BOOL)connectionShouldValidateCertificateChain\n{\n\tif (self->_connectionShouldValidateCertificateChain != connectionShouldValidateCertificateChain) {\n\t\tself->_connectionShouldValidateCertificateChain = connectionShouldValidateCertificateChain;\n\t}\n}\n\n- (void)setAddressType:(IRCConnectionAddressType)addressType\n{\n\tif (self->_addressType != addressType) {\n\t\tself->_addressType = addressType;\n\t}\n}\n\n- (void)setProxyType:(IRCConnectionProxyType)proxyType\n{\n\tif (self->_proxyType != proxyType) {\n\t\tself->_proxyType = proxyType;\n\t}\n}\n\n- (void)setIdentityClientSideCertificate:(nullable NSData *)identityClientSideCertificate\n{\n\tif (self->_identityClientSideCertificate != identityClientSideCertificate) {\n\t\tself->_identityClientSideCertificate = identityClientSideCertificate.copy;\n\t}\n}\n\n- (void)setProxyAddress:(nullable NSString *)proxyAddress\n{\n\tif (self->_proxyAddress != proxyAddress) {\n\t\tself->_proxyAddress = proxyAddress.copy;\n\t}\n}\n\n- (void)setProxyPassword:(nullable NSString *)proxyPassword\n{\n\tif (self->_proxyPassword != proxyPassword) {\n\t\tself->_proxyPassword = proxyPassword.copy;\n\t}\n}\n\n- (void)setProxyUsername:(nullable NSString *)proxyUsername\n{\n\tif (self->_proxyUsername != proxyUsername) {\n\t\tself->_proxyUsername = proxyUsername.copy;\n\t}\n}\n\n- (void)setServerAddress:(NSString *)serverAddress\n{\n\tNSParameterAssert(serverAddress != nil);\n\n\tif (self->_serverAddress != serverAddress) {\n\t\tself->_serverAddress = serverAddress.copy;\n\t}\n}\n\n- (void)setFloodControlDelayInterval:(NSUInteger)floodControlDelayInterval\n{\n\tNSParameterAssert(floodControlDelayInterval >= IRCConnectionConfigFloodControlMinimumDelayInterval &&\n\t\t\t\t\t  floodControlDelayInterval <= IRCConnectionConfigFloodControlMaximumDelayInterval);\n\n\tif (self->_floodControlDelayInterval != floodControlDelayInterval) {\n\t\tself->_floodControlDelayInterval = floodControlDelayInterval;\n\t}\n}\n\n- (void)setFloodControlMaximumMessages:(NSUInteger)floodControlMaximumMessages\n{\n\tNSParameterAssert(floodControlMaximumMessages >= IRCConnectionConfigFloodControlMinimumMessageCount &&\n\t\t\t\t\t  floodControlMaximumMessages <= IRCConnectionConfigFloodControlMaximumMessageCount);\n\n\tif (self->_floodControlMaximumMessages != floodControlMaximumMessages) {\n\t\tself->_floodControlMaximumMessages = floodControlMaximumMessages;\n\t}\n}\n\n- (void)setProxyPort:(uint16_t)proxyPort\n{\n\tif (self->_proxyPort != proxyPort) {\n\t\tself->_proxyPort = proxyPort;\n\t}\n}\n\n- (void)setServerPort:(uint16_t)serverPort\n{\n\tif (self->_serverPort != serverPort) {\n\t\tself->_serverPort = serverPort;\n\t}\n}\n\n- (void)setPrimaryEncoding:(NSStringEncoding)primaryEncoding\n{\n\tif (self->_primaryEncoding != primaryEncoding) {\n\t\tself->_primaryEncoding = primaryEncoding;\n\t}\n}\n\n- (void)setFallbackEncoding:(NSStringEncoding)fallbackEncoding\n{\n\tif (self->_fallbackEncoding != fallbackEncoding) {\n\t\tself->_fallbackEncoding = fallbackEncoding;\n\t}\n}\n\n- (void)setCipherSuites:(RCMCipherSuiteCollection)cipherSuites\n{\n\tif (self->_cipherSuites != cipherSuites) {\n\t\tself->_cipherSuites = cipherSuites;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/IRC/IRCConnectionErrors.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"IRCConnectionErrors.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const IRCConnectionErrorDomain = @\"Textual.ConnectionError\";\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Library/External Libraries/Sockets/GCDAsyncSocket-patch.txt",
    "content": "commit c0e472e058df72293d9a313dc1b0d8437f3af4ae\nAuthor: Michael Morris <michael@codeux.com>\nDate:   Tue Jul 5 21:21:13 2016 -0400\n\n    Patches for Textual\n\ndiff --git a/Source/GCD/GCDAsyncSocket.m b/Source/GCD/GCDAsyncSocket.m\nold mode 100644\nnew mode 100755\nindex 1f13e36..c826db8\n--- a/Source/GCD/GCDAsyncSocket.m\n+++ b/Source/GCD/GCDAsyncSocket.m\n@@ -29,6 +29,8 @@\n #import <sys/un.h>\n #import <unistd.h>\n \n+#define GCDAsyncSocketUsesStrictTimers\t\t1\n+\n #if ! __has_feature(objc_arc)\n #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n // For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC\n@@ -508,7 +510,7 @@ - (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable\n \t{\n \t\t// Read a specific length of data\n \t\t\n-\t\treturn MIN(bytesAvailable, (readLength - bytesDone));\n+\t\treturn (readLength - bytesDone);\n \t\t\n \t\t// No need to avoid resizing the buffer.\n \t\t// If the user provided their own buffer,\n@@ -3010,7 +3012,11 @@ - (void)startConnectTimeout:(NSTimeInterval)timeout\n {\n \tif (timeout >= 0.0)\n \t{\n+#if GCDAsyncSocketUsesStrictTimers == 1\n+\t\tconnectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, socketQueue);\n+#else\n \t\tconnectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);\n+#endif\n \t\t\n \t\t__weak GCDAsyncSocket *weakSelf = self;\n \t\t\n@@ -5664,8 +5670,12 @@ - (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout\n {\n \tif (timeout >= 0.0)\n \t{\n+#if GCDAsyncSocketUsesStrictTimers == 1\n+\t\treadTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, socketQueue);\n+#else\n \t\treadTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);\n-\t\t\n+#endif\n+\n \t\t__weak GCDAsyncSocket *weakSelf = self;\n \t\t\n \t\tdispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool {\n@@ -6307,8 +6317,12 @@ - (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout\n {\n \tif (timeout >= 0.0)\n \t{\n+#if GCDAsyncSocketUsesStrictTimers == 1\n+\t\twriteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, socketQueue);\n+#else\n \t\twriteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, socketQueue);\n-\t\t\n+#endif\n+\n \t\t__weak GCDAsyncSocket *weakSelf = self;\n \t\t\n \t\tdispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool {\n@@ -7011,7 +7025,7 @@ - (void)ssl_startTLS\n \t\tfor (cipherIndex = 0; cipherIndex < numberCiphers; cipherIndex++)\n \t\t{\n \t\t\tNSNumber *cipherObject = [cipherSuites objectAtIndex:cipherIndex];\n-\t\t\tciphers[cipherIndex] = [cipherObject shortValue];\n+\t\t\tciphers[cipherIndex] = [cipherObject intValue];\n \t\t}\n \t\t\n \t\tstatus = SSLSetEnabledCiphers(sslContext, ciphers, numberCiphers);\n"
  },
  {
    "path": "Sources/Shared/Library/External Libraries/Sockets/GCDAsyncSocket.m",
    "content": "//\n//  GCDAsyncSocket.m\n//  \n//  This class is in the public domain.\n//  Originally created by Robbie Hanson in Q4 2010.\n//  Updated and maintained by Deusty LLC and the Apple development community.\n//\n//  https://github.com/robbiehanson/CocoaAsyncSocket\n//\n\n#import \"GCDAsyncSocket.h\"\n\n#if TARGET_OS_IPHONE\n#import <CFNetwork/CFNetwork.h>\n#endif\n\n#import <TargetConditionals.h>\n#import <arpa/inet.h>\n#import <fcntl.h>\n#import <ifaddrs.h>\n#import <netdb.h>\n#import <netinet/in.h>\n#import <net/if.h>\n#import <sys/socket.h>\n#import <sys/types.h>\n#import <sys/ioctl.h>\n#import <sys/poll.h>\n#import <sys/uio.h>\n#import <sys/un.h>\n#import <unistd.h>\n\n#if ! __has_feature(objc_arc)\n#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).\n// For more information see: https://github.com/robbiehanson/CocoaAsyncSocket/wiki/ARC\n#endif\n\n#define GCDAsyncSocketReadEOFPollsSocketForWriteStatus\t1\n\n#ifndef GCDAsyncSocketLoggingEnabled\n#define GCDAsyncSocketLoggingEnabled 0\n#endif\n\n#if GCDAsyncSocketLoggingEnabled\n\n// Logging Enabled - See log level below\n\n// Logging uses the CocoaLumberjack framework (which is also GCD based).\n// https://github.com/robbiehanson/CocoaLumberjack\n// \n// It allows us to do a lot of logging without significantly slowing down the code.\n#import \"DDLog.h\"\n\n#define LogAsync   YES\n#define LogContext GCDAsyncSocketLoggingContext\n\n#define LogObjc(flg, frmt, ...) LOG_OBJC_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)\n#define LogC(flg, frmt, ...)    LOG_C_MAYBE(LogAsync, logLevel, flg, LogContext, frmt, ##__VA_ARGS__)\n\n#define LogError(frmt, ...)     LogObjc(LOG_FLAG_ERROR,   (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogWarn(frmt, ...)      LogObjc(LOG_FLAG_WARN,    (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogInfo(frmt, ...)      LogObjc(LOG_FLAG_INFO,    (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogVerbose(frmt, ...)   LogObjc(LOG_FLAG_VERBOSE, (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n\n#define LogCError(frmt, ...)    LogC(LOG_FLAG_ERROR,   (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogCWarn(frmt, ...)     LogC(LOG_FLAG_WARN,    (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogCInfo(frmt, ...)     LogC(LOG_FLAG_INFO,    (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n#define LogCVerbose(frmt, ...)  LogC(LOG_FLAG_VERBOSE, (@\"%@: \" frmt), THIS_FILE, ##__VA_ARGS__)\n\n#define LogTrace()              LogObjc(LOG_FLAG_VERBOSE, @\"%@: %@\", THIS_FILE, THIS_METHOD)\n#define LogCTrace()             LogC(LOG_FLAG_VERBOSE, @\"%@: %s\", THIS_FILE, __FUNCTION__)\n\n#ifndef GCDAsyncSocketLogLevel\n#define GCDAsyncSocketLogLevel LOG_LEVEL_VERBOSE\n#endif\n\n// Log levels : off, error, warn, info, verbose\nstatic const int logLevel = GCDAsyncSocketLogLevel;\n\n#else\n\n// Logging Disabled\n\n#define LogError(frmt, ...)     {}\n#define LogWarn(frmt, ...)      {}\n#define LogInfo(frmt, ...)      {}\n#define LogVerbose(frmt, ...)   {}\n\n#define LogCError(frmt, ...)    {}\n#define LogCWarn(frmt, ...)     {}\n#define LogCInfo(frmt, ...)     {}\n#define LogCVerbose(frmt, ...)  {}\n\n#define LogTrace()              {}\n#define LogCTrace(frmt, ...)    {}\n\n#endif\n\n/**\n * Seeing a return statements within an inner block\n * can sometimes be mistaken for a return point of the enclosing method.\n * This makes inline blocks a bit easier to read.\n**/\n#define return_from_block  return\n\n/**\n * A socket file descriptor is really just an integer.\n * It represents the index of the socket within the kernel.\n * This makes invalid file descriptor comparisons easier to read.\n**/\n#define SOCKET_NULL -1\n\n\nNSString *const GCDAsyncSocketException = @\"GCDAsyncSocketException\";\nNSString *const GCDAsyncSocketErrorDomain = @\"GCDAsyncSocketErrorDomain\";\n\nNSString *const GCDAsyncSocketQueueName = @\"GCDAsyncSocket\";\nNSString *const GCDAsyncSocketThreadName = @\"GCDAsyncSocket-CFStream\";\n\nNSString *const GCDAsyncSocketManuallyEvaluateTrust = @\"GCDAsyncSocketManuallyEvaluateTrust\";\n#if TARGET_OS_IPHONE\nNSString *const GCDAsyncSocketUseCFStreamForTLS = @\"GCDAsyncSocketUseCFStreamForTLS\";\n#endif\nNSString *const GCDAsyncSocketSSLPeerID = @\"GCDAsyncSocketSSLPeerID\";\nNSString *const GCDAsyncSocketSSLProtocolVersionMin = @\"GCDAsyncSocketSSLProtocolVersionMin\";\nNSString *const GCDAsyncSocketSSLProtocolVersionMax = @\"GCDAsyncSocketSSLProtocolVersionMax\";\nNSString *const GCDAsyncSocketSSLSessionOptionFalseStart = @\"GCDAsyncSocketSSLSessionOptionFalseStart\";\nNSString *const GCDAsyncSocketSSLSessionOptionSendOneByteRecord = @\"GCDAsyncSocketSSLSessionOptionSendOneByteRecord\";\nNSString *const GCDAsyncSocketSSLCipherSuites = @\"GCDAsyncSocketSSLCipherSuites\";\n#if !TARGET_OS_IPHONE\nNSString *const GCDAsyncSocketSSLDiffieHellmanParameters = @\"GCDAsyncSocketSSLDiffieHellmanParameters\";\n#endif\n\nenum GCDAsyncSocketFlags\n{\n\tkSocketStarted                 = 1 <<  0,  // If set, socket has been started (accepting/connecting)\n\tkConnected                     = 1 <<  1,  // If set, the socket is connected\n\tkForbidReadsWrites             = 1 <<  2,  // If set, no new reads or writes are allowed\n\tkReadsPaused                   = 1 <<  3,  // If set, reads are paused due to possible timeout\n\tkWritesPaused                  = 1 <<  4,  // If set, writes are paused due to possible timeout\n\tkDisconnectAfterReads          = 1 <<  5,  // If set, disconnect after no more reads are queued\n\tkDisconnectAfterWrites         = 1 <<  6,  // If set, disconnect after no more writes are queued\n\tkSocketCanAcceptBytes          = 1 <<  7,  // If set, we know socket can accept bytes. If unset, it's unknown.\n\tkReadSourceSuspended           = 1 <<  8,  // If set, the read source is suspended\n\tkWriteSourceSuspended          = 1 <<  9,  // If set, the write source is suspended\n\tkQueuedTLS                     = 1 << 10,  // If set, we've queued an upgrade to TLS\n\tkStartingReadTLS               = 1 << 11,  // If set, we're waiting for TLS negotiation to complete\n\tkStartingWriteTLS              = 1 << 12,  // If set, we're waiting for TLS negotiation to complete\n\tkSocketSecure                  = 1 << 13,  // If set, socket is using secure communication via SSL/TLS\n\tkSocketHasReadEOF              = 1 << 14,  // If set, we have read EOF from socket\n\tkReadStreamClosed              = 1 << 15,  // If set, we've read EOF plus prebuffer has been drained\n\tkDealloc                       = 1 << 16,  // If set, the socket is being deallocated\n#if TARGET_OS_IPHONE\n\tkAddedStreamsToRunLoop         = 1 << 17,  // If set, CFStreams have been added to listener thread\n\tkUsingCFStreamForTLS           = 1 << 18,  // If set, we're forced to use CFStream instead of SecureTransport\n\tkSecureSocketHasBytesAvailable = 1 << 19,  // If set, CFReadStream has notified us of bytes available\n#endif\n};\n\nenum GCDAsyncSocketConfig\n{\n\tkIPv4Disabled              = 1 << 0,  // If set, IPv4 is disabled\n\tkIPv6Disabled              = 1 << 1,  // If set, IPv6 is disabled\n\tkPreferIPv6                = 1 << 2,  // If set, IPv6 is preferred over IPv4\n\tkAllowHalfDuplexConnection = 1 << 3,  // If set, the socket will stay open even if the read stream closes\n\tkUseStrictTimers\t\t   = 1 << 4,\n};\n\n#if TARGET_OS_IPHONE\n  static NSThread *cfstreamThread;  // Used for CFStreams\n\n\n  static uint64_t cfstreamThreadRetainCount;   // setup & teardown\n  static dispatch_queue_t cfstreamThreadSetupQueue; // setup & teardown\n#endif\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * A PreBuffer is used when there is more data available on the socket\n * than is being requested by current read request.\n * In this case we slurp up all data from the socket (to minimize sys calls),\n * and store additional yet unread data in a \"prebuffer\".\n * \n * The prebuffer is entirely drained before we read from the socket again.\n * In other words, a large chunk of data is written is written to the prebuffer.\n * The prebuffer is then drained via a series of one or more reads (for subsequent read request(s)).\n * \n * A ring buffer was once used for this purpose.\n * But a ring buffer takes up twice as much memory as needed (double the size for mirroring).\n * In fact, it generally takes up more than twice the needed size as everything has to be rounded up to vm_page_size.\n * And since the prebuffer is always completely drained after being written to, a full ring buffer isn't needed.\n * \n * The current design is very simple and straight-forward, while also keeping memory requirements lower.\n**/\n\n@interface GCDAsyncSocketPreBuffer : NSObject\n{\n\tuint8_t *preBuffer;\n\tsize_t preBufferSize;\n\t\n\tuint8_t *readPointer;\n\tuint8_t *writePointer;\n}\n\n- (id)initWithCapacity:(size_t)numBytes;\n\n- (void)ensureCapacityForWrite:(size_t)numBytes;\n\n- (size_t)availableBytes;\n- (uint8_t *)readBuffer;\n\n- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr;\n\n- (size_t)availableSpace;\n- (uint8_t *)writeBuffer;\n\n- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr;\n\n- (void)didRead:(size_t)bytesRead;\n- (void)didWrite:(size_t)bytesWritten;\n\n- (void)reset;\n\n@end\n\n@implementation GCDAsyncSocketPreBuffer\n\n- (id)initWithCapacity:(size_t)numBytes\n{\n\tif ((self = [super init]))\n\t{\n\t\tpreBufferSize = numBytes;\n\t\tpreBuffer = malloc(preBufferSize);\n\t\t\n\t\treadPointer = preBuffer;\n\t\twritePointer = preBuffer;\n\t}\n\treturn self;\n}\n\n- (void)dealloc\n{\n\tif (preBuffer)\n\t\tfree(preBuffer);\n}\n\n- (void)ensureCapacityForWrite:(size_t)numBytes\n{\n\tsize_t availableSpace = [self availableSpace];\n\t\n\tif (numBytes > availableSpace)\n\t{\n\t\tsize_t additionalBytes = numBytes - availableSpace;\n\t\t\n\t\tsize_t newPreBufferSize = preBufferSize + additionalBytes;\n\t\tuint8_t *newPreBuffer = realloc(preBuffer, newPreBufferSize);\n\t\t\n\t\tsize_t readPointerOffset = readPointer - preBuffer;\n\t\tsize_t writePointerOffset = writePointer - preBuffer;\n\t\t\n\t\tpreBuffer = newPreBuffer;\n\t\tpreBufferSize = newPreBufferSize;\n\t\t\n\t\treadPointer = preBuffer + readPointerOffset;\n\t\twritePointer = preBuffer + writePointerOffset;\n\t}\n}\n\n- (size_t)availableBytes\n{\n\treturn writePointer - readPointer;\n}\n\n- (uint8_t *)readBuffer\n{\n\treturn readPointer;\n}\n\n- (void)getReadBuffer:(uint8_t **)bufferPtr availableBytes:(size_t *)availableBytesPtr\n{\n\tif (bufferPtr) *bufferPtr = readPointer;\n\tif (availableBytesPtr) *availableBytesPtr = [self availableBytes];\n}\n\n- (void)didRead:(size_t)bytesRead\n{\n\treadPointer += bytesRead;\n\t\n\tif (readPointer == writePointer)\n\t{\n\t\t// The prebuffer has been drained. Reset pointers.\n\t\treadPointer  = preBuffer;\n\t\twritePointer = preBuffer;\n\t}\n}\n\n- (size_t)availableSpace\n{\n\treturn preBufferSize - (writePointer - preBuffer);\n}\n\n- (uint8_t *)writeBuffer\n{\n\treturn writePointer;\n}\n\n- (void)getWriteBuffer:(uint8_t **)bufferPtr availableSpace:(size_t *)availableSpacePtr\n{\n\tif (bufferPtr) *bufferPtr = writePointer;\n\tif (availableSpacePtr) *availableSpacePtr = [self availableSpace];\n}\n\n- (void)didWrite:(size_t)bytesWritten\n{\n\twritePointer += bytesWritten;\n}\n\n- (void)reset\n{\n\treadPointer  = preBuffer;\n\twritePointer = preBuffer;\n}\n\n@end\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * The GCDAsyncReadPacket encompasses the instructions for any given read.\n * The content of a read packet allows the code to determine if we're:\n *  - reading to a certain length\n *  - reading to a certain separator\n *  - or simply reading the first chunk of available data\n**/\n@interface GCDAsyncReadPacket : NSObject\n{\n  @public\n\tNSMutableData *buffer;\n\tNSUInteger startOffset;\n\tNSUInteger bytesDone;\n\tNSUInteger maxLength;\n\tNSTimeInterval timeout;\n\tNSUInteger readLength;\n\tNSData *term;\n\tBOOL bufferOwner;\n\tNSUInteger originalBufferLength;\n\tlong tag;\n}\n- (id)initWithData:(NSMutableData *)d\n       startOffset:(NSUInteger)s\n         maxLength:(NSUInteger)m\n           timeout:(NSTimeInterval)t\n        readLength:(NSUInteger)l\n        terminator:(NSData *)e\n               tag:(long)i;\n\n- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead;\n\n- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr;\n\n- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable;\n- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr;\n- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr;\n\n- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes;\n\n@end\n\n@implementation GCDAsyncReadPacket\n\n- (id)initWithData:(NSMutableData *)d\n       startOffset:(NSUInteger)s\n         maxLength:(NSUInteger)m\n           timeout:(NSTimeInterval)t\n        readLength:(NSUInteger)l\n        terminator:(NSData *)e\n               tag:(long)i\n{\n\tif((self = [super init]))\n\t{\n\t\tbytesDone = 0;\n\t\tmaxLength = m;\n\t\ttimeout = t;\n\t\treadLength = l;\n\t\tterm = [e copy];\n\t\ttag = i;\n\t\t\n\t\tif (d)\n\t\t{\n\t\t\tbuffer = d;\n\t\t\tstartOffset = s;\n\t\t\tbufferOwner = NO;\n\t\t\toriginalBufferLength = [d length];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (readLength > 0)\n\t\t\t\tbuffer = [[NSMutableData alloc] initWithLength:readLength];\n\t\t\telse\n\t\t\t\tbuffer = [[NSMutableData alloc] initWithLength:0];\n\t\t\t\n\t\t\tstartOffset = 0;\n\t\t\tbufferOwner = YES;\n\t\t\toriginalBufferLength = 0;\n\t\t}\n\t}\n\treturn self;\n}\n\n/**\n * Increases the length of the buffer (if needed) to ensure a read of the given size will fit.\n**/\n- (void)ensureCapacityForAdditionalDataOfLength:(NSUInteger)bytesToRead\n{\n\tNSUInteger buffSize = [buffer length];\n\tNSUInteger buffUsed = startOffset + bytesDone;\n\t\n\tNSUInteger buffSpace = buffSize - buffUsed;\n\t\n\tif (bytesToRead > buffSpace)\n\t{\n\t\tNSUInteger buffInc = bytesToRead - buffSpace;\n\t\t\n\t\t[buffer increaseLengthBy:buffInc];\n\t}\n}\n\n/**\n * This method is used when we do NOT know how much data is available to be read from the socket.\n * This method returns the default value unless it exceeds the specified readLength or maxLength.\n * \n * Furthermore, the shouldPreBuffer decision is based upon the packet type,\n * and whether the returned value would fit in the current buffer without requiring a resize of the buffer.\n**/\n- (NSUInteger)optimalReadLengthWithDefault:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr\n{\n\tNSUInteger result;\n\t\n\tif (readLength > 0)\n\t{\n\t\t// Read a specific length of data\n\t\t\n\t\tresult = MIN(defaultValue, (readLength - bytesDone));\n\t\t\n\t\t// There is no need to prebuffer since we know exactly how much data we need to read.\n\t\t// Even if the buffer isn't currently big enough to fit this amount of data,\n\t\t// it would have to be resized eventually anyway.\n\t\t\n\t\tif (shouldPreBufferPtr)\n\t\t\t*shouldPreBufferPtr = NO;\n\t}\n\telse\n\t{\n\t\t// Either reading until we find a specified terminator,\n\t\t// or we're simply reading all available data.\n\t\t// \n\t\t// In other words, one of:\n\t\t// \n\t\t// - readDataToData packet\n\t\t// - readDataWithTimeout packet\n\t\t\n\t\tif (maxLength > 0)\n\t\t\tresult =  MIN(defaultValue, (maxLength - bytesDone));\n\t\telse\n\t\t\tresult = defaultValue;\n\t\t\n\t\t// Since we don't know the size of the read in advance,\n\t\t// the shouldPreBuffer decision is based upon whether the returned value would fit\n\t\t// in the current buffer without requiring a resize of the buffer.\n\t\t// \n\t\t// This is because, in all likelyhood, the amount read from the socket will be less than the default value.\n\t\t// Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead.\n\t\t\n\t\tif (shouldPreBufferPtr)\n\t\t{\n\t\t\tNSUInteger buffSize = [buffer length];\n\t\t\tNSUInteger buffUsed = startOffset + bytesDone;\n\t\t\t\n\t\t\tNSUInteger buffSpace = buffSize - buffUsed;\n\t\t\t\n\t\t\tif (buffSpace >= result)\n\t\t\t\t*shouldPreBufferPtr = NO;\n\t\t\telse\n\t\t\t\t*shouldPreBufferPtr = YES;\n\t\t}\n\t}\n\t\n\treturn result;\n}\n\n/**\n * For read packets without a set terminator, returns the amount of data\n * that can be read without exceeding the readLength or maxLength.\n * \n * The given parameter indicates the number of bytes estimated to be available on the socket,\n * which is taken into consideration during the calculation.\n * \n * The given hint MUST be greater than zero.\n**/\n- (NSUInteger)readLengthForNonTermWithHint:(NSUInteger)bytesAvailable\n{\n\tNSAssert(term == nil, @\"This method does not apply to term reads\");\n\tNSAssert(bytesAvailable > 0, @\"Invalid parameter: bytesAvailable\");\n\t\n\tif (readLength > 0)\n\t{\n\t\t// Read a specific length of data\n\t\t\n\t\treturn (readLength - bytesDone);\n\t\t\n\t\t// No need to avoid resizing the buffer.\n\t\t// If the user provided their own buffer,\n\t\t// and told us to read a certain length of data that exceeds the size of the buffer,\n\t\t// then it is clear that our code will resize the buffer during the read operation.\n\t\t// \n\t\t// This method does not actually do any resizing.\n\t\t// The resizing will happen elsewhere if needed.\n\t}\n\telse\n\t{\n\t\t// Read all available data\n\t\t\n\t\tNSUInteger result = bytesAvailable;\n\t\t\n\t\tif (maxLength > 0)\n\t\t{\n\t\t\tresult = MIN(result, (maxLength - bytesDone));\n\t\t}\n\t\t\n\t\t// No need to avoid resizing the buffer.\n\t\t// If the user provided their own buffer,\n\t\t// and told us to read all available data without giving us a maxLength,\n\t\t// then it is clear that our code might resize the buffer during the read operation.\n\t\t// \n\t\t// This method does not actually do any resizing.\n\t\t// The resizing will happen elsewhere if needed.\n\t\t\n\t\treturn result;\n\t}\n}\n\n/**\n * For read packets with a set terminator, returns the amount of data\n * that can be read without exceeding the maxLength.\n * \n * The given parameter indicates the number of bytes estimated to be available on the socket,\n * which is taken into consideration during the calculation.\n * \n * To optimize memory allocations, mem copies, and mem moves\n * the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first,\n * or if the data can be read directly into the read packet's buffer.\n**/\n- (NSUInteger)readLengthForTermWithHint:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr\n{\n\tNSAssert(term != nil, @\"This method does not apply to non-term reads\");\n\tNSAssert(bytesAvailable > 0, @\"Invalid parameter: bytesAvailable\");\n\t\n\t\n\tNSUInteger result = bytesAvailable;\n\t\n\tif (maxLength > 0)\n\t{\n\t\tresult = MIN(result, (maxLength - bytesDone));\n\t}\n\t\n\t// Should the data be read into the read packet's buffer, or into a pre-buffer first?\n\t// \n\t// One would imagine the preferred option is the faster one.\n\t// So which one is faster?\n\t// \n\t// Reading directly into the packet's buffer requires:\n\t// 1. Possibly resizing packet buffer (malloc/realloc)\n\t// 2. Filling buffer (read)\n\t// 3. Searching for term (memcmp)\n\t// 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy)\n\t// \n\t// Reading into prebuffer first:\n\t// 1. Possibly resizing prebuffer (malloc/realloc)\n\t// 2. Filling buffer (read)\n\t// 3. Searching for term (memcmp)\n\t// 4. Copying underflow into packet buffer (malloc/realloc, memcpy)\n\t// 5. Removing underflow from prebuffer (memmove)\n\t// \n\t// Comparing the performance of the two we can see that reading\n\t// data into the prebuffer first is slower due to the extra memove.\n\t// \n\t// However:\n\t// The implementation of NSMutableData is open source via core foundation's CFMutableData.\n\t// Decreasing the length of a mutable data object doesn't cause a realloc.\n\t// In other words, the capacity of a mutable data object can grow, but doesn't shrink.\n\t// \n\t// This means the prebuffer will rarely need a realloc.\n\t// The packet buffer, on the other hand, may often need a realloc.\n\t// This is especially true if we are the buffer owner.\n\t// Furthermore, if we are constantly realloc'ing the packet buffer,\n\t// and then moving the overflow into the prebuffer,\n\t// then we're consistently over-allocating memory for each term read.\n\t// And now we get into a bit of a tradeoff between speed and memory utilization.\n\t// \n\t// The end result is that the two perform very similarly.\n\t// And we can answer the original question very simply by another means.\n\t// \n\t// If we can read all the data directly into the packet's buffer without resizing it first,\n\t// then we do so. Otherwise we use the prebuffer.\n\t\n\tif (shouldPreBufferPtr)\n\t{\n\t\tNSUInteger buffSize = [buffer length];\n\t\tNSUInteger buffUsed = startOffset + bytesDone;\n\t\t\n\t\tif ((buffSize - buffUsed) >= result)\n\t\t\t*shouldPreBufferPtr = NO;\n\t\telse\n\t\t\t*shouldPreBufferPtr = YES;\n\t}\n\t\n\treturn result;\n}\n\n/**\n * For read packets with a set terminator,\n * returns the amount of data that can be read from the given preBuffer,\n * without going over a terminator or the maxLength.\n * \n * It is assumed the terminator has not already been read.\n**/\n- (NSUInteger)readLengthForTermWithPreBuffer:(GCDAsyncSocketPreBuffer *)preBuffer found:(BOOL *)foundPtr\n{\n\tNSAssert(term != nil, @\"This method does not apply to non-term reads\");\n\tNSAssert([preBuffer availableBytes] > 0, @\"Invoked with empty pre buffer!\");\n\t\n\t// We know that the terminator, as a whole, doesn't exist in our own buffer.\n\t// But it is possible that a _portion_ of it exists in our buffer.\n\t// So we're going to look for the terminator starting with a portion of our own buffer.\n\t// \n\t// Example:\n\t// \n\t// term length      = 3 bytes\n\t// bytesDone        = 5 bytes\n\t// preBuffer length = 5 bytes\n\t// \n\t// If we append the preBuffer to our buffer,\n\t// it would look like this:\n\t// \n\t// ---------------------\n\t// |B|B|B|B|B|P|P|P|P|P|\n\t// ---------------------\n\t// \n\t// So we start our search here:\n\t// \n\t// ---------------------\n\t// |B|B|B|B|B|P|P|P|P|P|\n\t// -------^-^-^---------\n\t// \n\t// And move forwards...\n\t// \n\t// ---------------------\n\t// |B|B|B|B|B|P|P|P|P|P|\n\t// ---------^-^-^-------\n\t// \n\t// Until we find the terminator or reach the end.\n\t// \n\t// ---------------------\n\t// |B|B|B|B|B|P|P|P|P|P|\n\t// ---------------^-^-^-\n\t\n\tBOOL found = NO;\n\t\n\tNSUInteger termLength = [term length];\n\tNSUInteger preBufferLength = [preBuffer availableBytes];\n\t\n\tif ((bytesDone + preBufferLength) < termLength)\n\t{\n\t\t// Not enough data for a full term sequence yet\n\t\treturn preBufferLength;\n\t}\n\t\n\tNSUInteger maxPreBufferLength;\n\tif (maxLength > 0) {\n\t\tmaxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone));\n\t\t\n\t\t// Note: maxLength >= termLength\n\t}\n\telse {\n\t\tmaxPreBufferLength = preBufferLength;\n\t}\n\t\n\tuint8_t seq[termLength];\n\tconst void *termBuf = [term bytes];\n\t\n\tNSUInteger bufLen = MIN(bytesDone, (termLength - 1));\n\tuint8_t *buf = (uint8_t *)[buffer mutableBytes] + startOffset + bytesDone - bufLen;\n\t\n\tNSUInteger preLen = termLength - bufLen;\n\tconst uint8_t *pre = [preBuffer readBuffer];\n\t\n\tNSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above.\n\t\n\tNSUInteger result = maxPreBufferLength;\n\t\n\tNSUInteger i;\n\tfor (i = 0; i < loopCount; i++)\n\t{\n\t\tif (bufLen > 0)\n\t\t{\n\t\t\t// Combining bytes from buffer and preBuffer\n\t\t\t\n\t\t\tmemcpy(seq, buf, bufLen);\n\t\t\tmemcpy(seq + bufLen, pre, preLen);\n\t\t\t\n\t\t\tif (memcmp(seq, termBuf, termLength) == 0)\n\t\t\t{\n\t\t\t\tresult = preLen;\n\t\t\t\tfound = YES;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tbuf++;\n\t\t\tbufLen--;\n\t\t\tpreLen++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Comparing directly from preBuffer\n\t\t\t\n\t\t\tif (memcmp(pre, termBuf, termLength) == 0)\n\t\t\t{\n\t\t\t\tNSUInteger preOffset = pre - [preBuffer readBuffer]; // pointer arithmetic\n\t\t\t\t\n\t\t\t\tresult = preOffset + termLength;\n\t\t\t\tfound = YES;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tpre++;\n\t\t}\n\t}\n\t\n\t// There is no need to avoid resizing the buffer in this particular situation.\n\t\n\tif (foundPtr) *foundPtr = found;\n\treturn result;\n}\n\n/**\n * For read packets with a set terminator, scans the packet buffer for the term.\n * It is assumed the terminator had not been fully read prior to the new bytes.\n * \n * If the term is found, the number of excess bytes after the term are returned.\n * If the term is not found, this method will return -1.\n * \n * Note: A return value of zero means the term was found at the very end.\n * \n * Prerequisites:\n * The given number of bytes have been added to the end of our buffer.\n * Our bytesDone variable has NOT been changed due to the prebuffered bytes.\n**/\n- (NSInteger)searchForTermAfterPreBuffering:(ssize_t)numBytes\n{\n\tNSAssert(term != nil, @\"This method does not apply to non-term reads\");\n\t\n\t// The implementation of this method is very similar to the above method.\n\t// See the above method for a discussion of the algorithm used here.\n\t\n\tuint8_t *buff = [buffer mutableBytes];\n\tNSUInteger buffLength = bytesDone + numBytes;\n\t\n\tconst void *termBuff = [term bytes];\n\tNSUInteger termLength = [term length];\n\t\n\t// Note: We are dealing with unsigned integers,\n\t// so make sure the math doesn't go below zero.\n\t\n\tNSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0;\n\t\n\twhile (i + termLength <= buffLength)\n\t{\n\t\tuint8_t *subBuffer = buff + startOffset + i;\n\t\t\n\t\tif (memcmp(subBuffer, termBuff, termLength) == 0)\n\t\t{\n\t\t\treturn buffLength - (i + termLength);\n\t\t}\n\t\t\n\t\ti++;\n\t}\n\t\n\treturn -1;\n}\n\n\n@end\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * The GCDAsyncWritePacket encompasses the instructions for any given write.\n**/\n@interface GCDAsyncWritePacket : NSObject\n{\n  @public\n\tNSData *buffer;\n\tNSUInteger bytesDone;\n\tlong tag;\n\tNSTimeInterval timeout;\n}\n- (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i;\n@end\n\n@implementation GCDAsyncWritePacket\n\n- (id)initWithData:(NSData *)d timeout:(NSTimeInterval)t tag:(long)i\n{\n\tif((self = [super init]))\n\t{\n\t\tbuffer = d; // Retain not copy. For performance as documented in header file.\n\t\tbytesDone = 0;\n\t\ttimeout = t;\n\t\ttag = i;\n\t}\n\treturn self;\n}\n\n\n@end\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * The GCDAsyncSpecialPacket encompasses special instructions for interruptions in the read/write queues.\n * This class my be altered to support more than just TLS in the future.\n**/\n@interface GCDAsyncSpecialPacket : NSObject\n{\n  @public\n\tNSDictionary *tlsSettings;\n}\n- (id)initWithTLSSettings:(NSDictionary *)settings;\n@end\n\n@implementation GCDAsyncSpecialPacket\n\n- (id)initWithTLSSettings:(NSDictionary *)settings\n{\n\tif((self = [super init]))\n\t{\n\t\ttlsSettings = [settings copy];\n\t}\n\treturn self;\n}\n\n\n@end\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark -\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n@implementation GCDAsyncSocket\n{\n\tuint32_t flags;\n\tuint16_t config;\n\t\n\t__weak id<GCDAsyncSocketDelegate> delegate;\n\tdispatch_queue_t delegateQueue;\n\t\n\tint socket4FD;\n\tint socket6FD;\n\tint socketUN;\n\tNSURL *socketUrl;\n\tint stateIndex;\n\tNSData * connectInterface4;\n\tNSData * connectInterface6;\n\tNSData * connectInterfaceUN;\n\t\n\tdispatch_queue_t socketQueue;\n\t\n\tdispatch_source_t accept4Source;\n\tdispatch_source_t accept6Source;\n\tdispatch_source_t acceptUNSource;\n\tdispatch_source_t connectTimer;\n\tdispatch_source_t readSource;\n\tdispatch_source_t writeSource;\n\tdispatch_source_t readTimer;\n\tdispatch_source_t writeTimer;\n\t\n\tNSMutableArray *readQueue;\n\tNSMutableArray *writeQueue;\n\t\n\tGCDAsyncReadPacket *currentRead;\n\tGCDAsyncWritePacket *currentWrite;\n\t\n\tunsigned long socketFDBytesAvailable;\n\t\n\tGCDAsyncSocketPreBuffer *preBuffer;\n\t\t\n#if TARGET_OS_IPHONE\n\tCFStreamClientContext streamContext;\n\tCFReadStreamRef readStream;\n\tCFWriteStreamRef writeStream;\n#endif\n\tSSLContextRef sslContext;\n\tGCDAsyncSocketPreBuffer *sslPreBuffer;\n\tsize_t sslWriteCachedLength;\n\tOSStatus sslErrCode;\n    OSStatus lastSSLHandshakeError;\n\t\n\tvoid *IsOnSocketQueueOrTargetQueueKey;\n\t\n\tid userData;\n    NSTimeInterval alternateAddressDelay;\n}\n\n- (id)init\n{\n\treturn [self initWithDelegate:nil delegateQueue:NULL socketQueue:NULL];\n}\n\n- (id)initWithSocketQueue:(dispatch_queue_t)sq\n{\n\treturn [self initWithDelegate:nil delegateQueue:NULL socketQueue:sq];\n}\n\n- (id)initWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq\n{\n\treturn [self initWithDelegate:aDelegate delegateQueue:dq socketQueue:NULL];\n}\n\n- (id)initWithDelegate:(id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq\n{\n\tif((self = [super init]))\n\t{\n\t\tdelegate = aDelegate;\n\t\tdelegateQueue = dq;\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tif (dq) dispatch_retain(dq);\n\t\t#endif\n\t\t\n\t\tsocket4FD = SOCKET_NULL;\n\t\tsocket6FD = SOCKET_NULL;\n\t\tsocketUN = SOCKET_NULL;\n\t\tsocketUrl = nil;\n\t\tstateIndex = 0;\n\t\t\n\t\tif (sq)\n\t\t{\n\t\t\tNSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),\n\t\t\t         @\"The given socketQueue parameter must not be a concurrent queue.\");\n\t\t\tNSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),\n\t\t\t         @\"The given socketQueue parameter must not be a concurrent queue.\");\n\t\t\tNSAssert(sq != dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),\n\t\t\t         @\"The given socketQueue parameter must not be a concurrent queue.\");\n\t\t\t\n\t\t\tsocketQueue = sq;\n\t\t\t#if !OS_OBJECT_USE_OBJC\n\t\t\tdispatch_retain(sq);\n\t\t\t#endif\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsocketQueue = dispatch_queue_create([GCDAsyncSocketQueueName UTF8String], NULL);\n\t\t}\n\t\t\n\t\t// The dispatch_queue_set_specific() and dispatch_get_specific() functions take a \"void *key\" parameter.\n\t\t// From the documentation:\n\t\t//\n\t\t// > Keys are only compared as pointers and are never dereferenced.\n\t\t// > Thus, you can use a pointer to a static variable for a specific subsystem or\n\t\t// > any other value that allows you to identify the value uniquely.\n\t\t//\n\t\t// We're just going to use the memory address of an ivar.\n\t\t// Specifically an ivar that is explicitly named for our purpose to make the code more readable.\n\t\t//\n\t\t// However, it feels tedious (and less readable) to include the \"&\" all the time:\n\t\t// dispatch_get_specific(&IsOnSocketQueueOrTargetQueueKey)\n\t\t//\n\t\t// So we're going to make it so it doesn't matter if we use the '&' or not,\n\t\t// by assigning the value of the ivar to the address of the ivar.\n\t\t// Thus: IsOnSocketQueueOrTargetQueueKey == &IsOnSocketQueueOrTargetQueueKey;\n\t\t\n\t\tIsOnSocketQueueOrTargetQueueKey = &IsOnSocketQueueOrTargetQueueKey;\n\t\t\n\t\tvoid *nonNullUnusedPointer = (__bridge void *)self;\n\t\tdispatch_queue_set_specific(socketQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);\n\t\t\n\t\treadQueue = [[NSMutableArray alloc] initWithCapacity:5];\n\t\tcurrentRead = nil;\n\t\t\n\t\twriteQueue = [[NSMutableArray alloc] initWithCapacity:5];\n\t\tcurrentWrite = nil;\n\t\t\n\t\tpreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];\n        alternateAddressDelay = 0.3;\n\t}\n\treturn self;\n}\n\n- (void)dealloc\n{\n\tLogInfo(@\"%@ - %@ (start)\", THIS_METHOD, self);\n\t\n\t// Set dealloc flag.\n\t// This is used by closeWithError to ensure we don't accidentally retain ourself.\n\tflags |= kDealloc;\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\t[self closeWithError:nil];\n\t}\n\telse\n\t{\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\t[self closeWithError:nil];\n\t\t});\n\t}\n\t\n\tdelegate = nil;\n\t\n\t#if !OS_OBJECT_USE_OBJC\n\tif (delegateQueue) dispatch_release(delegateQueue);\n\t#endif\n\tdelegateQueue = NULL;\n\t\n\t#if !OS_OBJECT_USE_OBJC\n\tif (socketQueue) dispatch_release(socketQueue);\n\t#endif\n\tsocketQueue = NULL;\n\t\n\tLogInfo(@\"%@ - %@ (finish)\", THIS_METHOD, self);\n}\n\n#pragma mark -\n\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD socketQueue:(nullable dispatch_queue_t)sq error:(NSError**)error {\n  return [self socketFromConnectedSocketFD:socketFD delegate:nil delegateQueue:NULL socketQueue:sq error:error];\n}\n\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq error:(NSError**)error {\n  return [self socketFromConnectedSocketFD:socketFD delegate:aDelegate delegateQueue:dq socketQueue:NULL error:error];\n}\n\n+ (nullable instancetype)socketFromConnectedSocketFD:(int)socketFD delegate:(nullable id<GCDAsyncSocketDelegate>)aDelegate delegateQueue:(nullable dispatch_queue_t)dq socketQueue:(nullable dispatch_queue_t)sq error:(NSError* __autoreleasing *)error\n{\n  __block BOOL errorOccured = NO;\n  \n  GCDAsyncSocket *socket = [[[self class] alloc] initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq];\n  \n  dispatch_sync(socket->socketQueue, ^{ @autoreleasepool {\n    struct sockaddr addr;\n    socklen_t addr_size = sizeof(struct sockaddr);\n    int retVal = getpeername(socketFD, (struct sockaddr *)&addr, &addr_size);\n    if (retVal)\n    {\n      NSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketOtherError\",\n                                                           @\"GCDAsyncSocket\", [NSBundle mainBundle],\n                                                           @\"Attempt to create socket from socket FD failed. getpeername() failed\", nil);\n      \n      NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\n      errorOccured = YES;\n      if (error)\n        *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];\n      return;\n    }\n    \n    if (addr.sa_family == AF_INET)\n    {\n      socket->socket4FD = socketFD;\n    }\n    else if (addr.sa_family == AF_INET6)\n    {\n      socket->socket6FD = socketFD;\n    }\n    else\n    {\n      NSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketOtherError\",\n                                                           @\"GCDAsyncSocket\", [NSBundle mainBundle],\n                                                           @\"Attempt to create socket from socket FD failed. socket FD is neither IPv4 nor IPv6\", nil);\n      \n      NSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n      \n      errorOccured = YES;\n      if (error)\n        *error = [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];\n      return;\n    }\n    \n    socket->flags = kSocketStarted;\n    [socket didConnect:socket->stateIndex];\n  }});\n  \n  return errorOccured? nil: socket;\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Configuration\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (id)delegate\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn delegate;\n\t}\n\telse\n\t{\n\t\t__block id result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = delegate;\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (void)setDelegate:(id)newDelegate synchronously:(BOOL)synchronously\n{\n\tdispatch_block_t block = ^{\n\t\tdelegate = newDelegate;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {\n\t\tblock();\n\t}\n\telse {\n\t\tif (synchronously)\n\t\t\tdispatch_sync(socketQueue, block);\n\t\telse\n\t\t\tdispatch_async(socketQueue, block);\n\t}\n}\n\n- (void)setDelegate:(id)newDelegate\n{\n\t[self setDelegate:newDelegate synchronously:NO];\n}\n\n- (void)synchronouslySetDelegate:(id)newDelegate\n{\n\t[self setDelegate:newDelegate synchronously:YES];\n}\n\n- (dispatch_queue_t)delegateQueue\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn delegateQueue;\n\t}\n\telse\n\t{\n\t\t__block dispatch_queue_t result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = delegateQueue;\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously\n{\n\tdispatch_block_t block = ^{\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tif (delegateQueue) dispatch_release(delegateQueue);\n\t\tif (newDelegateQueue) dispatch_retain(newDelegateQueue);\n\t\t#endif\n\t\t\n\t\tdelegateQueue = newDelegateQueue;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {\n\t\tblock();\n\t}\n\telse {\n\t\tif (synchronously)\n\t\t\tdispatch_sync(socketQueue, block);\n\t\telse\n\t\t\tdispatch_async(socketQueue, block);\n\t}\n}\n\n- (void)setDelegateQueue:(dispatch_queue_t)newDelegateQueue\n{\n\t[self setDelegateQueue:newDelegateQueue synchronously:NO];\n}\n\n- (void)synchronouslySetDelegateQueue:(dispatch_queue_t)newDelegateQueue\n{\n\t[self setDelegateQueue:newDelegateQueue synchronously:YES];\n}\n\n- (void)getDelegate:(id<GCDAsyncSocketDelegate> *)delegatePtr delegateQueue:(dispatch_queue_t *)delegateQueuePtr\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (delegatePtr) *delegatePtr = delegate;\n\t\tif (delegateQueuePtr) *delegateQueuePtr = delegateQueue;\n\t}\n\telse\n\t{\n\t\t__block id dPtr = NULL;\n\t\t__block dispatch_queue_t dqPtr = NULL;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tdPtr = delegate;\n\t\t\tdqPtr = delegateQueue;\n\t\t});\n\t\t\n\t\tif (delegatePtr) *delegatePtr = dPtr;\n\t\tif (delegateQueuePtr) *delegateQueuePtr = dqPtr;\n\t}\n}\n\n- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue synchronously:(BOOL)synchronously\n{\n\tdispatch_block_t block = ^{\n\t\t\n\t\tdelegate = newDelegate;\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tif (delegateQueue) dispatch_release(delegateQueue);\n\t\tif (newDelegateQueue) dispatch_retain(newDelegateQueue);\n\t\t#endif\n\t\t\n\t\tdelegateQueue = newDelegateQueue;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey)) {\n\t\tblock();\n\t}\n\telse {\n\t\tif (synchronously)\n\t\t\tdispatch_sync(socketQueue, block);\n\t\telse\n\t\t\tdispatch_async(socketQueue, block);\n\t}\n}\n\n- (void)setDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue\n{\n\t[self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:NO];\n}\n\n- (void)synchronouslySetDelegate:(id)newDelegate delegateQueue:(dispatch_queue_t)newDelegateQueue\n{\n\t[self setDelegate:newDelegate delegateQueue:newDelegateQueue synchronously:YES];\n}\n\n- (BOOL)isIPv4Enabled\n{\n\t// Note: YES means kIPv4Disabled is OFF\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn ((config & kIPv4Disabled) == 0);\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = ((config & kIPv4Disabled) == 0);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (void)setIPv4Enabled:(BOOL)flag\n{\n\t// Note: YES means kIPv4Disabled is OFF\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (flag)\n\t\t\tconfig &= ~kIPv4Disabled;\n\t\telse\n\t\t\tconfig |= kIPv4Disabled;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n- (BOOL)isIPv6Enabled\n{\n\t// Note: YES means kIPv6Disabled is OFF\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn ((config & kIPv6Disabled) == 0);\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = ((config & kIPv6Disabled) == 0);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (void)setIPv6Enabled:(BOOL)flag\n{\n\t// Note: YES means kIPv6Disabled is OFF\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (flag)\n\t\t\tconfig &= ~kIPv6Disabled;\n\t\telse\n\t\t\tconfig |= kIPv6Disabled;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n- (BOOL)isIPv4PreferredOverIPv6\n{\n\t// Note: YES means kPreferIPv6 is OFF\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn ((config & kPreferIPv6) == 0);\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = ((config & kPreferIPv6) == 0);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (void)setIPv4PreferredOverIPv6:(BOOL)flag\n{\n\t// Note: YES means kPreferIPv6 is OFF\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (flag)\n\t\t\tconfig &= ~kPreferIPv6;\n\t\telse\n\t\t\tconfig |= kPreferIPv6;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n- (NSTimeInterval) alternateAddressDelay {\n    __block NSTimeInterval delay;\n    dispatch_block_t block = ^{\n        delay = alternateAddressDelay;\n    };\n    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n        block();\n    else\n        dispatch_sync(socketQueue, block);\n    return delay;\n}\n\n- (void) setAlternateAddressDelay:(NSTimeInterval)delay {\n    dispatch_block_t block = ^{\n        alternateAddressDelay = delay;\n    };\n    if (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n        block();\n    else\n        dispatch_async(socketQueue, block);\n}\n\n- (id)userData\n{\n\t__block id result = nil;\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tresult = userData;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n- (void)setUserData:(id)arbitraryUserData\n{\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (userData != arbitraryUserData)\n\t\t{\n\t\t\tuserData = arbitraryUserData;\n\t\t}\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Accepting\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr\n{\n\treturn [self acceptOnInterface:nil port:port error:errPtr];\n}\n\n- (BOOL)acceptOnInterface:(NSString *)inInterface port:(uint16_t)port error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\t// Just in-case interface parameter is immutable.\n\tNSString *interface = [inInterface copy];\n\t\n\t__block BOOL result = NO;\n\t__block NSError *err = nil;\n\t\n\t// CreateSocket Block\n\t// This block will be invoked within the dispatch block below.\n\t\n\tint(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {\n\t\t\n\t\tint socketFD = socket(domain, SOCK_STREAM, 0);\n\t\t\n\t\tif (socketFD == SOCKET_NULL)\n\t\t{\n\t\t\tNSString *reason = @\"Error in socket() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\tint status;\n\t\t\n\t\t// Set socket options\n\t\t\n\t\tstatus = fcntl(socketFD, F_SETFL, O_NONBLOCK);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error enabling non-blocking IO on socket (fcntl)\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\tint reuseOn = 1;\n\t\tstatus = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error enabling address reuse (setsockopt)\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\t// Bind socket\n\t\t\n\t\tstatus = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error in bind() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\t// Listen\n\t\t\n\t\tstatus = listen(socketFD, 1024);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error in listen() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\treturn socketFD;\n\t};\n\t\n\t// Create dispatch block and run on socketQueue\n\t\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\tif (delegate == nil) // Must have delegate set\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept without a delegate. Set a delegate first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (delegateQueue == NULL) // Must have delegate queue set\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept without a delegate queue. Set a delegate queue first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tBOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;\n\t\tBOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;\n\t\t\n\t\tif (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled\n\t\t{\n\t\t\tNSString *msg = @\"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (![self isDisconnected]) // Must be disconnected\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept while connected or accepting connections. Disconnect first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Clear queues (spurious read/write requests post disconnect)\n\t\t[readQueue removeAllObjects];\n\t\t[writeQueue removeAllObjects];\n\t\t\n\t\t// Resolve interface from description\n\t\t\n\t\tNSMutableData *interface4 = nil;\n\t\tNSMutableData *interface6 = nil;\n\t\t\n\t\t[self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:port];\n\t\t\n\t\tif ((interface4 == nil) && (interface6 == nil))\n\t\t{\n\t\t\tNSString *msg = @\"Unknown interface. Specify valid interface by name (e.g. \\\"en1\\\") or IP address.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (isIPv4Disabled && (interface6 == nil))\n\t\t{\n\t\t\tNSString *msg = @\"IPv4 has been disabled and specified interface doesn't support IPv6.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (isIPv6Disabled && (interface4 == nil))\n\t\t{\n\t\t\tNSString *msg = @\"IPv6 has been disabled and specified interface doesn't support IPv4.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tBOOL enableIPv4 = !isIPv4Disabled && (interface4 != nil);\n\t\tBOOL enableIPv6 = !isIPv6Disabled && (interface6 != nil);\n\t\t\n\t\t// Create sockets, configure, bind, and listen\n\t\t\n\t\tif (enableIPv4)\n\t\t{\n\t\t\tLogVerbose(@\"Creating IPv4 socket\");\n\t\t\tsocket4FD = createSocket(AF_INET, interface4);\n\t\t\t\n\t\t\tif (socket4FD == SOCKET_NULL)\n\t\t\t{\n\t\t\t\treturn_from_block;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (enableIPv6)\n\t\t{\n\t\t\tLogVerbose(@\"Creating IPv6 socket\");\n\t\t\t\n\t\t\tif (enableIPv4 && (port == 0))\n\t\t\t{\n\t\t\t\t// No specific port was specified, so we allowed the OS to pick an available port for us.\n\t\t\t\t// Now we need to make sure the IPv6 socket listens on the same port as the IPv4 socket.\n\t\t\t\t\n\t\t\t\tstruct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)[interface6 mutableBytes];\n\t\t\t\taddr6->sin6_port = htons([self localPort4]);\n\t\t\t}\n\t\t\t\n\t\t\tsocket6FD = createSocket(AF_INET6, interface6);\n\t\t\t\n\t\t\tif (socket6FD == SOCKET_NULL)\n\t\t\t{\n\t\t\t\tif (socket4FD != SOCKET_NULL)\n\t\t\t\t{\n\t\t\t\t\tLogVerbose(@\"close(socket4FD)\");\n\t\t\t\t\tclose(socket4FD);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\treturn_from_block;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Create accept sources\n\t\t\n\t\tif (enableIPv4)\n\t\t{\n\t\t\taccept4Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket4FD, 0, socketQueue);\n\t\t\t\n\t\t\tint socketFD = socket4FD;\n\t\t\tdispatch_source_t acceptSource = accept4Source;\n\t\t\t\n\t\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\t\n\t\t\tdispatch_source_set_event_handler(accept4Source, ^{ @autoreleasepool {\n\t\t\t#pragma clang diagnostic push\n\t\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\t\n\t\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"event4Block\");\n\t\t\t\t\n\t\t\t\tunsigned long i = 0;\n\t\t\t\tunsigned long numPendingConnections = dispatch_source_get_data(acceptSource);\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"numPendingConnections: %lu\", numPendingConnections);\n\t\t\t\t\n\t\t\t\twhile ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));\n\t\t\t\t\n\t\t\t#pragma clang diagnostic pop\n\t\t\t}});\n\t\t\t\n\t\t\t\n\t\t\tdispatch_source_set_cancel_handler(accept4Source, ^{\n\t\t\t#pragma clang diagnostic push\n\t\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\t\n\t\t\t\t#if !OS_OBJECT_USE_OBJC\n\t\t\t\tLogVerbose(@\"dispatch_release(accept4Source)\");\n\t\t\t\tdispatch_release(acceptSource);\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"close(socket4FD)\");\n\t\t\t\tclose(socketFD);\n\t\t\t\n\t\t\t#pragma clang diagnostic pop\n\t\t\t});\n\t\t\t\n\t\t\tLogVerbose(@\"dispatch_resume(accept4Source)\");\n\t\t\tdispatch_resume(accept4Source);\n\t\t}\n\t\t\n\t\tif (enableIPv6)\n\t\t{\n\t\t\taccept6Source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socket6FD, 0, socketQueue);\n\t\t\t\n\t\t\tint socketFD = socket6FD;\n\t\t\tdispatch_source_t acceptSource = accept6Source;\n\t\t\t\n\t\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\t\n\t\t\tdispatch_source_set_event_handler(accept6Source, ^{ @autoreleasepool {\n\t\t\t#pragma clang diagnostic push\n\t\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\t\n\t\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"event6Block\");\n\t\t\t\t\n\t\t\t\tunsigned long i = 0;\n\t\t\t\tunsigned long numPendingConnections = dispatch_source_get_data(acceptSource);\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"numPendingConnections: %lu\", numPendingConnections);\n\t\t\t\t\n\t\t\t\twhile ([strongSelf doAccept:socketFD] && (++i < numPendingConnections));\n\t\t\t\t\n\t\t\t#pragma clang diagnostic pop\n\t\t\t}});\n\t\t\t\n\t\t\tdispatch_source_set_cancel_handler(accept6Source, ^{\n\t\t\t#pragma clang diagnostic push\n\t\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\t\n\t\t\t\t#if !OS_OBJECT_USE_OBJC\n\t\t\t\tLogVerbose(@\"dispatch_release(accept6Source)\");\n\t\t\t\tdispatch_release(acceptSource);\n\t\t\t\t#endif\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"close(socket6FD)\");\n\t\t\t\tclose(socketFD);\n\t\t\t\t\n\t\t\t#pragma clang diagnostic pop\n\t\t\t});\n\t\t\t\n\t\t\tLogVerbose(@\"dispatch_resume(accept6Source)\");\n\t\t\tdispatch_resume(accept6Source);\n\t\t}\n\t\t\n\t\tflags |= kSocketStarted;\n\t\t\n\t\tresult = YES;\n\t}};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\tif (result == NO)\n\t{\n\t\tLogInfo(@\"Error in accept: %@\", err);\n\t\t\n\t\tif (errPtr)\n\t\t\t*errPtr = err;\n\t}\n\t\n\treturn result;\n}\n\n- (BOOL)acceptOnUrl:(NSURL *)url error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\t__block BOOL result = NO;\n\t__block NSError *err = nil;\n\t\n\t// CreateSocket Block\n\t// This block will be invoked within the dispatch block below.\n\t\n\tint(^createSocket)(int, NSData*) = ^int (int domain, NSData *interfaceAddr) {\n\t\t\n\t\tint socketFD = socket(domain, SOCK_STREAM, 0);\n\t\t\n\t\tif (socketFD == SOCKET_NULL)\n\t\t{\n\t\t\tNSString *reason = @\"Error in socket() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\tint status;\n\t\t\n\t\t// Set socket options\n\t\t\n\t\tstatus = fcntl(socketFD, F_SETFL, O_NONBLOCK);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error enabling non-blocking IO on socket (fcntl)\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\tint reuseOn = 1;\n\t\tstatus = setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error enabling address reuse (setsockopt)\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\t// Bind socket\n\t\t\n\t\tstatus = bind(socketFD, (const struct sockaddr *)[interfaceAddr bytes], (socklen_t)[interfaceAddr length]);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error in bind() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\t// Listen\n\t\t\n\t\tstatus = listen(socketFD, 1024);\n\t\tif (status == -1)\n\t\t{\n\t\t\tNSString *reason = @\"Error in listen() function\";\n\t\t\terr = [self errnoErrorWithReason:reason];\n\t\t\t\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t\treturn SOCKET_NULL;\n\t\t}\n\t\t\n\t\treturn socketFD;\n\t};\n\t\n\t// Create dispatch block and run on socketQueue\n\t\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\tif (delegate == nil) // Must have delegate set\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept without a delegate. Set a delegate first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (delegateQueue == NULL) // Must have delegate queue set\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept without a delegate queue. Set a delegate queue first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (![self isDisconnected]) // Must be disconnected\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to accept while connected or accepting connections. Disconnect first.\";\n\t\t\terr = [self badConfigError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Clear queues (spurious read/write requests post disconnect)\n\t\t[readQueue removeAllObjects];\n\t\t[writeQueue removeAllObjects];\n\t\t\n\t\t// Remove a previous socket\n\t\t\n\t\tNSError *error = nil;\n\t\tNSFileManager *fileManager = [NSFileManager defaultManager];\n\t\tif ([fileManager fileExistsAtPath:url.path]) {\n\t\t\tif (![[NSFileManager defaultManager] removeItemAtURL:url error:&error]) {\n\t\t\t\tNSString *msg = @\"Could not remove previous unix domain socket at given url.\";\n\t\t\t\terr = [self otherError:msg];\n\t\t\t\t\n\t\t\t\treturn_from_block;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Resolve interface from description\n\t\t\n\t\tNSData *interface = [self getInterfaceAddressFromUrl:url];\n\t\t\n\t\tif (interface == nil)\n\t\t{\n\t\t\tNSString *msg = @\"Invalid unix domain url. Specify a valid file url that does not exist (e.g. \\\"file:///tmp/socket\\\")\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Create sockets, configure, bind, and listen\n\t\t\n\t\tLogVerbose(@\"Creating unix domain socket\");\n\t\tsocketUN = createSocket(AF_UNIX, interface);\n\t\t\n\t\tif (socketUN == SOCKET_NULL)\n\t\t{\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tsocketUrl = url;\n\t\t\n\t\t// Create accept sources\n\t\t\n\t\tacceptUNSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketUN, 0, socketQueue);\n\t\t\n\t\tint socketFD = socketUN;\n\t\tdispatch_source_t acceptSource = acceptUNSource;\n\t\t\n\t\tdispatch_source_set_event_handler(acceptUNSource, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tLogVerbose(@\"eventUNBlock\");\n\t\t\t\n\t\t\tunsigned long i = 0;\n\t\t\tunsigned long numPendingConnections = dispatch_source_get_data(acceptSource);\n\t\t\t\n\t\t\tLogVerbose(@\"numPendingConnections: %lu\", numPendingConnections);\n\t\t\t\n\t\t\twhile ([self doAccept:socketFD] && (++i < numPendingConnections));\n\t\t}});\n\t\t\n\t\tdispatch_source_set_cancel_handler(acceptUNSource, ^{\n\t\t\t\n#if NEEDS_DISPATCH_RETAIN_RELEASE\n\t\t\tLogVerbose(@\"dispatch_release(accept4Source)\");\n\t\t\tdispatch_release(acceptSource);\n#endif\n\t\t\t\n\t\t\tLogVerbose(@\"close(socket4FD)\");\n\t\t\tclose(socketFD);\n\t\t});\n\t\t\n\t\tLogVerbose(@\"dispatch_resume(accept4Source)\");\n\t\tdispatch_resume(acceptUNSource);\n\t\t\n\t\tflags |= kSocketStarted;\n\t\t\n\t\tresult = YES;\n\t}};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\tif (result == NO)\n\t{\n\t\tLogInfo(@\"Error in accept: %@\", err);\n\t\t\n\t\tif (errPtr)\n\t\t\t*errPtr = err;\n\t}\n\t\n\treturn result;\t\n}\n\n- (BOOL)doAccept:(int)parentSocketFD\n{\n\tLogTrace();\n\t\n\tint socketType;\n\tint childSocketFD;\n\tNSData *childSocketAddress;\n\t\n\tif (parentSocketFD == socket4FD)\n\t{\n\t\tsocketType = 0;\n\t\t\n\t\tstruct sockaddr_in addr;\n\t\tsocklen_t addrLen = sizeof(addr);\n\t\t\n\t\tchildSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);\n\t\t\n\t\tif (childSocketFD == -1)\n\t\t{\n\t\t\tLogWarn(@\"Accept failed with error: %@\", [self errnoError]);\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tchildSocketAddress = [NSData dataWithBytes:&addr length:addrLen];\n\t}\n\telse if (parentSocketFD == socket6FD)\n\t{\n\t\tsocketType = 1;\n\t\t\n\t\tstruct sockaddr_in6 addr;\n\t\tsocklen_t addrLen = sizeof(addr);\n\t\t\n\t\tchildSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);\n\t\t\n\t\tif (childSocketFD == -1)\n\t\t{\n\t\t\tLogWarn(@\"Accept failed with error: %@\", [self errnoError]);\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tchildSocketAddress = [NSData dataWithBytes:&addr length:addrLen];\n\t}\n\telse // if (parentSocketFD == socketUN)\n\t{\n\t\tsocketType = 2;\n\t\t\n\t\tstruct sockaddr_un addr;\n\t\tsocklen_t addrLen = sizeof(addr);\n\t\t\n\t\tchildSocketFD = accept(parentSocketFD, (struct sockaddr *)&addr, &addrLen);\n\t\t\n\t\tif (childSocketFD == -1)\n\t\t{\n\t\t\tLogWarn(@\"Accept failed with error: %@\", [self errnoError]);\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tchildSocketAddress = [NSData dataWithBytes:&addr length:addrLen];\n\t}\n\t\n\t// Enable non-blocking IO on the socket\n\t\n\tint result = fcntl(childSocketFD, F_SETFL, O_NONBLOCK);\n\tif (result == -1)\n\t{\n\t\tLogWarn(@\"Error enabling non-blocking IO on accepted socket (fcntl)\");\n\t\tLogVerbose(@\"close(childSocketFD)\");\n\t\tclose(childSocketFD);\n\t\treturn NO;\n\t}\n\t\n\t// Prevent SIGPIPE signals\n\t\n\tint nosigpipe = 1;\n\tsetsockopt(childSocketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));\n\t\n\t// Notify delegate\n\t\n\tif (delegateQueue)\n\t{\n\t\t__strong id theDelegate = delegate;\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t// Query delegate for custom socket queue\n\t\t\t\n\t\t\tdispatch_queue_t childSocketQueue = NULL;\n\t\t\t\n\t\t\tif ([theDelegate respondsToSelector:@selector(newSocketQueueForConnectionFromAddress:onSocket:)])\n\t\t\t{\n\t\t\t\tchildSocketQueue = [theDelegate newSocketQueueForConnectionFromAddress:childSocketAddress\n\t\t\t\t                                                              onSocket:self];\n\t\t\t}\n\t\t\t\n\t\t\t// Create GCDAsyncSocket instance for accepted socket\n\t\t\t\n\t\t\tGCDAsyncSocket *acceptedSocket = [[[self class] alloc] initWithDelegate:theDelegate\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  delegateQueue:delegateQueue\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tsocketQueue:childSocketQueue];\n\t\t\t\n\t\t\tif (socketType == 0)\n\t\t\t\tacceptedSocket->socket4FD = childSocketFD;\n\t\t\telse if (socketType == 1)\n\t\t\t\tacceptedSocket->socket6FD = childSocketFD;\n\t\t\telse\n\t\t\t\tacceptedSocket->socketUN = childSocketFD;\n\t\t\t\n\t\t\tacceptedSocket->flags = (kSocketStarted | kConnected);\n\t\t\t\n\t\t\t// Setup read and write sources for accepted socket\n\t\t\t\n\t\t\tdispatch_async(acceptedSocket->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[acceptedSocket setupReadAndWriteSourcesForNewlyConnectedSocket:childSocketFD];\n\t\t\t}});\n\t\t\t\n\t\t\t// Notify delegate\n\t\t\t\n\t\t\tif ([theDelegate respondsToSelector:@selector(socket:didAcceptNewSocket:)])\n\t\t\t{\n\t\t\t\t[theDelegate socket:self didAcceptNewSocket:acceptedSocket];\n\t\t\t}\n\t\t\t\n\t\t\t// Release the socket queue returned from the delegate (it was retained by acceptedSocket)\n\t\t\t#if !OS_OBJECT_USE_OBJC\n\t\t\tif (childSocketQueue) dispatch_release(childSocketQueue);\n\t\t\t#endif\n\t\t\t\n\t\t\t// The accepted socket should have been retained by the delegate.\n\t\t\t// Otherwise it gets properly released when exiting the block.\n\t\t}});\n\t}\n\t\n\treturn YES;\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Connecting\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * This method runs through the various checks required prior to a connection attempt.\n * It is shared between the connectToHost and connectToAddress methods.\n * \n**/\n- (BOOL)preConnectWithInterface:(NSString *)interface error:(NSError **)errPtr\n{\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\tif (delegate == nil) // Must have delegate set\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect without a delegate. Set a delegate first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tif (delegateQueue == NULL) // Must have delegate queue set\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect without a delegate queue. Set a delegate queue first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tif (![self isDisconnected]) // Must be disconnected\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect while connected or accepting connections. Disconnect first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tBOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;\n\tBOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;\n\t\n\tif (isIPv4Disabled && isIPv6Disabled) // Must have IPv4 or IPv6 enabled\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Both IPv4 and IPv6 have been disabled. Must enable at least one protocol first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tif (interface)\n\t{\n\t\tNSMutableData *interface4 = nil;\n\t\tNSMutableData *interface6 = nil;\n\t\t\n\t\t[self getInterfaceAddress4:&interface4 address6:&interface6 fromDescription:interface port:0];\n\t\t\n\t\tif ((interface4 == nil) && (interface6 == nil))\n\t\t{\n\t\t\tif (errPtr)\n\t\t\t{\n\t\t\t\tNSString *msg = @\"Unknown interface. Specify valid interface by name (e.g. \\\"en1\\\") or IP address.\";\n\t\t\t\t*errPtr = [self badParamError:msg];\n\t\t\t}\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tif (isIPv4Disabled && (interface6 == nil))\n\t\t{\n\t\t\tif (errPtr)\n\t\t\t{\n\t\t\t\tNSString *msg = @\"IPv4 has been disabled and specified interface doesn't support IPv6.\";\n\t\t\t\t*errPtr = [self badParamError:msg];\n\t\t\t}\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tif (isIPv6Disabled && (interface4 == nil))\n\t\t{\n\t\t\tif (errPtr)\n\t\t\t{\n\t\t\t\tNSString *msg = @\"IPv6 has been disabled and specified interface doesn't support IPv4.\";\n\t\t\t\t*errPtr = [self badParamError:msg];\n\t\t\t}\n\t\t\treturn NO;\n\t\t}\n\t\t\n\t\tconnectInterface4 = interface4;\n\t\tconnectInterface6 = interface6;\n\t}\n\t\n\t// Clear queues (spurious read/write requests post disconnect)\n\t[readQueue removeAllObjects];\n\t[writeQueue removeAllObjects];\n\t\n\treturn YES;\n}\n\n- (BOOL)preConnectWithUrl:(NSURL *)url error:(NSError **)errPtr\n{\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\tif (delegate == nil) // Must have delegate set\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect without a delegate. Set a delegate first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tif (delegateQueue == NULL) // Must have delegate queue set\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect without a delegate queue. Set a delegate queue first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tif (![self isDisconnected]) // Must be disconnected\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Attempting to connect while connected or accepting connections. Disconnect first.\";\n\t\t\t*errPtr = [self badConfigError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tNSData *interface = [self getInterfaceAddressFromUrl:url];\n\t\n\tif (interface == nil)\n\t{\n\t\tif (errPtr)\n\t\t{\n\t\t\tNSString *msg = @\"Unknown interface. Specify valid interface by name (e.g. \\\"en1\\\") or IP address.\";\n\t\t\t*errPtr = [self badParamError:msg];\n\t\t}\n\t\treturn NO;\n\t}\n\t\n\tconnectInterfaceUN = interface;\n\t\n\t// Clear queues (spurious read/write requests post disconnect)\n\t[readQueue removeAllObjects];\n\t[writeQueue removeAllObjects];\n\t\n\treturn YES;\n}\n\n- (BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr\n{\n\treturn [self connectToHost:host onPort:port withTimeout:-1 error:errPtr];\n}\n\n- (BOOL)connectToHost:(NSString *)host\n               onPort:(uint16_t)port\n          withTimeout:(NSTimeInterval)timeout\n                error:(NSError **)errPtr\n{\n\treturn [self connectToHost:host onPort:port viaInterface:nil withTimeout:timeout error:errPtr];\n}\n\n- (BOOL)connectToHost:(NSString *)inHost\n               onPort:(uint16_t)port\n         viaInterface:(NSString *)inInterface\n          withTimeout:(NSTimeInterval)timeout\n                error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\t// Just in case immutable objects were passed\n\tNSString *host = [inHost copy];\n\tNSString *interface = [inInterface copy];\n\t\n\t__block BOOL result = NO;\n\t__block NSError *preConnectErr = nil;\n\t\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\t// Check for problems with host parameter\n\t\t\n\t\tif ([host length] == 0)\n\t\t{\n\t\t\tNSString *msg = @\"Invalid host parameter (nil or \\\"\\\"). Should be a domain name or IP address string.\";\n\t\t\tpreConnectErr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Run through standard pre-connect checks\n\t\t\n\t\tif (![self preConnectWithInterface:interface error:&preConnectErr])\n\t\t{\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// We've made it past all the checks.\n\t\t// It's time to start the connection process.\n\t\t\n\t\tflags |= kSocketStarted;\n\t\t\n\t\tLogVerbose(@\"Dispatching DNS lookup...\");\n\t\t\n\t\t// It's possible that the given host parameter is actually a NSMutableString.\n\t\t// So we want to copy it now, within this block that will be executed synchronously.\n\t\t// This way the asynchronous lookup block below doesn't have to worry about it changing.\n\t\t\n\t\tNSString *hostCpy = [host copy];\n\t\t\n\t\tint aStateIndex = stateIndex;\n\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\n\t\tdispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);\n\t\tdispatch_async(globalConcurrentQueue, ^{ @autoreleasepool {\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\tNSError *lookupErr = nil;\n\t\t\tNSMutableArray *addresses = [[self class] lookupHost:hostCpy port:port error:&lookupErr];\n\t\t\t\n\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\n\t\t\tif (lookupErr)\n\t\t\t{\n\t\t\t\tdispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\t\n\t\t\t\t\t[strongSelf lookup:aStateIndex didFail:lookupErr];\n\t\t\t\t}});\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tNSData *address4 = nil;\n\t\t\t\tNSData *address6 = nil;\n\t\t\t\t\n\t\t\t\tfor (NSData *address in addresses)\n\t\t\t\t{\n\t\t\t\t\tif (!address4 && [[self class] isIPv4Address:address])\n\t\t\t\t\t{\n\t\t\t\t\t\taddress4 = address;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!address6 && [[self class] isIPv6Address:address])\n\t\t\t\t\t{\n\t\t\t\t\t\taddress6 = address;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\t\n\t\t\t\t\t[strongSelf lookup:aStateIndex didSucceedWithAddress4:address4 address6:address6];\n\t\t\t\t}});\n\t\t\t}\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t}});\n\t\t\n\t\t[self startConnectTimeout:timeout];\n\t\t\n\t\tresult = YES;\n\t}};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\t\n\tif (errPtr) *errPtr = preConnectErr;\n\treturn result;\n}\n\n- (BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError **)errPtr\n{\n\treturn [self connectToAddress:remoteAddr viaInterface:nil withTimeout:-1 error:errPtr];\n}\n\n- (BOOL)connectToAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr\n{\n\treturn [self connectToAddress:remoteAddr viaInterface:nil withTimeout:timeout error:errPtr];\n}\n\n- (BOOL)connectToAddress:(NSData *)inRemoteAddr\n            viaInterface:(NSString *)inInterface\n             withTimeout:(NSTimeInterval)timeout\n                   error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\t// Just in case immutable objects were passed\n\tNSData *remoteAddr = [inRemoteAddr copy];\n\tNSString *interface = [inInterface copy];\n\t\n\t__block BOOL result = NO;\n\t__block NSError *err = nil;\n\t\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\t// Check for problems with remoteAddr parameter\n\t\t\n\t\tNSData *address4 = nil;\n\t\tNSData *address6 = nil;\n\t\t\n\t\tif ([remoteAddr length] >= sizeof(struct sockaddr))\n\t\t{\n\t\t\tconst struct sockaddr *sockaddr = (const struct sockaddr *)[remoteAddr bytes];\n\t\t\t\n\t\t\tif (sockaddr->sa_family == AF_INET)\n\t\t\t{\n\t\t\t\tif ([remoteAddr length] == sizeof(struct sockaddr_in))\n\t\t\t\t{\n\t\t\t\t\taddress4 = remoteAddr;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (sockaddr->sa_family == AF_INET6)\n\t\t\t{\n\t\t\t\tif ([remoteAddr length] == sizeof(struct sockaddr_in6))\n\t\t\t\t{\n\t\t\t\t\taddress6 = remoteAddr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif ((address4 == nil) && (address6 == nil))\n\t\t{\n\t\t\tNSString *msg = @\"A valid IPv4 or IPv6 address was not given\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tBOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;\n\t\tBOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;\n\t\t\n\t\tif (isIPv4Disabled && (address4 != nil))\n\t\t{\n\t\t\tNSString *msg = @\"IPv4 has been disabled and an IPv4 address was passed.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (isIPv6Disabled && (address6 != nil))\n\t\t{\n\t\t\tNSString *msg = @\"IPv6 has been disabled and an IPv6 address was passed.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Run through standard pre-connect checks\n\t\t\n\t\tif (![self preConnectWithInterface:interface error:&err])\n\t\t{\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// We've made it past all the checks.\n\t\t// It's time to start the connection process.\n\t\t\n\t\tif (![self connectWithAddress4:address4 address6:address6 error:&err])\n\t\t{\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tflags |= kSocketStarted;\n\t\t\n\t\t[self startConnectTimeout:timeout];\n\t\t\n\t\tresult = YES;\n\t}};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\tif (result == NO)\n\t{\n\t\tif (errPtr)\n\t\t\t*errPtr = err;\n\t}\n\t\n\treturn result;\n}\n\n- (BOOL)connectToUrl:(NSURL *)url withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\t__block BOOL result = NO;\n\t__block NSError *err = nil;\n\t\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\t// Check for problems with host parameter\n\t\t\n\t\tif ([url.path length] == 0)\n\t\t{\n\t\t\tNSString *msg = @\"Invalid unix domain socket url.\";\n\t\t\terr = [self badParamError:msg];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// Run through standard pre-connect checks\n\t\t\n\t\tif (![self preConnectWithUrl:url error:&err])\n\t\t{\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\t// We've made it past all the checks.\n\t\t// It's time to start the connection process.\n\t\t\n\t\tflags |= kSocketStarted;\n\t\t\n\t\t// Start the normal connection process\n\t\t\n\t\tNSError *connectError = nil;\n\t\tif (![self connectWithAddressUN:connectInterfaceUN error:&connectError])\n\t\t{\n\t\t\t[self closeWithError:connectError];\n\t\t\t\n\t\t\treturn_from_block;\n\t\t}\n\n\t\t[self startConnectTimeout:timeout];\n\t\t\n\t\tresult = YES;\n\t}};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\tif (result == NO)\n\t{\n\t\tif (errPtr)\n\t\t\t*errPtr = err;\n\t}\n\t\n\treturn result;\n}\n\n- (void)lookup:(int)aStateIndex didSucceedWithAddress4:(NSData *)address4 address6:(NSData *)address6\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\tNSAssert(address4 || address6, @\"Expected at least one valid address\");\n\t\n\tif (aStateIndex != stateIndex)\n\t{\n\t\tLogInfo(@\"Ignoring lookupDidSucceed, already disconnected\");\n\t\t\n\t\t// The connect operation has been cancelled.\n\t\t// That is, socket was disconnected, or connection has already timed out.\n\t\treturn;\n\t}\n\t\n\t// Check for problems\n\t\n\tBOOL isIPv4Disabled = (config & kIPv4Disabled) ? YES : NO;\n\tBOOL isIPv6Disabled = (config & kIPv6Disabled) ? YES : NO;\n\t\n\tif (isIPv4Disabled && (address6 == nil))\n\t{\n\t\tNSString *msg = @\"IPv4 has been disabled and DNS lookup found no IPv6 address.\";\n\t\t\n\t\t[self closeWithError:[self otherError:msg]];\n\t\treturn;\n\t}\n\t\n\tif (isIPv6Disabled && (address4 == nil))\n\t{\n\t\tNSString *msg = @\"IPv6 has been disabled and DNS lookup found no IPv4 address.\";\n\t\t\n\t\t[self closeWithError:[self otherError:msg]];\n\t\treturn;\n\t}\n\t\n\t// Start the normal connection process\n\t\n\tNSError *err = nil;\n\tif (![self connectWithAddress4:address4 address6:address6 error:&err])\n\t{\n\t\t[self closeWithError:err];\n\t}\n}\n\n/**\n * This method is called if the DNS lookup fails.\n * This method is executed on the socketQueue.\n * \n * Since the DNS lookup executed synchronously on a global concurrent queue,\n * the original connection request may have already been cancelled or timed-out by the time this method is invoked.\n * The lookupIndex tells us whether the lookup is still valid or not.\n**/\n- (void)lookup:(int)aStateIndex didFail:(NSError *)error\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t\n\tif (aStateIndex != stateIndex)\n\t{\n\t\tLogInfo(@\"Ignoring lookup:didFail: - already disconnected\");\n\t\t\n\t\t// The connect operation has been cancelled.\n\t\t// That is, socket was disconnected, or connection has already timed out.\n\t\treturn;\n\t}\n\t\n\t[self endConnectTimeout];\n\t[self closeWithError:error];\n}\n\n- (BOOL)bindSocket:(int)socketFD toInterface:(NSData *)connectInterface error:(NSError **)errPtr\n{\n    // Bind the socket to the desired interface (if needed)\n    \n    if (connectInterface)\n    {\n        LogVerbose(@\"Binding socket...\");\n        \n        if ([[self class] portFromAddress:connectInterface] > 0)\n        {\n            // Since we're going to be binding to a specific port,\n            // we should turn on reuseaddr to allow us to override sockets in time_wait.\n            \n            int reuseOn = 1;\n            setsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));\n        }\n        \n        const struct sockaddr *interfaceAddr = (const struct sockaddr *)[connectInterface bytes];\n        \n        int result = bind(socketFD, interfaceAddr, (socklen_t)[connectInterface length]);\n        if (result != 0)\n        {\n            if (errPtr)\n                *errPtr = [self errnoErrorWithReason:@\"Error in bind() function\"];\n            \n            return NO;\n        }\n    }\n    \n    return YES;\n}\n\n- (int)createSocket:(int)family connectInterface:(NSData *)connectInterface errPtr:(NSError **)errPtr\n{\n    int socketFD = socket(family, SOCK_STREAM, 0);\n    \n    if (socketFD == SOCKET_NULL)\n    {\n        if (errPtr)\n            *errPtr = [self errnoErrorWithReason:@\"Error in socket() function\"];\n        \n        return socketFD;\n    }\n    \n    if (![self bindSocket:socketFD toInterface:connectInterface error:errPtr])\n    {\n        [self closeSocket:socketFD];\n        \n        return SOCKET_NULL;\n    }\n    \n    // Prevent SIGPIPE signals\n    \n    int nosigpipe = 1;\n    setsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));\n    \n    return socketFD;\n}\n\n- (void)connectSocket:(int)socketFD address:(NSData *)address stateIndex:(int)aStateIndex\n{\n    // If there already is a socket connected, we close socketFD and return\n    if (self.isConnected)\n    {\n        [self closeSocket:socketFD];\n        return;\n    }\n    \n    // Start the connection process in a background queue\n    \n    __weak GCDAsyncSocket *weakSelf = self;\n    \n    dispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);\n    dispatch_async(globalConcurrentQueue, ^{\n#pragma clang diagnostic push\n#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n        \n        int result = connect(socketFD, (const struct sockaddr *)[address bytes], (socklen_t)[address length]);\n        \n        __strong GCDAsyncSocket *strongSelf = weakSelf;\n        if (strongSelf == nil) return_from_block;\n        \n        dispatch_async(strongSelf->socketQueue, ^{ @autoreleasepool {\n            \n            if (strongSelf.isConnected)\n            {\n                [strongSelf closeSocket:socketFD];\n                return_from_block;\n            }\n            \n            if (result == 0)\n            {\n                [self closeUnusedSocket:socketFD];\n                \n                [strongSelf didConnect:aStateIndex];\n            }\n            else\n            {\n                [strongSelf closeSocket:socketFD];\n                \n                // If there are no more sockets trying to connect, we inform the error to the delegate\n                if (strongSelf.socket4FD == SOCKET_NULL && strongSelf.socket6FD == SOCKET_NULL)\n                {\n                    NSError *error = [strongSelf errnoErrorWithReason:@\"Error in connect() function\"];\n                    [strongSelf didNotConnect:aStateIndex error:error];\n                }\n            }\n        }});\n        \n#pragma clang diagnostic pop\n    });\n    \n    LogVerbose(@\"Connecting...\");\n}\n\n- (void)closeSocket:(int)socketFD\n{\n    if (socketFD != SOCKET_NULL &&\n        (socketFD == socket6FD || socketFD == socket4FD))\n    {\n        close(socketFD);\n        \n        if (socketFD == socket4FD)\n        {\n            LogVerbose(@\"close(socket4FD)\");\n            socket4FD = SOCKET_NULL;\n        }\n        else if (socketFD == socket6FD)\n        {\n            LogVerbose(@\"close(socket6FD)\");\n            socket6FD = SOCKET_NULL;\n        }\n    }\n}\n\n- (void)closeUnusedSocket:(int)usedSocketFD\n{\n    if (usedSocketFD != socket4FD)\n    {\n        [self closeSocket:socket4FD];\n    }\n    else if (usedSocketFD != socket6FD)\n    {\n        [self closeSocket:socket6FD];\n    }\n}\n\n- (BOOL)connectWithAddress4:(NSData *)address4 address6:(NSData *)address6 error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\tLogVerbose(@\"IPv4: %@:%hu\", [[self class] hostFromAddress:address4], [[self class] portFromAddress:address4]);\n\tLogVerbose(@\"IPv6: %@:%hu\", [[self class] hostFromAddress:address6], [[self class] portFromAddress:address6]);\n\t\n\t// Determine socket type\n\t\n\tBOOL preferIPv6 = (config & kPreferIPv6) ? YES : NO;\n\t\n\t// Create and bind the sockets\n    \n    if (address4)\n    {\n        LogVerbose(@\"Creating IPv4 socket\");\n        \n        socket4FD = [self createSocket:AF_INET connectInterface:connectInterface4 errPtr:errPtr];\n    }\n    \n    if (address6)\n    {\n        LogVerbose(@\"Creating IPv6 socket\");\n        \n        socket6FD = [self createSocket:AF_INET6 connectInterface:connectInterface6 errPtr:errPtr];\n    }\n    \n    if (socket4FD == SOCKET_NULL && socket6FD == SOCKET_NULL)\n    {\n        return NO;\n    }\n\t\n\tint socketFD, alternateSocketFD;\n\tNSData *address, *alternateAddress;\n\t\n    if ((preferIPv6 && socket6FD != SOCKET_NULL) || socket4FD == SOCKET_NULL)\n    {\n        socketFD = socket6FD;\n        alternateSocketFD = socket4FD;\n        address = address6;\n        alternateAddress = address4;\n    }\n    else\n    {\n        socketFD = socket4FD;\n        alternateSocketFD = socket6FD;\n        address = address4;\n        alternateAddress = address6;\n    }\n\n    int aStateIndex = stateIndex;\n    \n    [self connectSocket:socketFD address:address stateIndex:aStateIndex];\n    \n    if (alternateAddress)\n    {\n        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(alternateAddressDelay * NSEC_PER_SEC)), socketQueue, ^{\n            [self connectSocket:alternateSocketFD address:alternateAddress stateIndex:aStateIndex];\n        });\n    }\n\t\n\treturn YES;\n}\n\n- (BOOL)connectWithAddressUN:(NSData *)address error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t// Create the socket\n\t\n\tint socketFD;\n\t\n\tLogVerbose(@\"Creating unix domain socket\");\n\t\n\tsocketUN = socket(AF_UNIX, SOCK_STREAM, 0);\n\t\n\tsocketFD = socketUN;\n\t\n\tif (socketFD == SOCKET_NULL)\n\t{\n\t\tif (errPtr)\n\t\t\t*errPtr = [self errnoErrorWithReason:@\"Error in socket() function\"];\n\t\t\n\t\treturn NO;\n\t}\n\t\n\t// Bind the socket to the desired interface (if needed)\n\t\n\tLogVerbose(@\"Binding socket...\");\n\t\n\tint reuseOn = 1;\n\tsetsockopt(socketFD, SOL_SOCKET, SO_REUSEADDR, &reuseOn, sizeof(reuseOn));\n\n//\tconst struct sockaddr *interfaceAddr = (const struct sockaddr *)[address bytes];\n//\t\n//\tint result = bind(socketFD, interfaceAddr, (socklen_t)[address length]);\n//\tif (result != 0)\n//\t{\n//\t\tif (errPtr)\n//\t\t\t*errPtr = [self errnoErrorWithReason:@\"Error in bind() function\"];\n//\t\t\n//\t\treturn NO;\n//\t}\n\t\n\t// Prevent SIGPIPE signals\n\t\n\tint nosigpipe = 1;\n\tsetsockopt(socketFD, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));\n\t\n\t// Start the connection process in a background queue\n\t\n\tint aStateIndex = stateIndex;\n\t\n\tdispatch_queue_t globalConcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);\n\tdispatch_async(globalConcurrentQueue, ^{\n\t\t\n\t\tconst struct sockaddr *addr = (const struct sockaddr *)[address bytes];\n\t\tint result = connect(socketFD, addr, addr->sa_len);\n\t\tif (result == 0)\n\t\t{\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[self didConnect:aStateIndex];\n\t\t\t}});\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// TODO: Bad file descriptor\n\t\t\tperror(\"connect\");\n\t\t\tNSError *error = [self errnoErrorWithReason:@\"Error in connect() function\"];\n\t\t\t\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[self didNotConnect:aStateIndex error:error];\n\t\t\t}});\n\t\t}\n\t});\n\t\n\tLogVerbose(@\"Connecting...\");\n\t\n\treturn YES;\n}\n\n- (void)didConnect:(int)aStateIndex\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t\n\tif (aStateIndex != stateIndex)\n\t{\n\t\tLogInfo(@\"Ignoring didConnect, already disconnected\");\n\t\t\n\t\t// The connect operation has been cancelled.\n\t\t// That is, socket was disconnected, or connection has already timed out.\n\t\treturn;\n\t}\n\t\n\tflags |= kConnected;\n\t\n\t[self endConnectTimeout];\n\t\n\t#if TARGET_OS_IPHONE\n\t// The endConnectTimeout method executed above incremented the stateIndex.\n\taStateIndex = stateIndex;\n\t#endif\n\t\n\t// Setup read/write streams (as workaround for specific shortcomings in the iOS platform)\n\t// \n\t// Note:\n\t// There may be configuration options that must be set by the delegate before opening the streams.\n\t// The primary example is the kCFStreamNetworkServiceTypeVoIP flag, which only works on an unopened stream.\n\t// \n\t// Thus we wait until after the socket:didConnectToHost:port: delegate method has completed.\n\t// This gives the delegate time to properly configure the streams if needed.\n\t\n\tdispatch_block_t SetupStreamsPart1 = ^{\n\t\t#if TARGET_OS_IPHONE\n\t\t\n\t\tif (![self createReadAndWriteStream])\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error creating CFStreams\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif (![self registerForStreamCallbacksIncludingReadWrite:NO])\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in CFStreamSetClient\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t#endif\n\t};\n\tdispatch_block_t SetupStreamsPart2 = ^{\n\t\t#if TARGET_OS_IPHONE\n\t\t\n\t\tif (aStateIndex != stateIndex)\n\t\t{\n\t\t\t// The socket has been disconnected.\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif (![self addStreamsToRunLoop])\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in CFStreamScheduleWithRunLoop\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tif (![self openStreams])\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error creating CFStreams\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t#endif\n\t};\n\t\n\t// Notify delegate\n\t\n\tNSString *host = [self connectedHost];\n\tuint16_t port = [self connectedPort];\n\tNSURL *url = [self connectedUrl];\n\t\n\t__strong id theDelegate = delegate;\n\n\tif (delegateQueue && host != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToHost:port:)])\n\t{\n\t\tSetupStreamsPart1();\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t[theDelegate socket:self didConnectToHost:host port:port];\n\t\t\t\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tSetupStreamsPart2();\n\t\t\t}});\n\t\t}});\n\t}\n\telse if (delegateQueue && url != nil && [theDelegate respondsToSelector:@selector(socket:didConnectToUrl:)])\n\t{\n\t\tSetupStreamsPart1();\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t[theDelegate socket:self didConnectToUrl:url];\n\t\t\t\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tSetupStreamsPart2();\n\t\t\t}});\n\t\t}});\n\t}\n\telse\n\t{\n\t\tSetupStreamsPart1();\n\t\tSetupStreamsPart2();\n\t}\n\t\t\n\t// Get the connected socket\n\t\n\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\n\t// Enable non-blocking IO on the socket\n\t\n\tint result = fcntl(socketFD, F_SETFL, O_NONBLOCK);\n\tif (result == -1)\n\t{\n\t\tNSString *errMsg = @\"Error enabling non-blocking IO on socket (fcntl)\";\n\t\t[self closeWithError:[self otherError:errMsg]];\n\t\t\n\t\treturn;\n\t}\n\t\n\t// Setup our read/write sources\n\t\n\t[self setupReadAndWriteSourcesForNewlyConnectedSocket:socketFD];\n\t\n\t// Dequeue any pending read/write requests\n\t\n\t[self maybeDequeueRead];\n\t[self maybeDequeueWrite];\n}\n\n- (void)didNotConnect:(int)aStateIndex error:(NSError *)error\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t\n\tif (aStateIndex != stateIndex)\n\t{\n\t\tLogInfo(@\"Ignoring didNotConnect, already disconnected\");\n\t\t\n\t\t// The connect operation has been cancelled.\n\t\t// That is, socket was disconnected, or connection has already timed out.\n\t\treturn;\n\t}\n\t\n\t[self closeWithError:error];\n}\n\n- (void)startConnectTimeout:(NSTimeInterval)timeout\n{\n\tif (timeout >= 0.0)\n\t{\n\t\tunsigned long connectTimerMask = 0;\n\n\t\tif (config & kUseStrictTimers) {\n\t\t\tconnectTimerMask = DISPATCH_TIMER_STRICT;\n\t\t}\n\n\t\tconnectTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, connectTimerMask, socketQueue);\n\t\t\n\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\n\t\tdispatch_source_set_event_handler(connectTimer, ^{ @autoreleasepool {\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\n\t\t\t[strongSelf doConnectTimeout];\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t}});\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tdispatch_source_t theConnectTimer = connectTimer;\n\t\tdispatch_source_set_cancel_handler(connectTimer, ^{\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\tLogVerbose(@\"dispatch_release(connectTimer)\");\n\t\t\tdispatch_release(theConnectTimer);\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t});\n\t\t#endif\n\t\t\n\t\tdispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));\n\t\tdispatch_source_set_timer(connectTimer, tt, DISPATCH_TIME_FOREVER, 0);\n\t\t\n\t\tdispatch_resume(connectTimer);\n\t}\n}\n\n- (void)endConnectTimeout\n{\n\tLogTrace();\n\t\n\tif (connectTimer)\n\t{\n\t\tdispatch_source_cancel(connectTimer);\n\t\tconnectTimer = NULL;\n\t}\n\t\n\t// Increment stateIndex.\n\t// This will prevent us from processing results from any related background asynchronous operations.\n\t// \n\t// Note: This should be called from close method even if connectTimer is NULL.\n\t// This is because one might disconnect a socket prior to a successful connection which had no timeout.\n\t\n\tstateIndex++;\n\t\n\tif (connectInterface4)\n\t{\n\t\tconnectInterface4 = nil;\n\t}\n\tif (connectInterface6)\n\t{\n\t\tconnectInterface6 = nil;\n\t}\n}\n\n- (void)doConnectTimeout\n{\n\tLogTrace();\n\t\n\t[self endConnectTimeout];\n\t[self closeWithError:[self connectTimeoutError]];\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Disconnecting\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (void)closeWithError:(NSError *)error\n{\n\tLogTrace();\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t[self endConnectTimeout];\n\t\n\tif (currentRead != nil)  [self endCurrentRead];\n\tif (currentWrite != nil) [self endCurrentWrite];\n\t\n\t[readQueue removeAllObjects];\n\t[writeQueue removeAllObjects];\n\t\n\t[preBuffer reset];\n\t\n\t#if TARGET_OS_IPHONE\n\t{\n\t\tif (readStream || writeStream)\n\t\t{\n\t\t\t[self removeStreamsFromRunLoop];\n\t\t\t\n\t\t\tif (readStream)\n\t\t\t{\n\t\t\t\tCFReadStreamSetClient(readStream, kCFStreamEventNone, NULL, NULL);\n\t\t\t\tCFReadStreamClose(readStream);\n\t\t\t\tCFRelease(readStream);\n\t\t\t\treadStream = NULL;\n\t\t\t}\n\t\t\tif (writeStream)\n\t\t\t{\n\t\t\t\tCFWriteStreamSetClient(writeStream, kCFStreamEventNone, NULL, NULL);\n\t\t\t\tCFWriteStreamClose(writeStream);\n\t\t\t\tCFRelease(writeStream);\n\t\t\t\twriteStream = NULL;\n\t\t\t}\n\t\t}\n\t}\n\t#endif\n\t\n\t[sslPreBuffer reset];\n\tsslErrCode = lastSSLHandshakeError = noErr;\n\t\n\tif (sslContext)\n\t{\n\t\t// Getting a linker error here about the SSLx() functions?\n\t\t// You need to add the Security Framework to your application.\n\t\t\n\t\tSSLClose(sslContext);\n\t\t\n\t\t#if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)\n\t\tCFRelease(sslContext);\n\t\t#else\n\t\tSSLDisposeContext(sslContext);\n\t\t#endif\n\t\t\n\t\tsslContext = NULL;\n\t}\n\t\n\t// For some crazy reason (in my opinion), cancelling a dispatch source doesn't\n\t// invoke the cancel handler if the dispatch source is paused.\n\t// So we have to unpause the source if needed.\n\t// This allows the cancel handler to be run, which in turn releases the source and closes the socket.\n\t\n\tif (!accept4Source && !accept6Source && !acceptUNSource && !readSource && !writeSource)\n\t{\n\t\tLogVerbose(@\"manually closing close\");\n\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t{\n\t\t\tLogVerbose(@\"close(socket4FD)\");\n\t\t\tclose(socket4FD);\n\t\t\tsocket4FD = SOCKET_NULL;\n\t\t}\n\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t{\n\t\t\tLogVerbose(@\"close(socket6FD)\");\n\t\t\tclose(socket6FD);\n\t\t\tsocket6FD = SOCKET_NULL;\n\t\t}\n\t\t\n\t\tif (socketUN != SOCKET_NULL)\n\t\t{\n\t\t\tLogVerbose(@\"close(socketUN)\");\n\t\t\tclose(socketUN);\n\t\t\tsocketUN = SOCKET_NULL;\n\t\t\tunlink(socketUrl.path.fileSystemRepresentation);\n\t\t\tsocketUrl = nil;\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (accept4Source)\n\t\t{\n\t\t\tLogVerbose(@\"dispatch_source_cancel(accept4Source)\");\n\t\t\tdispatch_source_cancel(accept4Source);\n\t\t\t\n\t\t\t// We never suspend accept4Source\n\t\t\t\n\t\t\taccept4Source = NULL;\n\t\t}\n\t\t\n\t\tif (accept6Source)\n\t\t{\n\t\t\tLogVerbose(@\"dispatch_source_cancel(accept6Source)\");\n\t\t\tdispatch_source_cancel(accept6Source);\n\t\t\t\n\t\t\t// We never suspend accept6Source\n\t\t\t\n\t\t\taccept6Source = NULL;\n\t\t}\n\t\t\n\t\tif (acceptUNSource)\n\t\t{\n\t\t\tLogVerbose(@\"dispatch_source_cancel(acceptUNSource)\");\n\t\t\tdispatch_source_cancel(acceptUNSource);\n\t\t\t\n\t\t\t// We never suspend acceptUNSource\n\t\t\t\n\t\t\tacceptUNSource = NULL;\n\t\t}\n\t\n\t\tif (readSource)\n\t\t{\n\t\t\tLogVerbose(@\"dispatch_source_cancel(readSource)\");\n\t\t\tdispatch_source_cancel(readSource);\n\t\t\t\n\t\t\t[self resumeReadSource];\n\t\t\t\n\t\t\treadSource = NULL;\n\t\t}\n\t\t\n\t\tif (writeSource)\n\t\t{\n\t\t\tLogVerbose(@\"dispatch_source_cancel(writeSource)\");\n\t\t\tdispatch_source_cancel(writeSource);\n\t\t\t\n\t\t\t[self resumeWriteSource];\n\t\t\t\n\t\t\twriteSource = NULL;\n\t\t}\n\t\t\n\t\t// The sockets will be closed by the cancel handlers of the corresponding source\n\t\t\n\t\tsocket4FD = SOCKET_NULL;\n\t\tsocket6FD = SOCKET_NULL;\n\t\tsocketUN = SOCKET_NULL;\n\t}\n\t\n\t// If the client has passed the connect/accept method, then the connection has at least begun.\n\t// Notify delegate that it is now ending.\n\tBOOL shouldCallDelegate = (flags & kSocketStarted) ? YES : NO;\n\tBOOL isDeallocating = (flags & kDealloc) ? YES : NO;\n\t\n\t// Clear stored socket info and all flags (config remains as is)\n\tsocketFDBytesAvailable = 0;\n\tflags = 0;\n\tsslWriteCachedLength = 0;\n\t\n\tif (shouldCallDelegate)\n\t{\n\t\t__strong id theDelegate = delegate;\n\t\t__strong id theSelf = isDeallocating ? nil : self;\n\t\t\n\t\tif (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)])\n\t\t{\n\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[theDelegate socketDidDisconnect:theSelf withError:error];\n\t\t\t}});\n\t\t}\t\n\t}\n}\n\n- (void)disconnect\n{\n\tdispatch_block_t block = ^{ @autoreleasepool {\n\t\t\n\t\tif (flags & kSocketStarted)\n\t\t{\n\t\t\t[self closeWithError:nil];\n\t\t}\n\t}};\n\t\n\t// Synchronous disconnection, as documented in the header file\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n}\n\n- (void)disconnectAfterReading\n{\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tif (flags & kSocketStarted)\n\t\t{\n\t\t\tflags |= (kForbidReadsWrites | kDisconnectAfterReads);\n\t\t\t[self maybeClose];\n\t\t}\n\t}});\n}\n\n- (void)disconnectAfterWriting\n{\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tif (flags & kSocketStarted)\n\t\t{\n\t\t\tflags |= (kForbidReadsWrites | kDisconnectAfterWrites);\n\t\t\t[self maybeClose];\n\t\t}\n\t}});\n}\n\n- (void)disconnectAfterReadingAndWriting\n{\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tif (flags & kSocketStarted)\n\t\t{\n\t\t\tflags |= (kForbidReadsWrites | kDisconnectAfterReads | kDisconnectAfterWrites);\n\t\t\t[self maybeClose];\n\t\t}\n\t}});\n}\n\n/**\n * Closes the socket if possible.\n * That is, if all writes have completed, and we're set to disconnect after writing,\n * or if all reads have completed, and we're set to disconnect after reading.\n**/\n- (void)maybeClose\n{\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\tBOOL shouldClose = NO;\n\t\n\tif (flags & kDisconnectAfterReads)\n\t{\n\t\tif (([readQueue count] == 0) && (currentRead == nil))\n\t\t{\n\t\t\tif (flags & kDisconnectAfterWrites)\n\t\t\t{\n\t\t\t\tif (([writeQueue count] == 0) && (currentWrite == nil))\n\t\t\t\t{\n\t\t\t\t\tshouldClose = YES;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tshouldClose = YES;\n\t\t\t}\n\t\t}\n\t}\n\telse if (flags & kDisconnectAfterWrites)\n\t{\n\t\tif (([writeQueue count] == 0) && (currentWrite == nil))\n\t\t{\n\t\t\tshouldClose = YES;\n\t\t}\n\t}\n\t\n\tif (shouldClose)\n\t{\n\t\t[self closeWithError:nil];\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Errors\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (NSError *)badConfigError:(NSString *)errMsg\n{\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadConfigError userInfo:userInfo];\n}\n\n- (NSError *)badParamError:(NSString *)errMsg\n{\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketBadParamError userInfo:userInfo];\n}\n\n+ (NSError *)gaiError:(int)gai_error\n{\n\tNSString *errMsg = [NSString stringWithCString:gai_strerror(gai_error) encoding:NSASCIIStringEncoding];\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:@\"kCFStreamErrorDomainNetDB\" code:gai_error userInfo:userInfo];\n}\n\n- (NSError *)errnoErrorWithReason:(NSString *)reason\n{\n\tNSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:errMsg, NSLocalizedDescriptionKey,\n\t                                                                    reason, NSLocalizedFailureReasonErrorKey, nil];\n\t\n\treturn [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];\n}\n\n- (NSError *)errnoError\n{\n\tNSString *errMsg = [NSString stringWithUTF8String:strerror(errno)];\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:userInfo];\n}\n\n- (NSError *)sslError:(OSStatus)ssl_error\n{\n\tNSString *msg = @\"Error code definition can be found in Apple's SecureTransport.h\";\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:msg forKey:NSLocalizedRecoverySuggestionErrorKey];\n\t\n\treturn [NSError errorWithDomain:@\"kCFStreamErrorDomainSSL\" code:ssl_error userInfo:userInfo];\n}\n\n- (NSError *)connectTimeoutError\n{\n\tNSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketConnectTimeoutError\",\n\t                                                     @\"GCDAsyncSocket\", [NSBundle mainBundle],\n\t                                                     @\"Attempt to connect to host timed out\", nil);\n\t\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketConnectTimeoutError userInfo:userInfo];\n}\n\n/**\n * Returns a standard AsyncSocket maxed out error.\n**/\n- (NSError *)readMaxedOutError\n{\n\tNSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketReadMaxedOutError\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t @\"GCDAsyncSocket\", [NSBundle mainBundle],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t @\"Read operation reached set maximum length\", nil);\n\t\n\tNSDictionary *info = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadMaxedOutError userInfo:info];\n}\n\n/**\n * Returns a standard AsyncSocket write timeout error.\n**/\n- (NSError *)readTimeoutError\n{\n\tNSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketReadTimeoutError\",\n\t                                                     @\"GCDAsyncSocket\", [NSBundle mainBundle],\n\t                                                     @\"Read operation timed out\", nil);\n\t\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketReadTimeoutError userInfo:userInfo];\n}\n\n/**\n * Returns a standard AsyncSocket write timeout error.\n**/\n- (NSError *)writeTimeoutError\n{\n\tNSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketWriteTimeoutError\",\n\t                                                     @\"GCDAsyncSocket\", [NSBundle mainBundle],\n\t                                                     @\"Write operation timed out\", nil);\n\t\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketWriteTimeoutError userInfo:userInfo];\n}\n\n- (NSError *)connectionClosedError\n{\n\tNSString *errMsg = NSLocalizedStringWithDefaultValue(@\"GCDAsyncSocketClosedError\",\n\t                                                     @\"GCDAsyncSocket\", [NSBundle mainBundle],\n\t                                                     @\"Socket closed by remote peer\", nil);\n\t\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketClosedError userInfo:userInfo];\n}\n\n- (NSError *)otherError:(NSString *)errMsg\n{\n\tNSDictionary *userInfo = [NSDictionary dictionaryWithObject:errMsg forKey:NSLocalizedDescriptionKey];\n\t\n\treturn [NSError errorWithDomain:GCDAsyncSocketErrorDomain code:GCDAsyncSocketOtherError userInfo:userInfo];\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Diagnostics\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (BOOL)isDisconnected\n{\n\t__block BOOL result = NO;\n\t\n\tdispatch_block_t block = ^{\n\t\tresult = (flags & kSocketStarted) ? NO : YES;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n- (BOOL)isConnected\n{\n\t__block BOOL result = NO;\n\t\n\tdispatch_block_t block = ^{\n\t\tresult = (flags & kConnected) ? YES : NO;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n- (NSString *)connectedHost\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t\treturn [self connectedHostFromSocket4:socket4FD];\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t\treturn [self connectedHostFromSocket6:socket6FD];\n\t\t\n\t\treturn nil;\n\t}\n\telse\n\t{\n\t\t__block NSString *result = nil;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tif (socket4FD != SOCKET_NULL)\n\t\t\t\tresult = [self connectedHostFromSocket4:socket4FD];\n\t\t\telse if (socket6FD != SOCKET_NULL)\n\t\t\t\tresult = [self connectedHostFromSocket6:socket6FD];\n\t\t}});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (uint16_t)connectedPort\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t\treturn [self connectedPortFromSocket4:socket4FD];\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t\treturn [self connectedPortFromSocket6:socket6FD];\n\t\t\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\t__block uint16_t result = 0;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\t// No need for autorelease pool\n\t\t\t\n\t\t\tif (socket4FD != SOCKET_NULL)\n\t\t\t\tresult = [self connectedPortFromSocket4:socket4FD];\n\t\t\telse if (socket6FD != SOCKET_NULL)\n\t\t\t\tresult = [self connectedPortFromSocket6:socket6FD];\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (NSURL *)connectedUrl\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (socketUN != SOCKET_NULL)\n\t\t\treturn [self connectedUrlFromSocketUN:socketUN];\n\t\t\n\t\treturn nil;\n\t}\n\telse\n\t{\n\t\t__block NSURL *result = nil;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tif (socketUN != SOCKET_NULL)\n\t\t\t\tresult = [self connectedUrlFromSocketUN:socketUN];\n\t\t}});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (NSString *)localHost\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t\treturn [self localHostFromSocket4:socket4FD];\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t\treturn [self localHostFromSocket6:socket6FD];\n\t\t\n\t\treturn nil;\n\t}\n\telse\n\t{\n\t\t__block NSString *result = nil;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tif (socket4FD != SOCKET_NULL)\n\t\t\t\tresult = [self localHostFromSocket4:socket4FD];\n\t\t\telse if (socket6FD != SOCKET_NULL)\n\t\t\t\tresult = [self localHostFromSocket6:socket6FD];\n\t\t}});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (uint16_t)localPort\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t\treturn [self localPortFromSocket4:socket4FD];\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t\treturn [self localPortFromSocket6:socket6FD];\n\t\t\n\t\treturn 0;\n\t}\n\telse\n\t{\n\t\t__block uint16_t result = 0;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\t// No need for autorelease pool\n\t\t\t\n\t\t\tif (socket4FD != SOCKET_NULL)\n\t\t\t\tresult = [self localPortFromSocket4:socket4FD];\n\t\t\telse if (socket6FD != SOCKET_NULL)\n\t\t\t\tresult = [self localPortFromSocket6:socket6FD];\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (NSString *)connectedHost4\n{\n\tif (socket4FD != SOCKET_NULL)\n\t\treturn [self connectedHostFromSocket4:socket4FD];\n\t\n\treturn nil;\n}\n\n- (NSString *)connectedHost6\n{\n\tif (socket6FD != SOCKET_NULL)\n\t\treturn [self connectedHostFromSocket6:socket6FD];\n\t\n\treturn nil;\n}\n\n- (uint16_t)connectedPort4\n{\n\tif (socket4FD != SOCKET_NULL)\n\t\treturn [self connectedPortFromSocket4:socket4FD];\n\t\n\treturn 0;\n}\n\n- (uint16_t)connectedPort6\n{\n\tif (socket6FD != SOCKET_NULL)\n\t\treturn [self connectedPortFromSocket6:socket6FD];\n\t\n\treturn 0;\n}\n\n- (NSString *)localHost4\n{\n\tif (socket4FD != SOCKET_NULL)\n\t\treturn [self localHostFromSocket4:socket4FD];\n\t\n\treturn nil;\n}\n\n- (NSString *)localHost6\n{\n\tif (socket6FD != SOCKET_NULL)\n\t\treturn [self localHostFromSocket6:socket6FD];\n\t\n\treturn nil;\n}\n\n- (uint16_t)localPort4\n{\n\tif (socket4FD != SOCKET_NULL)\n\t\treturn [self localPortFromSocket4:socket4FD];\n\t\n\treturn 0;\n}\n\n- (uint16_t)localPort6\n{\n\tif (socket6FD != SOCKET_NULL)\n\t\treturn [self localPortFromSocket6:socket6FD];\n\t\n\treturn 0;\n}\n\n- (NSString *)connectedHostFromSocket4:(int)socketFD\n{\n\tstruct sockaddr_in sockaddr4;\n\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\n\tif (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)\n\t{\n\t\treturn nil;\n\t}\n\treturn [[self class] hostFromSockaddr4:&sockaddr4];\n}\n\n- (NSString *)connectedHostFromSocket6:(int)socketFD\n{\n\tstruct sockaddr_in6 sockaddr6;\n\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\n\tif (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)\n\t{\n\t\treturn nil;\n\t}\n\treturn [[self class] hostFromSockaddr6:&sockaddr6];\n}\n\n- (uint16_t)connectedPortFromSocket4:(int)socketFD\n{\n\tstruct sockaddr_in sockaddr4;\n\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\n\tif (getpeername(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)\n\t{\n\t\treturn 0;\n\t}\n\treturn [[self class] portFromSockaddr4:&sockaddr4];\n}\n\n- (uint16_t)connectedPortFromSocket6:(int)socketFD\n{\n\tstruct sockaddr_in6 sockaddr6;\n\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\n\tif (getpeername(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)\n\t{\n\t\treturn 0;\n\t}\n\treturn [[self class] portFromSockaddr6:&sockaddr6];\n}\n\n- (NSURL *)connectedUrlFromSocketUN:(int)socketFD\n{\n\tstruct sockaddr_un sockaddr;\n\tsocklen_t sockaddrlen = sizeof(sockaddr);\n\t\n\tif (getpeername(socketFD, (struct sockaddr *)&sockaddr, &sockaddrlen) < 0)\n\t{\n\t\treturn 0;\n\t}\n\treturn [[self class] urlFromSockaddrUN:&sockaddr];\n}\n\n- (NSString *)localHostFromSocket4:(int)socketFD\n{\n\tstruct sockaddr_in sockaddr4;\n\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\n\tif (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)\n\t{\n\t\treturn nil;\n\t}\n\treturn [[self class] hostFromSockaddr4:&sockaddr4];\n}\n\n- (NSString *)localHostFromSocket6:(int)socketFD\n{\n\tstruct sockaddr_in6 sockaddr6;\n\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\n\tif (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)\n\t{\n\t\treturn nil;\n\t}\n\treturn [[self class] hostFromSockaddr6:&sockaddr6];\n}\n\n- (uint16_t)localPortFromSocket4:(int)socketFD\n{\n\tstruct sockaddr_in sockaddr4;\n\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\n\tif (getsockname(socketFD, (struct sockaddr *)&sockaddr4, &sockaddr4len) < 0)\n\t{\n\t\treturn 0;\n\t}\n\treturn [[self class] portFromSockaddr4:&sockaddr4];\n}\n\n- (uint16_t)localPortFromSocket6:(int)socketFD\n{\n\tstruct sockaddr_in6 sockaddr6;\n\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\n\tif (getsockname(socketFD, (struct sockaddr *)&sockaddr6, &sockaddr6len) < 0)\n\t{\n\t\treturn 0;\n\t}\n\treturn [[self class] portFromSockaddr6:&sockaddr6];\n}\n\n- (NSData *)connectedAddress\n{\n\t__block NSData *result = nil;\n\t\n\tdispatch_block_t block = ^{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t{\n\t\t\tstruct sockaddr_in sockaddr4;\n\t\t\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\t\t\n\t\t\tif (getpeername(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)\n\t\t\t{\n\t\t\t\tresult = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t{\n\t\t\tstruct sockaddr_in6 sockaddr6;\n\t\t\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\t\t\n\t\t\tif (getpeername(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)\n\t\t\t{\n\t\t\t\tresult = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];\n\t\t\t}\n\t\t}\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n- (NSData *)localAddress\n{\n\t__block NSData *result = nil;\n\t\n\tdispatch_block_t block = ^{\n\t\tif (socket4FD != SOCKET_NULL)\n\t\t{\n\t\t\tstruct sockaddr_in sockaddr4;\n\t\t\tsocklen_t sockaddr4len = sizeof(sockaddr4);\n\t\t\t\n\t\t\tif (getsockname(socket4FD, (struct sockaddr *)&sockaddr4, &sockaddr4len) == 0)\n\t\t\t{\n\t\t\t\tresult = [[NSData alloc] initWithBytes:&sockaddr4 length:sockaddr4len];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (socket6FD != SOCKET_NULL)\n\t\t{\n\t\t\tstruct sockaddr_in6 sockaddr6;\n\t\t\tsocklen_t sockaddr6len = sizeof(sockaddr6);\n\t\t\t\n\t\t\tif (getsockname(socket6FD, (struct sockaddr *)&sockaddr6, &sockaddr6len) == 0)\n\t\t\t{\n\t\t\t\tresult = [[NSData alloc] initWithBytes:&sockaddr6 length:sockaddr6len];\n\t\t\t}\n\t\t}\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n- (BOOL)isIPv4\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn (socket4FD != SOCKET_NULL);\n\t}\n\telse\n\t{\n\t\t__block BOOL result = NO;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = (socket4FD != SOCKET_NULL);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (BOOL)isIPv6\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn (socket6FD != SOCKET_NULL);\n\t}\n\telse\n\t{\n\t\t__block BOOL result = NO;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = (socket6FD != SOCKET_NULL);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n- (BOOL)isSecure\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn (flags & kSocketSecure) ? YES : NO;\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = (flags & kSocketSecure) ? YES : NO;\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Utilities\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * Finds the address of an interface description.\n * An inteface description may be an interface name (en0, en1, lo0) or corresponding IP (192.168.4.34).\n * \n * The interface description may optionally contain a port number at the end, separated by a colon.\n * If a non-zero port parameter is provided, any port number in the interface description is ignored.\n * \n * The returned value is a 'struct sockaddr' wrapped in an NSMutableData object.\n**/\n- (void)getInterfaceAddress4:(NSMutableData **)interfaceAddr4Ptr\n                    address6:(NSMutableData **)interfaceAddr6Ptr\n             fromDescription:(NSString *)interfaceDescription\n                        port:(uint16_t)port\n{\n\tNSMutableData *addr4 = nil;\n\tNSMutableData *addr6 = nil;\n\t\n\tNSString *interface = nil;\n\t\n\tNSArray *components = [interfaceDescription componentsSeparatedByString:@\":\"];\n\tif ([components count] > 0)\n\t{\n\t\tNSString *temp = [components objectAtIndex:0];\n\t\tif ([temp length] > 0)\n\t\t{\n\t\t\tinterface = temp;\n\t\t}\n\t}\n\tif ([components count] > 1 && port == 0)\n\t{\n\t\tlong portL = strtol([[components objectAtIndex:1] UTF8String], NULL, 10);\n\t\t\n\t\tif (portL > 0 && portL <= UINT16_MAX)\n\t\t{\n\t\t\tport = (uint16_t)portL;\n\t\t}\n\t}\n\t\n\tif (interface == nil)\n\t{\n\t\t// ANY address\n\t\t\n\t\tstruct sockaddr_in sockaddr4;\n\t\tmemset(&sockaddr4, 0, sizeof(sockaddr4));\n\t\t\n\t\tsockaddr4.sin_len         = sizeof(sockaddr4);\n\t\tsockaddr4.sin_family      = AF_INET;\n\t\tsockaddr4.sin_port        = htons(port);\n\t\tsockaddr4.sin_addr.s_addr = htonl(INADDR_ANY);\n\t\t\n\t\tstruct sockaddr_in6 sockaddr6;\n\t\tmemset(&sockaddr6, 0, sizeof(sockaddr6));\n\t\t\n\t\tsockaddr6.sin6_len       = sizeof(sockaddr6);\n\t\tsockaddr6.sin6_family    = AF_INET6;\n\t\tsockaddr6.sin6_port      = htons(port);\n\t\tsockaddr6.sin6_addr      = in6addr_any;\n\t\t\n\t\taddr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];\n\t\taddr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];\n\t}\n\telse if ([interface isEqualToString:@\"localhost\"] || [interface isEqualToString:@\"loopback\"])\n\t{\n\t\t// LOOPBACK address\n\t\t\n\t\tstruct sockaddr_in sockaddr4;\n\t\tmemset(&sockaddr4, 0, sizeof(sockaddr4));\n\t\t\n\t\tsockaddr4.sin_len         = sizeof(sockaddr4);\n\t\tsockaddr4.sin_family      = AF_INET;\n\t\tsockaddr4.sin_port        = htons(port);\n\t\tsockaddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);\n\t\t\n\t\tstruct sockaddr_in6 sockaddr6;\n\t\tmemset(&sockaddr6, 0, sizeof(sockaddr6));\n\t\t\n\t\tsockaddr6.sin6_len       = sizeof(sockaddr6);\n\t\tsockaddr6.sin6_family    = AF_INET6;\n\t\tsockaddr6.sin6_port      = htons(port);\n\t\tsockaddr6.sin6_addr      = in6addr_loopback;\n\t\t\n\t\taddr4 = [NSMutableData dataWithBytes:&sockaddr4 length:sizeof(sockaddr4)];\n\t\taddr6 = [NSMutableData dataWithBytes:&sockaddr6 length:sizeof(sockaddr6)];\n\t}\n\telse\n\t{\n\t\tconst char *iface = [interface UTF8String];\n\t\t\n\t\tstruct ifaddrs *addrs;\n\t\tconst struct ifaddrs *cursor;\n\t\t\n\t\tif ((getifaddrs(&addrs) == 0))\n\t\t{\n\t\t\tcursor = addrs;\n\t\t\twhile (cursor != NULL)\n\t\t\t{\n\t\t\t\tif ((addr4 == nil) && (cursor->ifa_addr->sa_family == AF_INET))\n\t\t\t\t{\n\t\t\t\t\t// IPv4\n\t\t\t\t\t\n\t\t\t\t\tstruct sockaddr_in nativeAddr4;\n\t\t\t\t\tmemcpy(&nativeAddr4, cursor->ifa_addr, sizeof(nativeAddr4));\n\t\t\t\t\t\n\t\t\t\t\tif (strcmp(cursor->ifa_name, iface) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Name match\n\t\t\t\t\t\t\n\t\t\t\t\t\tnativeAddr4.sin_port = htons(port);\n\t\t\t\t\t\t\n\t\t\t\t\t\taddr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tchar ip[INET_ADDRSTRLEN];\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst char *conversion = inet_ntop(AF_INET, &nativeAddr4.sin_addr, ip, sizeof(ip));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((conversion != NULL) && (strcmp(ip, iface) == 0))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// IP match\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnativeAddr4.sin_port = htons(port);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\taddr4 = [NSMutableData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ((addr6 == nil) && (cursor->ifa_addr->sa_family == AF_INET6))\n\t\t\t\t{\n\t\t\t\t\t// IPv6\n\t\t\t\t\t\n\t\t\t\t\tstruct sockaddr_in6 nativeAddr6;\n\t\t\t\t\tmemcpy(&nativeAddr6, cursor->ifa_addr, sizeof(nativeAddr6));\n\t\t\t\t\t\n\t\t\t\t\tif (strcmp(cursor->ifa_name, iface) == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Name match\n\t\t\t\t\t\t\n\t\t\t\t\t\tnativeAddr6.sin6_port = htons(port);\n\t\t\t\t\t\t\n\t\t\t\t\t\taddr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tchar ip[INET6_ADDRSTRLEN];\n\t\t\t\t\t\t\n\t\t\t\t\t\tconst char *conversion = inet_ntop(AF_INET6, &nativeAddr6.sin6_addr, ip, sizeof(ip));\n\t\t\t\t\t\t\n\t\t\t\t\t\tif ((conversion != NULL) && (strcmp(ip, iface) == 0))\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// IP match\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tnativeAddr6.sin6_port = htons(port);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\taddr6 = [NSMutableData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tcursor = cursor->ifa_next;\n\t\t\t}\n\t\t\t\n\t\t\tfreeifaddrs(addrs);\n\t\t}\n\t}\n\t\n\tif (interfaceAddr4Ptr) *interfaceAddr4Ptr = addr4;\n\tif (interfaceAddr6Ptr) *interfaceAddr6Ptr = addr6;\n}\n\n- (NSData *)getInterfaceAddressFromUrl:(NSURL *)url\n{\n\tNSString *path = url.path;\n\tif (path.length == 0) {\n\t\treturn nil;\n\t}\n\t\n    struct sockaddr_un nativeAddr;\n    nativeAddr.sun_family = AF_UNIX;\n    strlcpy(nativeAddr.sun_path, path.fileSystemRepresentation, sizeof(nativeAddr.sun_path));\n    nativeAddr.sun_len = SUN_LEN(&nativeAddr);\n    NSData *interface = [NSData dataWithBytes:&nativeAddr length:sizeof(struct sockaddr_un)];\n\t\n\treturn interface;\n}\n\n- (void)setupReadAndWriteSourcesForNewlyConnectedSocket:(int)socketFD\n{\n\treadSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, socketFD, 0, socketQueue);\n\twriteSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, socketFD, 0, socketQueue);\n\t\n\t// Setup event handlers\n\t\n\t__weak GCDAsyncSocket *weakSelf = self;\n\t\n\tdispatch_source_set_event_handler(readSource, ^{ @autoreleasepool {\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\tif (strongSelf == nil) return_from_block;\n\t\t\n\t\tLogVerbose(@\"readEventBlock\");\n\t\t\n\t\tstrongSelf->socketFDBytesAvailable = dispatch_source_get_data(strongSelf->readSource);\n\t\tLogVerbose(@\"socketFDBytesAvailable: %lu\", strongSelf->socketFDBytesAvailable);\n\t\t\n\t\tif (strongSelf->socketFDBytesAvailable > 0)\n\t\t\t[strongSelf doReadData];\n\t\telse\n\t\t\t[strongSelf doReadEOF];\n\t\t\n\t#pragma clang diagnostic pop\n\t}});\n\t\n\tdispatch_source_set_event_handler(writeSource, ^{ @autoreleasepool {\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\tif (strongSelf == nil) return_from_block;\n\t\t\n\t\tLogVerbose(@\"writeEventBlock\");\n\t\t\n\t\tstrongSelf->flags |= kSocketCanAcceptBytes;\n\t\t[strongSelf doWriteData];\n\t\t\n\t#pragma clang diagnostic pop\n\t}});\n\t\n\t// Setup cancel handlers\n\t\n\t__block int socketFDRefCount = 2;\n\t\n\t#if !OS_OBJECT_USE_OBJC\n\tdispatch_source_t theReadSource = readSource;\n\tdispatch_source_t theWriteSource = writeSource;\n\t#endif\n\t\n\tdispatch_source_set_cancel_handler(readSource, ^{\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\tLogVerbose(@\"readCancelBlock\");\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tLogVerbose(@\"dispatch_release(readSource)\");\n\t\tdispatch_release(theReadSource);\n\t\t#endif\n\t\t\n\t\tif (--socketFDRefCount == 0)\n\t\t{\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t}\n\t\t\n\t#pragma clang diagnostic pop\n\t});\n\t\n\tdispatch_source_set_cancel_handler(writeSource, ^{\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\tLogVerbose(@\"writeCancelBlock\");\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tLogVerbose(@\"dispatch_release(writeSource)\");\n\t\tdispatch_release(theWriteSource);\n\t\t#endif\n\t\t\n\t\tif (--socketFDRefCount == 0)\n\t\t{\n\t\t\tLogVerbose(@\"close(socketFD)\");\n\t\t\tclose(socketFD);\n\t\t}\n\t\t\n\t#pragma clang diagnostic pop\n\t});\n\t\n\t// We will not be able to read until data arrives.\n\t// But we should be able to write immediately.\n\t\n\tsocketFDBytesAvailable = 0;\n\tflags &= ~kReadSourceSuspended;\n\t\n\tLogVerbose(@\"dispatch_resume(readSource)\");\n\tdispatch_resume(readSource);\n\t\n\tflags |= kSocketCanAcceptBytes;\n\tflags |= kWriteSourceSuspended;\n}\n\n- (BOOL)usingCFStreamForTLS\n{\n\t#if TARGET_OS_IPHONE\n\t\n\tif ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))\n\t{\n\t\t// The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.\n\t\t\n\t\treturn YES;\n\t}\n\t\n\t#endif\n\t\n\treturn NO;\n}\n\n- (BOOL)usingSecureTransportForTLS\n{\n\t// Invoking this method is equivalent to ![self usingCFStreamForTLS] (just more readable)\n\t\n\t#if TARGET_OS_IPHONE\n\t\n\tif ((flags & kSocketSecure) && (flags & kUsingCFStreamForTLS))\n\t{\n\t\t// The startTLS method was given the GCDAsyncSocketUseCFStreamForTLS flag.\n\t\t\n\t\treturn NO;\n\t}\n\t\n\t#endif\n\t\n\treturn YES;\n}\n\n- (void)suspendReadSource\n{\n\tif (!(flags & kReadSourceSuspended))\n\t{\n\t\tLogVerbose(@\"dispatch_suspend(readSource)\");\n\t\t\n\t\tdispatch_suspend(readSource);\n\t\tflags |= kReadSourceSuspended;\n\t}\n}\n\n- (void)resumeReadSource\n{\n\tif (flags & kReadSourceSuspended)\n\t{\n\t\tLogVerbose(@\"dispatch_resume(readSource)\");\n\t\t\n\t\tdispatch_resume(readSource);\n\t\tflags &= ~kReadSourceSuspended;\n\t}\n}\n\n- (void)suspendWriteSource\n{\n\tif (!(flags & kWriteSourceSuspended))\n\t{\n\t\tLogVerbose(@\"dispatch_suspend(writeSource)\");\n\t\t\n\t\tdispatch_suspend(writeSource);\n\t\tflags |= kWriteSourceSuspended;\n\t}\n}\n\n- (void)resumeWriteSource\n{\n\tif (flags & kWriteSourceSuspended)\n\t{\n\t\tLogVerbose(@\"dispatch_resume(writeSource)\");\n\t\t\n\t\tdispatch_resume(writeSource);\n\t\tflags &= ~kWriteSourceSuspended;\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Reading\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag\n{\n\t[self readDataWithTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];\n}\n\n- (void)readDataWithTimeout:(NSTimeInterval)timeout\n                     buffer:(NSMutableData *)buffer\n               bufferOffset:(NSUInteger)offset\n                        tag:(long)tag\n{\n\t[self readDataWithTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];\n}\n\n- (void)readDataWithTimeout:(NSTimeInterval)timeout\n                     buffer:(NSMutableData *)buffer\n               bufferOffset:(NSUInteger)offset\n                  maxLength:(NSUInteger)length\n                        tag:(long)tag\n{\n\tif (offset > [buffer length]) {\n\t\tLogWarn(@\"Cannot read: offset > [buffer length]\");\n\t\treturn;\n\t}\n\t\n\tGCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer\n\t                                                          startOffset:offset\n\t                                                            maxLength:length\n\t                                                              timeout:timeout\n\t                                                           readLength:0\n\t                                                           terminator:nil\n\t                                                                  tag:tag];\n\t\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tLogTrace();\n\t\t\n\t\tif ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))\n\t\t{\n\t\t\t[readQueue addObject:packet];\n\t\t\t[self maybeDequeueRead];\n\t\t}\n\t}});\n\t\n\t// Do not rely on the block being run in order to release the packet,\n\t// as the queue might get released without the block completing.\n}\n\n- (void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag\n{\n\t[self readDataToLength:length withTimeout:timeout buffer:nil bufferOffset:0 tag:tag];\n}\n\n- (void)readDataToLength:(NSUInteger)length\n             withTimeout:(NSTimeInterval)timeout\n                  buffer:(NSMutableData *)buffer\n            bufferOffset:(NSUInteger)offset\n                     tag:(long)tag\n{\n\tif (length == 0) {\n\t\tLogWarn(@\"Cannot read: length == 0\");\n\t\treturn;\n\t}\n\tif (offset > [buffer length]) {\n\t\tLogWarn(@\"Cannot read: offset > [buffer length]\");\n\t\treturn;\n\t}\n\t\n\tGCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer\n\t                                                          startOffset:offset\n\t                                                            maxLength:0\n\t                                                              timeout:timeout\n\t                                                           readLength:length\n\t                                                           terminator:nil\n\t                                                                  tag:tag];\n\t\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tLogTrace();\n\t\t\n\t\tif ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))\n\t\t{\n\t\t\t[readQueue addObject:packet];\n\t\t\t[self maybeDequeueRead];\n\t\t}\n\t}});\n\t\n\t// Do not rely on the block being run in order to release the packet,\n\t// as the queue might get released without the block completing.\n}\n\n- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag\n{\n\t[self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:0 tag:tag];\n}\n\n- (void)readDataToData:(NSData *)data\n           withTimeout:(NSTimeInterval)timeout\n                buffer:(NSMutableData *)buffer\n          bufferOffset:(NSUInteger)offset\n                   tag:(long)tag\n{\n\t[self readDataToData:data withTimeout:timeout buffer:buffer bufferOffset:offset maxLength:0 tag:tag];\n}\n\n- (void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout maxLength:(NSUInteger)length tag:(long)tag\n{\n\t[self readDataToData:data withTimeout:timeout buffer:nil bufferOffset:0 maxLength:length tag:tag];\n}\n\n- (void)readDataToData:(NSData *)data\n           withTimeout:(NSTimeInterval)timeout\n                buffer:(NSMutableData *)buffer\n          bufferOffset:(NSUInteger)offset\n             maxLength:(NSUInteger)maxLength\n                   tag:(long)tag\n{\n\tif ([data length] == 0) {\n\t\tLogWarn(@\"Cannot read: [data length] == 0\");\n\t\treturn;\n\t}\n\tif (offset > [buffer length]) {\n\t\tLogWarn(@\"Cannot read: offset > [buffer length]\");\n\t\treturn;\n\t}\n\tif (maxLength > 0 && maxLength < [data length]) {\n\t\tLogWarn(@\"Cannot read: maxLength > 0 && maxLength < [data length]\");\n\t\treturn;\n\t}\n\t\n\tGCDAsyncReadPacket *packet = [[GCDAsyncReadPacket alloc] initWithData:buffer\n\t                                                          startOffset:offset\n\t                                                            maxLength:maxLength\n\t                                                              timeout:timeout\n\t                                                           readLength:0\n\t                                                           terminator:data\n\t                                                                  tag:tag];\n\t\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tLogTrace();\n\t\t\n\t\tif ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))\n\t\t{\n\t\t\t[readQueue addObject:packet];\n\t\t\t[self maybeDequeueRead];\n\t\t}\n\t}});\n\t\n\t// Do not rely on the block being run in order to release the packet,\n\t// as the queue might get released without the block completing.\n}\n\n- (float)progressOfReadReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr\n{\n\t__block float result = 0.0F;\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (!currentRead || ![currentRead isKindOfClass:[GCDAsyncReadPacket class]])\n\t\t{\n\t\t\t// We're not reading anything right now.\n\t\t\t\n\t\t\tif (tagPtr != NULL)   *tagPtr = 0;\n\t\t\tif (donePtr != NULL)  *donePtr = 0;\n\t\t\tif (totalPtr != NULL) *totalPtr = 0;\n\t\t\t\n\t\t\tresult = NAN;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// It's only possible to know the progress of our read if we're reading to a certain length.\n\t\t\t// If we're reading to data, we of course have no idea when the data will arrive.\n\t\t\t// If we're reading to timeout, then we have no idea when the next chunk of data will arrive.\n\t\t\t\n\t\t\tNSUInteger done = currentRead->bytesDone;\n\t\t\tNSUInteger total = currentRead->readLength;\n\t\t\t\n\t\t\tif (tagPtr != NULL)   *tagPtr = currentRead->tag;\n\t\t\tif (donePtr != NULL)  *donePtr = done;\n\t\t\tif (totalPtr != NULL) *totalPtr = total;\n\t\t\t\n\t\t\tif (total > 0)\n\t\t\t\tresult = (float)done / (float)total;\n\t\t\telse\n\t\t\t\tresult = 1.0F;\n\t\t}\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n/**\n * This method starts a new read, if needed.\n * \n * It is called when:\n * - a user requests a read\n * - after a read request has finished (to handle the next request)\n * - immediately after the socket opens to handle any pending requests\n * \n * This method also handles auto-disconnect post read/write completion.\n**/\n- (void)maybeDequeueRead\n{\n\tLogTrace();\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t// If we're not currently processing a read AND we have an available read stream\n\tif ((currentRead == nil) && (flags & kConnected))\n\t{\n\t\tif ([readQueue count] > 0)\n\t\t{\n\t\t\t// Dequeue the next object in the write queue\n\t\t\tcurrentRead = [readQueue objectAtIndex:0];\n\t\t\t[readQueue removeObjectAtIndex:0];\n\t\t\t\n\t\t\t\n\t\t\tif ([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]])\n\t\t\t{\n\t\t\t\tLogVerbose(@\"Dequeued GCDAsyncSpecialPacket\");\n\t\t\t\t\n\t\t\t\t// Attempt to start TLS\n\t\t\t\tflags |= kStartingReadTLS;\n\t\t\t\t\n\t\t\t\t// This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set\n\t\t\t\t[self maybeStartTLS];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLogVerbose(@\"Dequeued GCDAsyncReadPacket\");\n\t\t\t\t\n\t\t\t\t// Setup read timer (if needed)\n\t\t\t\t[self setupReadTimerWithTimeout:currentRead->timeout];\n\t\t\t\t\n\t\t\t\t// Immediately read, if possible\n\t\t\t\t[self doReadData];\n\t\t\t}\n\t\t}\n\t\telse if (flags & kDisconnectAfterReads)\n\t\t{\n\t\t\tif (flags & kDisconnectAfterWrites)\n\t\t\t{\n\t\t\t\tif (([writeQueue count] == 0) && (currentWrite == nil))\n\t\t\t\t{\n\t\t\t\t\t[self closeWithError:nil];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[self closeWithError:nil];\n\t\t\t}\n\t\t}\n\t\telse if (flags & kSocketSecure)\n\t\t{\n\t\t\t[self flushSSLBuffers];\n\t\t\t\n\t\t\t// Edge case:\n\t\t\t// \n\t\t\t// We just drained all data from the ssl buffers,\n\t\t\t// and all known data from the socket (socketFDBytesAvailable).\n\t\t\t// \n\t\t\t// If we didn't get any data from this process,\n\t\t\t// then we may have reached the end of the TCP stream.\n\t\t\t// \n\t\t\t// Be sure callbacks are enabled so we're notified about a disconnection.\n\t\t\t\n\t\t\tif ([preBuffer availableBytes] == 0)\n\t\t\t{\n\t\t\t\tif ([self usingCFStreamForTLS]) {\n\t\t\t\t\t// Callbacks never disabled\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t[self resumeReadSource];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)flushSSLBuffers\n{\n\tLogTrace();\n\t\n\tNSAssert((flags & kSocketSecure), @\"Cannot flush ssl buffers on non-secure socket\");\n\t\n\tif ([preBuffer availableBytes] > 0)\n\t{\n\t\t// Only flush the ssl buffers if the prebuffer is empty.\n\t\t// This is to avoid growing the prebuffer inifinitely large.\n\t\t\n\t\treturn;\n\t}\n\t\n\t#if TARGET_OS_IPHONE\n\t\n\tif ([self usingCFStreamForTLS])\n\t{\n\t\tif ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))\n\t\t{\n\t\t\tLogVerbose(@\"%@ - Flushing ssl buffers into prebuffer...\", THIS_METHOD);\n\t\t\t\n\t\t\tCFIndex defaultBytesToRead = (1024 * 4);\n\t\t\t\n\t\t\t[preBuffer ensureCapacityForWrite:defaultBytesToRead];\n\t\t\t\n\t\t\tuint8_t *buffer = [preBuffer writeBuffer];\n\t\t\t\n\t\t\tCFIndex result = CFReadStreamRead(readStream, buffer, defaultBytesToRead);\n\t\t\tLogVerbose(@\"%@ - CFReadStreamRead(): result = %i\", THIS_METHOD, (int)result);\n\t\t\t\n\t\t\tif (result > 0)\n\t\t\t{\n\t\t\t\t[preBuffer didWrite:result];\n\t\t\t}\n\t\t\t\n\t\t\tflags &= ~kSecureSocketHasBytesAvailable;\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\t\n\t#endif\n\t\n\t__block NSUInteger estimatedBytesAvailable = 0;\n\t\n\tdispatch_block_t updateEstimatedBytesAvailable = ^{\n\t\t\n\t\t// Figure out if there is any data available to be read\n\t\t// \n\t\t// socketFDBytesAvailable        <- Number of encrypted bytes we haven't read from the bsd socket\n\t\t// [sslPreBuffer availableBytes] <- Number of encrypted bytes we've buffered from bsd socket\n\t\t// sslInternalBufSize            <- Number of decrypted bytes SecureTransport has buffered\n\t\t// \n\t\t// We call the variable \"estimated\" because we don't know how many decrypted bytes we'll get\n\t\t// from the encrypted bytes in the sslPreBuffer.\n\t\t// However, we do know this is an upper bound on the estimation.\n\t\t\n\t\testimatedBytesAvailable = socketFDBytesAvailable + [sslPreBuffer availableBytes];\n\t\t\n\t\tsize_t sslInternalBufSize = 0;\n\t\tSSLGetBufferedReadSize(sslContext, &sslInternalBufSize);\n\t\t\n\t\testimatedBytesAvailable += sslInternalBufSize;\n\t};\n\t\n\tupdateEstimatedBytesAvailable();\n\t\n\tif (estimatedBytesAvailable > 0)\n\t{\n\t\tLogVerbose(@\"%@ - Flushing ssl buffers into prebuffer...\", THIS_METHOD);\n\t\t\n\t\tBOOL done = NO;\n\t\tdo\n\t\t{\n\t\t\tLogVerbose(@\"%@ - estimatedBytesAvailable = %lu\", THIS_METHOD, (unsigned long)estimatedBytesAvailable);\n\t\t\t\n\t\t\t// Make sure there's enough room in the prebuffer\n\t\t\t\n\t\t\t[preBuffer ensureCapacityForWrite:estimatedBytesAvailable];\n\t\t\t\n\t\t\t// Read data into prebuffer\n\t\t\t\n\t\t\tuint8_t *buffer = [preBuffer writeBuffer];\n\t\t\tsize_t bytesRead = 0;\n\t\t\t\n\t\t\tOSStatus result = SSLRead(sslContext, buffer, (size_t)estimatedBytesAvailable, &bytesRead);\n\t\t\tLogVerbose(@\"%@ - read from secure socket = %u\", THIS_METHOD, (unsigned)bytesRead);\n\t\t\t\n\t\t\tif (bytesRead > 0)\n\t\t\t{\n\t\t\t\t[preBuffer didWrite:bytesRead];\n\t\t\t}\n\t\t\t\n\t\t\tLogVerbose(@\"%@ - prebuffer.length = %zu\", THIS_METHOD, [preBuffer availableBytes]);\n\t\t\t\n\t\t\tif (result != noErr)\n\t\t\t{\n\t\t\t\tdone = YES;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tupdateEstimatedBytesAvailable();\n\t\t\t}\n\t\t\t\n\t\t} while (!done && estimatedBytesAvailable > 0);\n\t}\n}\n\n- (void)doReadData\n{\n\tLogTrace();\n\t\n\t// This method is called on the socketQueue.\n\t// It might be called directly, or via the readSource when data is available to be read.\n\t\n\tif ((currentRead == nil) || (flags & kReadsPaused))\n\t{\n\t\tLogVerbose(@\"No currentRead or kReadsPaused\");\n\t\t\n\t\t// Unable to read at this time\n\t\t\n\t\tif (flags & kSocketSecure)\n\t\t{\n\t\t\t// Here's the situation:\n\t\t\t// \n\t\t\t// We have an established secure connection.\n\t\t\t// There may not be a currentRead, but there might be encrypted data sitting around for us.\n\t\t\t// When the user does get around to issuing a read, that encrypted data will need to be decrypted.\n\t\t\t// \n\t\t\t// So why make the user wait?\n\t\t\t// We might as well get a head start on decrypting some data now.\n\t\t\t// \n\t\t\t// The other reason we do this has to do with detecting a socket disconnection.\n\t\t\t// The SSL/TLS protocol has it's own disconnection handshake.\n\t\t\t// So when a secure socket is closed, a \"goodbye\" packet comes across the wire.\n\t\t\t// We want to make sure we read the \"goodbye\" packet so we can properly detect the TCP disconnection.\n\t\t\t\n\t\t\t[self flushSSLBuffers];\n\t\t}\n\t\t\n\t\tif ([self usingCFStreamForTLS])\n\t\t{\n\t\t\t// CFReadStream only fires once when there is available data.\n\t\t\t// It won't fire again until we've invoked CFReadStreamRead.\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the readSource is firing, we need to pause it\n\t\t\t// or else it will continue to fire over and over again.\n\t\t\t// \n\t\t\t// If the readSource is not firing,\n\t\t\t// we want it to continue monitoring the socket.\n\t\t\t\n\t\t\tif (socketFDBytesAvailable > 0)\n\t\t\t{\n\t\t\t\t[self suspendReadSource];\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t\n\tBOOL hasBytesAvailable = NO;\n\tunsigned long estimatedBytesAvailable = 0;\n\t\n\tif ([self usingCFStreamForTLS])\n\t{\n\t\t#if TARGET_OS_IPHONE\n\t\t\n\t\t// Requested CFStream, rather than SecureTransport, for TLS (via GCDAsyncSocketUseCFStreamForTLS)\n\t\t\n\t\testimatedBytesAvailable = 0;\n\t\tif ((flags & kSecureSocketHasBytesAvailable) && CFReadStreamHasBytesAvailable(readStream))\n\t\t\thasBytesAvailable = YES;\n\t\telse\n\t\t\thasBytesAvailable = NO;\n\t\t\n\t\t#endif\n\t}\n\telse\n\t{\n\t\testimatedBytesAvailable = socketFDBytesAvailable;\n\t\t\n\t\tif (flags & kSocketSecure)\n\t\t{\n\t\t\t// There are 2 buffers to be aware of here.\n\t\t\t// \n\t\t\t// We are using SecureTransport, a TLS/SSL security layer which sits atop TCP.\n\t\t\t// We issue a read to the SecureTranport API, which in turn issues a read to our SSLReadFunction.\n\t\t\t// Our SSLReadFunction then reads from the BSD socket and returns the encrypted data to SecureTransport.\n\t\t\t// SecureTransport then decrypts the data, and finally returns the decrypted data back to us.\n\t\t\t// \n\t\t\t// The first buffer is one we create.\n\t\t\t// SecureTransport often requests small amounts of data.\n\t\t\t// This has to do with the encypted packets that are coming across the TCP stream.\n\t\t\t// But it's non-optimal to do a bunch of small reads from the BSD socket.\n\t\t\t// So our SSLReadFunction reads all available data from the socket (optimizing the sys call)\n\t\t\t// and may store excess in the sslPreBuffer.\n\t\t\t\n\t\t\testimatedBytesAvailable += [sslPreBuffer availableBytes];\n\t\t\t\n\t\t\t// The second buffer is within SecureTransport.\n\t\t\t// As mentioned earlier, there are encrypted packets coming across the TCP stream.\n\t\t\t// SecureTransport needs the entire packet to decrypt it.\n\t\t\t// But if the entire packet produces X bytes of decrypted data,\n\t\t\t// and we only asked SecureTransport for X/2 bytes of data,\n\t\t\t// it must store the extra X/2 bytes of decrypted data for the next read.\n\t\t\t// \n\t\t\t// The SSLGetBufferedReadSize function will tell us the size of this internal buffer.\n\t\t\t// From the documentation:\n\t\t\t// \n\t\t\t// \"This function does not block or cause any low-level read operations to occur.\"\n\t\t\t\n\t\t\tsize_t sslInternalBufSize = 0;\n\t\t\tSSLGetBufferedReadSize(sslContext, &sslInternalBufSize);\n\t\t\t\n\t\t\testimatedBytesAvailable += sslInternalBufSize;\n\t\t}\n\t\t\n\t\thasBytesAvailable = (estimatedBytesAvailable > 0);\n\t}\n\t\n\tif ((hasBytesAvailable == NO) && ([preBuffer availableBytes] == 0))\n\t{\n\t\tLogVerbose(@\"No data available to read...\");\n\t\t\n\t\t// No data available to read.\n\t\t\n\t\tif (![self usingCFStreamForTLS])\n\t\t{\n\t\t\t// Need to wait for readSource to fire and notify us of\n\t\t\t// available data in the socket's internal read buffer.\n\t\t\t\n\t\t\t[self resumeReadSource];\n\t\t}\n\t\treturn;\n\t}\n\t\n\tif (flags & kStartingReadTLS)\n\t{\n\t\tLogVerbose(@\"Waiting for SSL/TLS handshake to complete\");\n\t\t\n\t\t// The readQueue is waiting for SSL/TLS handshake to complete.\n\t\t\n\t\tif (flags & kStartingWriteTLS)\n\t\t{\n\t\t\tif ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)\n\t\t\t{\n\t\t\t\t// We are in the process of a SSL Handshake.\n\t\t\t\t// We were waiting for incoming data which has just arrived.\n\t\t\t\t\n\t\t\t\t[self ssl_continueSSLHandshake];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We are still waiting for the writeQueue to drain and start the SSL/TLS process.\n\t\t\t// We now know data is available to read.\n\t\t\t\n\t\t\tif (![self usingCFStreamForTLS])\n\t\t\t{\n\t\t\t\t// Suspend the read source or else it will continue to fire nonstop.\n\t\t\t\t\n\t\t\t\t[self suspendReadSource];\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\t\n\tBOOL done        = NO;  // Completed read operation\n\tNSError *error   = nil; // Error occurred\n\t\n\tNSUInteger totalBytesReadForCurrentRead = 0;\n\t\n\t// \n\t// STEP 1 - READ FROM PREBUFFER\n\t// \n\t\n\tif ([preBuffer availableBytes] > 0)\n\t{\n\t\t// There are 3 types of read packets:\n\t\t// \n\t\t// 1) Read all available data.\n\t\t// 2) Read a specific length of data.\n\t\t// 3) Read up to a particular terminator.\n\t\t\n\t\tNSUInteger bytesToCopy;\n\t\t\n\t\tif (currentRead->term != nil)\n\t\t{\n\t\t\t// Read type #3 - read up to a terminator\n\t\t\t\n\t\t\tbytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Read type #1 or #2\n\t\t\t\n\t\t\tbytesToCopy = [currentRead readLengthForNonTermWithHint:[preBuffer availableBytes]];\n\t\t}\n\t\t\n\t\t// Make sure we have enough room in the buffer for our read.\n\t\t\n\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];\n\t\t\n\t\t// Copy bytes from prebuffer into packet buffer\n\t\t\n\t\tuint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset +\n\t\t                                                                  currentRead->bytesDone;\n\t\t\n\t\tmemcpy(buffer, [preBuffer readBuffer], bytesToCopy);\n\t\t\n\t\t// Remove the copied bytes from the preBuffer\n\t\t[preBuffer didRead:bytesToCopy];\n\t\t\n\t\tLogVerbose(@\"copied(%lu) preBufferLength(%zu)\", (unsigned long)bytesToCopy, [preBuffer availableBytes]);\n\t\t\n\t\t// Update totals\n\t\t\n\t\tcurrentRead->bytesDone += bytesToCopy;\n\t\ttotalBytesReadForCurrentRead += bytesToCopy;\n\t\t\n\t\t// Check to see if the read operation is done\n\t\t\n\t\tif (currentRead->readLength > 0)\n\t\t{\n\t\t\t// Read type #2 - read a specific length of data\n\t\t\t\n\t\t\tdone = (currentRead->bytesDone == currentRead->readLength);\n\t\t}\n\t\telse if (currentRead->term != nil)\n\t\t{\n\t\t\t// Read type #3 - read up to a terminator\n\t\t\t\n\t\t\t// Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method\n\t\t\t\n\t\t\tif (!done && currentRead->maxLength > 0)\n\t\t\t{\n\t\t\t\t// We're not done and there's a set maxLength.\n\t\t\t\t// Have we reached that maxLength yet?\n\t\t\t\t\n\t\t\t\tif (currentRead->bytesDone >= currentRead->maxLength)\n\t\t\t\t{\n\t\t\t\t\terror = [self readMaxedOutError];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Read type #1 - read all available data\n\t\t\t// \n\t\t\t// We're done as soon as\n\t\t\t// - we've read all available data (in prebuffer and socket)\n\t\t\t// - we've read the maxLength of read packet.\n\t\t\t\n\t\t\tdone = ((currentRead->maxLength > 0) && (currentRead->bytesDone == currentRead->maxLength));\n\t\t}\n\t\t\n\t}\n\t\n\t// \n\t// STEP 2 - READ FROM SOCKET\n\t// \n\t\n\tBOOL socketEOF = (flags & kSocketHasReadEOF) ? YES : NO;  // Nothing more to read via socket (end of file)\n\tBOOL waiting   = !done && !error && !socketEOF && !hasBytesAvailable; // Ran out of data, waiting for more\n\t\n\tif (!done && !error && !socketEOF && hasBytesAvailable)\n\t{\n\t\tNSAssert(([preBuffer availableBytes] == 0), @\"Invalid logic\");\n\t\t\n\t\tBOOL readIntoPreBuffer = NO;\n\t\tuint8_t *buffer = NULL;\n\t\tsize_t bytesRead = 0;\n\t\t\n\t\tif (flags & kSocketSecure)\n\t\t{\n\t\t\tif ([self usingCFStreamForTLS])\n\t\t\t{\n\t\t\t\t#if TARGET_OS_IPHONE\n\t\t\t\t\n\t\t\t\t// Using CFStream, rather than SecureTransport, for TLS\n\t\t\t\t\n\t\t\t\tNSUInteger defaultReadLength = (1024 * 32);\n\t\t\t\t\n\t\t\t\tNSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength\n\t\t\t\t                                                   shouldPreBuffer:&readIntoPreBuffer];\n\t\t\t\t\n\t\t\t\t// Make sure we have enough room in the buffer for our read.\n\t\t\t\t//\n\t\t\t\t// We are either reading directly into the currentRead->buffer,\n\t\t\t\t// or we're reading into the temporary preBuffer.\n\t\t\t\t\n\t\t\t\tif (readIntoPreBuffer)\n\t\t\t\t{\n\t\t\t\t\t[preBuffer ensureCapacityForWrite:bytesToRead];\n\t\t\t\t\t\n\t\t\t\t\tbuffer = [preBuffer writeBuffer];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];\n\t\t\t\t\t\n\t\t\t\t\tbuffer = (uint8_t *)[currentRead->buffer mutableBytes]\n\t\t\t\t\t       + currentRead->startOffset\n\t\t\t\t\t       + currentRead->bytesDone;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Read data into buffer\n\t\t\t\t\n\t\t\t\tCFIndex result = CFReadStreamRead(readStream, buffer, (CFIndex)bytesToRead);\n\t\t\t\tLogVerbose(@\"CFReadStreamRead(): result = %i\", (int)result);\n\t\t\t\t\n\t\t\t\tif (result < 0)\n\t\t\t\t{\n\t\t\t\t\terror = (__bridge_transfer NSError *)CFReadStreamCopyError(readStream);\n\t\t\t\t}\n\t\t\t\telse if (result == 0)\n\t\t\t\t{\n\t\t\t\t\tsocketEOF = YES;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\twaiting = YES;\n\t\t\t\t\tbytesRead = (size_t)result;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// We only know how many decrypted bytes were read.\n\t\t\t\t// The actual number of bytes read was likely more due to the overhead of the encryption.\n\t\t\t\t// So we reset our flag, and rely on the next callback to alert us of more data.\n\t\t\t\tflags &= ~kSecureSocketHasBytesAvailable;\n\t\t\t\t\n\t\t\t\t#endif\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Using SecureTransport for TLS\n\t\t\t\t//\n\t\t\t\t// We know:\n\t\t\t\t// - how many bytes are available on the socket\n\t\t\t\t// - how many encrypted bytes are sitting in the sslPreBuffer\n\t\t\t\t// - how many decypted bytes are sitting in the sslContext\n\t\t\t\t//\n\t\t\t\t// But we do NOT know:\n\t\t\t\t// - how many encypted bytes are sitting in the sslContext\n\t\t\t\t//\n\t\t\t\t// So we play the regular game of using an upper bound instead.\n\t\t\t\t\n\t\t\t\tNSUInteger defaultReadLength = (1024 * 32);\n\t\t\t\t\n\t\t\t\tif (defaultReadLength < estimatedBytesAvailable) {\n\t\t\t\t\tdefaultReadLength = estimatedBytesAvailable + (1024 * 16);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tNSUInteger bytesToRead = [currentRead optimalReadLengthWithDefault:defaultReadLength\n\t\t\t\t                                                   shouldPreBuffer:&readIntoPreBuffer];\n\t\t\t\t\n\t\t\t\tif (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t\n\t\t\t\t\tbytesToRead = SIZE_MAX;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Make sure we have enough room in the buffer for our read.\n\t\t\t\t//\n\t\t\t\t// We are either reading directly into the currentRead->buffer,\n\t\t\t\t// or we're reading into the temporary preBuffer.\n\t\t\t\t\n\t\t\t\tif (readIntoPreBuffer)\n\t\t\t\t{\n\t\t\t\t\t[preBuffer ensureCapacityForWrite:bytesToRead];\n\t\t\t\t\t\n\t\t\t\t\tbuffer = [preBuffer writeBuffer];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];\n\t\t\t\t\t\n\t\t\t\t\tbuffer = (uint8_t *)[currentRead->buffer mutableBytes]\n\t\t\t\t\t       + currentRead->startOffset\n\t\t\t\t\t       + currentRead->bytesDone;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// The documentation from Apple states:\n\t\t\t\t// \n\t\t\t\t//     \"a read operation might return errSSLWouldBlock,\n\t\t\t\t//      indicating that less data than requested was actually transferred\"\n\t\t\t\t// \n\t\t\t\t// However, starting around 10.7, the function will sometimes return noErr,\n\t\t\t\t// even if it didn't read as much data as requested. So we need to watch out for that.\n\t\t\t\t\n\t\t\t\tOSStatus result;\n\t\t\t\tdo\n\t\t\t\t{\n\t\t\t\t\tvoid *loop_buffer = buffer + bytesRead;\n\t\t\t\t\tsize_t loop_bytesToRead = (size_t)bytesToRead - bytesRead;\n\t\t\t\t\tsize_t loop_bytesRead = 0;\n\t\t\t\t\t\n\t\t\t\t\tresult = SSLRead(sslContext, loop_buffer, loop_bytesToRead, &loop_bytesRead);\n\t\t\t\t\tLogVerbose(@\"read from secure socket = %u\", (unsigned)loop_bytesRead);\n\t\t\t\t\t\n\t\t\t\t\tbytesRead += loop_bytesRead;\n\t\t\t\t\t\n\t\t\t\t} while ((result == noErr) && (bytesRead < bytesToRead));\n\t\t\t\t\n\t\t\t\t\n\t\t\t\tif (result != noErr)\n\t\t\t\t{\n\t\t\t\t\tif (result == errSSLWouldBlock)\n\t\t\t\t\t\twaiting = YES;\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result == errSSLClosedGraceful || result == errSSLClosedAbort)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// We've reached the end of the stream.\n\t\t\t\t\t\t\t// Handle this the same way we would an EOF from the socket.\n\t\t\t\t\t\t\tsocketEOF = YES;\n\t\t\t\t\t\t\tsslErrCode = result;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror = [self sslError:result];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// It's possible that bytesRead > 0, even if the result was errSSLWouldBlock.\n\t\t\t\t\t// This happens when the SSLRead function is able to read some data,\n\t\t\t\t\t// but not the entire amount we requested.\n\t\t\t\t\t\n\t\t\t\t\tif (bytesRead <= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tbytesRead = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Do not modify socketFDBytesAvailable.\n\t\t\t\t// It will be updated via the SSLReadFunction().\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Normal socket operation\n\t\t\t\n\t\t\tNSUInteger bytesToRead;\n\t\t\t\n\t\t\t// There are 3 types of read packets:\n\t\t\t//\n\t\t\t// 1) Read all available data.\n\t\t\t// 2) Read a specific length of data.\n\t\t\t// 3) Read up to a particular terminator.\n\t\t\t\n\t\t\tif (currentRead->term != nil)\n\t\t\t{\n\t\t\t\t// Read type #3 - read up to a terminator\n\t\t\t\t\n\t\t\t\tbytesToRead = [currentRead readLengthForTermWithHint:estimatedBytesAvailable\n\t\t\t\t                                     shouldPreBuffer:&readIntoPreBuffer];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Read type #1 or #2\n\t\t\t\t\n\t\t\t\tbytesToRead = [currentRead readLengthForNonTermWithHint:estimatedBytesAvailable];\n\t\t\t}\n\t\t\t\n\t\t\tif (bytesToRead > SIZE_MAX) { // NSUInteger may be bigger than size_t (read param 3)\n\t\t\t\tbytesToRead = SIZE_MAX;\n\t\t\t}\n\t\t\t\n\t\t\t// Make sure we have enough room in the buffer for our read.\n\t\t\t//\n\t\t\t// We are either reading directly into the currentRead->buffer,\n\t\t\t// or we're reading into the temporary preBuffer.\n\t\t\t\n\t\t\tif (readIntoPreBuffer)\n\t\t\t{\n\t\t\t\t[preBuffer ensureCapacityForWrite:bytesToRead];\n\t\t\t\t\n\t\t\t\tbuffer = [preBuffer writeBuffer];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesToRead];\n\t\t\t\t\n\t\t\t\tbuffer = (uint8_t *)[currentRead->buffer mutableBytes]\n\t\t\t\t       + currentRead->startOffset\n\t\t\t\t       + currentRead->bytesDone;\n\t\t\t}\n\t\t\t\n\t\t\t// Read data into buffer\n\t\t\t\n\t\t\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\t\t\n\t\t\tssize_t result = read(socketFD, buffer, (size_t)bytesToRead);\n\t\t\tLogVerbose(@\"read from socket = %i\", (int)result);\n\t\t\t\n\t\t\tif (result < 0)\n\t\t\t{\n\t\t\t\tif (errno == EWOULDBLOCK)\n\t\t\t\t\twaiting = YES;\n\t\t\t\telse\n\t\t\t\t\terror = [self errnoErrorWithReason:@\"Error in read() function\"];\n\t\t\t\t\n\t\t\t\tsocketFDBytesAvailable = 0;\n\t\t\t}\n\t\t\telse if (result == 0)\n\t\t\t{\n\t\t\t\tsocketEOF = YES;\n\t\t\t\tsocketFDBytesAvailable = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbytesRead = result;\n\t\t\t\t\n\t\t\t\tif (bytesRead < bytesToRead)\n\t\t\t\t{\n\t\t\t\t\t// The read returned less data than requested.\n\t\t\t\t\t// This means socketFDBytesAvailable was a bit off due to timing,\n\t\t\t\t\t// because we read from the socket right when the readSource event was firing.\n\t\t\t\t\tsocketFDBytesAvailable = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (socketFDBytesAvailable <= bytesRead)\n\t\t\t\t\t\tsocketFDBytesAvailable = 0;\n\t\t\t\t\telse\n\t\t\t\t\t\tsocketFDBytesAvailable -= bytesRead;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (socketFDBytesAvailable == 0)\n\t\t\t\t{\n\t\t\t\t\twaiting = YES;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (bytesRead > 0)\n\t\t{\n\t\t\t// Check to see if the read operation is done\n\t\t\t\n\t\t\tif (currentRead->readLength > 0)\n\t\t\t{\n\t\t\t\t// Read type #2 - read a specific length of data\n\t\t\t\t// \n\t\t\t\t// Note: We should never be using a prebuffer when we're reading a specific length of data.\n\t\t\t\t\n\t\t\t\tNSAssert(readIntoPreBuffer == NO, @\"Invalid logic\");\n\t\t\t\t\n\t\t\t\tcurrentRead->bytesDone += bytesRead;\n\t\t\t\ttotalBytesReadForCurrentRead += bytesRead;\n\t\t\t\t\n\t\t\t\tdone = (currentRead->bytesDone == currentRead->readLength);\n\t\t\t}\n\t\t\telse if (currentRead->term != nil)\n\t\t\t{\n\t\t\t\t// Read type #3 - read up to a terminator\n\t\t\t\t\n\t\t\t\tif (readIntoPreBuffer)\n\t\t\t\t{\n\t\t\t\t\t// We just read a big chunk of data into the preBuffer\n\t\t\t\t\t\n\t\t\t\t\t[preBuffer didWrite:bytesRead];\n\t\t\t\t\tLogVerbose(@\"read data into preBuffer - preBuffer.length = %zu\", [preBuffer availableBytes]);\n\t\t\t\t\t\n\t\t\t\t\t// Search for the terminating sequence\n\t\t\t\t\t\n\t\t\t\t\tNSUInteger bytesToCopy = [currentRead readLengthForTermWithPreBuffer:preBuffer found:&done];\n\t\t\t\t\tLogVerbose(@\"copying %lu bytes from preBuffer\", (unsigned long)bytesToCopy);\n\t\t\t\t\t\n\t\t\t\t\t// Ensure there's room on the read packet's buffer\n\t\t\t\t\t\n\t\t\t\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesToCopy];\n\t\t\t\t\t\n\t\t\t\t\t// Copy bytes from prebuffer into read buffer\n\t\t\t\t\t\n\t\t\t\t\tuint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset\n\t\t\t\t\t                                                                 + currentRead->bytesDone;\n\t\t\t\t\t\n\t\t\t\t\tmemcpy(readBuf, [preBuffer readBuffer], bytesToCopy);\n\t\t\t\t\t\n\t\t\t\t\t// Remove the copied bytes from the prebuffer\n\t\t\t\t\t[preBuffer didRead:bytesToCopy];\n\t\t\t\t\tLogVerbose(@\"preBuffer.length = %zu\", [preBuffer availableBytes]);\n\t\t\t\t\t\n\t\t\t\t\t// Update totals\n\t\t\t\t\tcurrentRead->bytesDone += bytesToCopy;\n\t\t\t\t\ttotalBytesReadForCurrentRead += bytesToCopy;\n\t\t\t\t\t\n\t\t\t\t\t// Our 'done' variable was updated via the readLengthForTermWithPreBuffer:found: method above\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// We just read a big chunk of data directly into the packet's buffer.\n\t\t\t\t\t// We need to move any overflow into the prebuffer.\n\t\t\t\t\t\n\t\t\t\t\tNSInteger overflow = [currentRead searchForTermAfterPreBuffering:bytesRead];\n\t\t\t\t\t\n\t\t\t\t\tif (overflow == 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Perfect match!\n\t\t\t\t\t\t// Every byte we read stays in the read buffer,\n\t\t\t\t\t\t// and the last byte we read was the last byte of the term.\n\t\t\t\t\t\t\n\t\t\t\t\t\tcurrentRead->bytesDone += bytesRead;\n\t\t\t\t\t\ttotalBytesReadForCurrentRead += bytesRead;\n\t\t\t\t\t\tdone = YES;\n\t\t\t\t\t}\n\t\t\t\t\telse if (overflow > 0)\n\t\t\t\t\t{\n\t\t\t\t\t\t// The term was found within the data that we read,\n\t\t\t\t\t\t// and there are extra bytes that extend past the end of the term.\n\t\t\t\t\t\t// We need to move these excess bytes out of the read packet and into the prebuffer.\n\t\t\t\t\t\t\n\t\t\t\t\t\tNSInteger underflow = bytesRead - overflow;\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Copy excess data into preBuffer\n\t\t\t\t\t\t\n\t\t\t\t\t\tLogVerbose(@\"copying %ld overflow bytes into preBuffer\", (long)overflow);\n\t\t\t\t\t\t[preBuffer ensureCapacityForWrite:overflow];\n\t\t\t\t\t\t\n\t\t\t\t\t\tuint8_t *overflowBuffer = buffer + underflow;\n\t\t\t\t\t\tmemcpy([preBuffer writeBuffer], overflowBuffer, overflow);\n\t\t\t\t\t\t\n\t\t\t\t\t\t[preBuffer didWrite:overflow];\n\t\t\t\t\t\tLogVerbose(@\"preBuffer.length = %zu\", [preBuffer availableBytes]);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Note: The completeCurrentRead method will trim the buffer for us.\n\t\t\t\t\t\t\n\t\t\t\t\t\tcurrentRead->bytesDone += underflow;\n\t\t\t\t\t\ttotalBytesReadForCurrentRead += underflow;\n\t\t\t\t\t\tdone = YES;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t// The term was not found within the data that we read.\n\t\t\t\t\t\t\n\t\t\t\t\t\tcurrentRead->bytesDone += bytesRead;\n\t\t\t\t\t\ttotalBytesReadForCurrentRead += bytesRead;\n\t\t\t\t\t\tdone = NO;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (!done && currentRead->maxLength > 0)\n\t\t\t\t{\n\t\t\t\t\t// We're not done and there's a set maxLength.\n\t\t\t\t\t// Have we reached that maxLength yet?\n\t\t\t\t\t\n\t\t\t\t\tif (currentRead->bytesDone >= currentRead->maxLength)\n\t\t\t\t\t{\n\t\t\t\t\t\terror = [self readMaxedOutError];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Read type #1 - read all available data\n\t\t\t\t\n\t\t\t\tif (readIntoPreBuffer)\n\t\t\t\t{\n\t\t\t\t\t// We just read a chunk of data into the preBuffer\n\t\t\t\t\t\n\t\t\t\t\t[preBuffer didWrite:bytesRead];\n\t\t\t\t\t\n\t\t\t\t\t// Now copy the data into the read packet.\n\t\t\t\t\t// \n\t\t\t\t\t// Recall that we didn't read directly into the packet's buffer to avoid\n\t\t\t\t\t// over-allocating memory since we had no clue how much data was available to be read.\n\t\t\t\t\t// \n\t\t\t\t\t// Ensure there's room on the read packet's buffer\n\t\t\t\t\t\n\t\t\t\t\t[currentRead ensureCapacityForAdditionalDataOfLength:bytesRead];\n\t\t\t\t\t\n\t\t\t\t\t// Copy bytes from prebuffer into read buffer\n\t\t\t\t\t\n\t\t\t\t\tuint8_t *readBuf = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset\n\t\t\t\t\t                                                                 + currentRead->bytesDone;\n\t\t\t\t\t\n\t\t\t\t\tmemcpy(readBuf, [preBuffer readBuffer], bytesRead);\n\t\t\t\t\t\n\t\t\t\t\t// Remove the copied bytes from the prebuffer\n\t\t\t\t\t[preBuffer didRead:bytesRead];\n\t\t\t\t\t\n\t\t\t\t\t// Update totals\n\t\t\t\t\tcurrentRead->bytesDone += bytesRead;\n\t\t\t\t\ttotalBytesReadForCurrentRead += bytesRead;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tcurrentRead->bytesDone += bytesRead;\n\t\t\t\t\ttotalBytesReadForCurrentRead += bytesRead;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdone = YES;\n\t\t\t}\n\t\t\t\n\t\t} // if (bytesRead > 0)\n\t\t\n\t} // if (!done && !error && !socketEOF && hasBytesAvailable)\n\t\n\t\n\tif (!done && currentRead->readLength == 0 && currentRead->term == nil)\n\t{\n\t\t// Read type #1 - read all available data\n\t\t// \n\t\t// We might arrive here if we read data from the prebuffer but not from the socket.\n\t\t\n\t\tdone = (totalBytesReadForCurrentRead > 0);\n\t}\n\t\n\t// Check to see if we're done, or if we've made progress\n\t\n\tif (done)\n\t{\n\t\t[self completeCurrentRead];\n\t\t\n\t\tif (!error && (!socketEOF || [preBuffer availableBytes] > 0))\n\t\t{\n\t\t\t[self maybeDequeueRead];\n\t\t}\n\t}\n\telse if (totalBytesReadForCurrentRead > 0)\n\t{\n\t\t// We're not done read type #2 or #3 yet, but we have read in some bytes\n\n\t\t__strong id theDelegate = delegate;\n\t\t\n\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadPartialDataOfLength:tag:)])\n\t\t{\n\t\t\tlong theReadTag = currentRead->tag;\n\t\t\t\n\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[theDelegate socket:self didReadPartialDataOfLength:totalBytesReadForCurrentRead tag:theReadTag];\n\t\t\t}});\n\t\t}\n\t}\n\t\n\t// Check for errors\n\t\n\tif (error)\n\t{\n\t\t[self closeWithError:error];\n\t}\n\telse if (socketEOF)\n\t{\n\t\t[self doReadEOF];\n\t}\n\telse if (waiting)\n\t{\n\t\tif (![self usingCFStreamForTLS])\n\t\t{\n\t\t\t// Monitor the socket for readability (if we're not already doing so)\n\t\t\t[self resumeReadSource];\n\t\t}\n\t}\n\t\n\t// Do not add any code here without first adding return statements in the error cases above.\n}\n\n- (void)doReadEOF\n{\n\tLogTrace();\n\t\n\t// This method may be called more than once.\n\t// If the EOF is read while there is still data in the preBuffer,\n\t// then this method may be called continually after invocations of doReadData to see if it's time to disconnect.\n\t\n\tflags |= kSocketHasReadEOF;\n\t\n\tif (flags & kSocketSecure)\n\t{\n\t\t// If the SSL layer has any buffered data, flush it into the preBuffer now.\n\t\t\n\t\t[self flushSSLBuffers];\n\t}\n\t\n\tBOOL shouldDisconnect = NO;\n\tNSError *error = nil;\n\t\n\tif ((flags & kStartingReadTLS) || (flags & kStartingWriteTLS))\n\t{\n\t\t// We received an EOF during or prior to startTLS.\n\t\t// The SSL/TLS handshake is now impossible, so this is an unrecoverable situation.\n\t\t\n\t\tshouldDisconnect = YES;\n\t\t\n\t\tif ([self usingSecureTransportForTLS])\n\t\t{\n\t\t\terror = [self sslError:errSSLClosedAbort];\n\t\t}\n\t}\n\telse if (flags & kReadStreamClosed)\n\t{\n\t\t// The preBuffer has already been drained.\n\t\t// The config allows half-duplex connections.\n\t\t// We've previously checked the socket, and it appeared writeable.\n\t\t// So we marked the read stream as closed and notified the delegate.\n\t\t// \n\t\t// As per the half-duplex contract, the socket will be closed when a write fails,\n\t\t// or when the socket is manually closed.\n\t\t\n\t\tshouldDisconnect = NO;\n\t}\n\telse if ([preBuffer availableBytes] > 0)\n\t{\n\t\tLogVerbose(@\"Socket reached EOF, but there is still data available in prebuffer\");\n\t\t\n\t\t// Although we won't be able to read any more data from the socket,\n\t\t// there is existing data that has been prebuffered that we can read.\n\t\t\n\t\tshouldDisconnect = NO;\n\t}\n\telse if (config & kAllowHalfDuplexConnection)\n\t{\n\t\t// We just received an EOF (end of file) from the socket's read stream.\n\t\t// This means the remote end of the socket (the peer we're connected to)\n\t\t// has explicitly stated that it will not be sending us any more data.\n\t\t// \n\t\t// Query the socket to see if it is still writeable. (Perhaps the peer will continue reading data from us)\n\n#if GCDAsyncSocketReadEOFPollsSocketForWriteStatus == 1\n\t\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\t\n\t\tstruct pollfd pfd[1];\n\t\tpfd[0].fd = socketFD;\n\t\tpfd[0].events = POLLOUT;\n\t\tpfd[0].revents = 0;\n\t\t\n\t\tpoll(pfd, 1, 0);\n\t\t\n\t\tif (pfd[0].revents & POLLOUT)\n\t\t{\n\t\t\t// Socket appears to still be writeable\n#endif\n\n\t\t\tshouldDisconnect = NO;\n\t\t\tflags |= kReadStreamClosed;\n\t\t\t\n\t\t\t// Notify the delegate that we're going half-duplex\n\t\t\t\n\t\t\t__strong id theDelegate = delegate;\n\n\t\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidCloseReadStream:)])\n\t\t\t{\n\t\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\t\n\t\t\t\t\t[theDelegate socketDidCloseReadStream:self];\n\t\t\t\t}});\n\t\t\t}\n\n#if GCDAsyncSocketReadEOFPollsSocketForWriteStatus == 1\n\t\t}\n\t\telse\n\t\t{\n\t\t\tshouldDisconnect = YES;\n\t\t}\n#endif\n\n\t}\n\telse\n\t{\n\t\tshouldDisconnect = YES;\n\t}\n\t\n\t\n\tif (shouldDisconnect)\n\t{\n\t\tif (error == nil)\n\t\t{\n\t\t\tif ([self usingSecureTransportForTLS])\n\t\t\t{\n\t\t\t\tif (sslErrCode != noErr && sslErrCode != errSSLClosedGraceful)\n\t\t\t\t{\n\t\t\t\t\terror = [self sslError:sslErrCode];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\terror = [self connectionClosedError];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\terror = [self connectionClosedError];\n\t\t\t}\n\t\t}\n\t\t[self closeWithError:error];\n\t}\n\telse\n\t{\n\t\tif (![self usingCFStreamForTLS])\n\t\t{\n\t\t\t// Suspend the read source (if needed)\n\t\t\t\n\t\t\t[self suspendReadSource];\n\t\t}\n\t}\n}\n\n- (void)completeCurrentRead\n{\n\tLogTrace();\n\t\n\tNSAssert(currentRead, @\"Trying to complete current read when there is no current read.\");\n\t\n\t\n\tNSData *result = nil;\n\t\n\tif (currentRead->bufferOwner)\n\t{\n\t\t// We created the buffer on behalf of the user.\n\t\t// Trim our buffer to be the proper size.\n\t\t[currentRead->buffer setLength:currentRead->bytesDone];\n\t\t\n\t\tresult = currentRead->buffer;\n\t}\n\telse\n\t{\n\t\t// We did NOT create the buffer.\n\t\t// The buffer is owned by the caller.\n\t\t// Only trim the buffer if we had to increase its size.\n\t\t\n\t\tif ([currentRead->buffer length] > currentRead->originalBufferLength)\n\t\t{\n\t\t\tNSUInteger readSize = currentRead->startOffset + currentRead->bytesDone;\n\t\t\tNSUInteger origSize = currentRead->originalBufferLength;\n\t\t\t\n\t\t\tNSUInteger buffSize = MAX(readSize, origSize);\n\t\t\t\n\t\t\t[currentRead->buffer setLength:buffSize];\n\t\t}\n\t\t\n\t\tuint8_t *buffer = (uint8_t *)[currentRead->buffer mutableBytes] + currentRead->startOffset;\n\t\t\n\t\tresult = [NSData dataWithBytesNoCopy:buffer length:currentRead->bytesDone freeWhenDone:NO];\n\t}\n\t\n\t__strong id theDelegate = delegate;\n\n\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReadData:withTag:)])\n\t{\n\t\tGCDAsyncReadPacket *theRead = currentRead; // Ensure currentRead retained since result may not own buffer\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t[theDelegate socket:self didReadData:result withTag:theRead->tag];\n\t\t}});\n\t}\n\t\n\t[self endCurrentRead];\n}\n\n- (void)endCurrentRead\n{\n\tif (readTimer)\n\t{\n\t\tdispatch_source_cancel(readTimer);\n\t\treadTimer = NULL;\n\t}\n\t\n\tcurrentRead = nil;\n}\n\n- (void)setupReadTimerWithTimeout:(NSTimeInterval)timeout\n{\n\tif (timeout >= 0.0)\n\t{\n\t\tunsigned long readTimerMask = 0;\n\n\t\tif (config & kUseStrictTimers) {\n\t\t\treadTimerMask = DISPATCH_TIMER_STRICT;\n\t\t}\n\n\t\treadTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, readTimerMask, socketQueue);\n\n\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\n\t\tdispatch_source_set_event_handler(readTimer, ^{ @autoreleasepool {\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\n\t\t\t[strongSelf doReadTimeout];\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t}});\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tdispatch_source_t theReadTimer = readTimer;\n\t\tdispatch_source_set_cancel_handler(readTimer, ^{\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\tLogVerbose(@\"dispatch_release(readTimer)\");\n\t\t\tdispatch_release(theReadTimer);\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t});\n\t\t#endif\n\t\t\n\t\tdispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));\n\t\t\n\t\tdispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);\n\t\tdispatch_resume(readTimer);\n\t}\n}\n\n- (void)doReadTimeout\n{\n\t// This is a little bit tricky.\n\t// Ideally we'd like to synchronously query the delegate about a timeout extension.\n\t// But if we do so synchronously we risk a possible deadlock.\n\t// So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.\n\t\n\tflags |= kReadsPaused;\n\t\n\t__strong id theDelegate = delegate;\n\n\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutReadWithTag:elapsed:bytesDone:)])\n\t{\n\t\tGCDAsyncReadPacket *theRead = currentRead;\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tNSTimeInterval timeoutExtension = 0.0;\n\t\t\t\n\t\t\ttimeoutExtension = [theDelegate socket:self shouldTimeoutReadWithTag:theRead->tag\n\t\t\t                                                             elapsed:theRead->timeout\n\t\t\t                                                           bytesDone:theRead->bytesDone];\n\t\t\t\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[self doReadTimeoutWithExtension:timeoutExtension];\n\t\t\t}});\n\t\t}});\n\t}\n\telse\n\t{\n\t\t[self doReadTimeoutWithExtension:0.0];\n\t}\n}\n\n- (void)doReadTimeoutWithExtension:(NSTimeInterval)timeoutExtension\n{\n\tif (currentRead)\n\t{\n\t\tif (timeoutExtension > 0.0)\n\t\t{\n\t\t\tcurrentRead->timeout += timeoutExtension;\n\t\t\t\n\t\t\t// Reschedule the timer\n\t\t\tdispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));\n\t\t\tdispatch_source_set_timer(readTimer, tt, DISPATCH_TIME_FOREVER, 0);\n\t\t\t\n\t\t\t// Unpause reads, and continue\n\t\t\tflags &= ~kReadsPaused;\n\t\t\t[self doReadData];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLogVerbose(@\"ReadTimeout\");\n\t\t\t\n\t\t\t[self closeWithError:[self readTimeoutError]];\n\t\t}\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Writing\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag\n{\n\tif ([data length] == 0) return;\n\t\n\tGCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];\n\t\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tLogTrace();\n\t\t\n\t\tif ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))\n\t\t{\n\t\t\t[writeQueue addObject:packet];\n\t\t\t[self maybeDequeueWrite];\n\t\t}\n\t}});\n\t\n\t// Do not rely on the block being run in order to release the packet,\n\t// as the queue might get released without the block completing.\n}\n\n- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr\n{\n\t__block float result = 0.0F;\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (!currentWrite || ![currentWrite isKindOfClass:[GCDAsyncWritePacket class]])\n\t\t{\n\t\t\t// We're not writing anything right now.\n\t\t\t\n\t\t\tif (tagPtr != NULL)   *tagPtr = 0;\n\t\t\tif (donePtr != NULL)  *donePtr = 0;\n\t\t\tif (totalPtr != NULL) *totalPtr = 0;\n\t\t\t\n\t\t\tresult = NAN;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSUInteger done = currentWrite->bytesDone;\n\t\t\tNSUInteger total = [currentWrite->buffer length];\n\t\t\t\n\t\t\tif (tagPtr != NULL)   *tagPtr = currentWrite->tag;\n\t\t\tif (donePtr != NULL)  *donePtr = done;\n\t\t\tif (totalPtr != NULL) *totalPtr = total;\n\t\t\t\n\t\t\tresult = (float)done / (float)total;\n\t\t}\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n\t\n\treturn result;\n}\n\n/**\n * Conditionally starts a new write.\n * \n * It is called when:\n * - a user requests a write\n * - after a write request has finished (to handle the next request)\n * - immediately after the socket opens to handle any pending requests\n * \n * This method also handles auto-disconnect post read/write completion.\n**/\n- (void)maybeDequeueWrite\n{\n\tLogTrace();\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t\n\t// If we're not currently processing a write AND we have an available write stream\n\tif ((currentWrite == nil) && (flags & kConnected))\n\t{\n\t\tif ([writeQueue count] > 0)\n\t\t{\n\t\t\t// Dequeue the next object in the write queue\n\t\t\tcurrentWrite = [writeQueue objectAtIndex:0];\n\t\t\t[writeQueue removeObjectAtIndex:0];\n\t\t\t\n\t\t\t\n\t\t\tif ([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]])\n\t\t\t{\n\t\t\t\tLogVerbose(@\"Dequeued GCDAsyncSpecialPacket\");\n\t\t\t\t\n\t\t\t\t// Attempt to start TLS\n\t\t\t\tflags |= kStartingWriteTLS;\n\t\t\t\t\n\t\t\t\t// This method won't do anything unless both kStartingReadTLS and kStartingWriteTLS are set\n\t\t\t\t[self maybeStartTLS];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLogVerbose(@\"Dequeued GCDAsyncWritePacket\");\n\t\t\t\t\n\t\t\t\t// Setup write timer (if needed)\n\t\t\t\t[self setupWriteTimerWithTimeout:currentWrite->timeout];\n\t\t\t\t\n\t\t\t\t// Immediately write, if possible\n\t\t\t\t[self doWriteData];\n\t\t\t}\n\t\t}\n\t\telse if (flags & kDisconnectAfterWrites)\n\t\t{\n\t\t\tif (flags & kDisconnectAfterReads)\n\t\t\t{\n\t\t\t\tif (([readQueue count] == 0) && (currentRead == nil))\n\t\t\t\t{\n\t\t\t\t\t[self closeWithError:nil];\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t[self closeWithError:nil];\n\t\t\t}\n\t\t}\n\t}\n}\n\n- (void)doWriteData\n{\n\tLogTrace();\n\t\n\t// This method is called by the writeSource via the socketQueue\n\t\n\tif ((currentWrite == nil) || (flags & kWritesPaused))\n\t{\n\t\tLogVerbose(@\"No currentWrite or kWritesPaused\");\n\t\t\n\t\t// Unable to write at this time\n\t\t\n\t\tif ([self usingCFStreamForTLS])\n\t\t{\n\t\t\t// CFWriteStream only fires once when there is available data.\n\t\t\t// It won't fire again until we've invoked CFWriteStreamWrite.\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If the writeSource is firing, we need to pause it\n\t\t\t// or else it will continue to fire over and over again.\n\t\t\t\n\t\t\tif (flags & kSocketCanAcceptBytes)\n\t\t\t{\n\t\t\t\t[self suspendWriteSource];\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\t\n\tif (!(flags & kSocketCanAcceptBytes))\n\t{\n\t\tLogVerbose(@\"No space available to write...\");\n\t\t\n\t\t// No space available to write.\n\t\t\n\t\tif (![self usingCFStreamForTLS])\n\t\t{\n\t\t\t// Need to wait for writeSource to fire and notify us of\n\t\t\t// available space in the socket's internal write buffer.\n\t\t\t\n\t\t\t[self resumeWriteSource];\n\t\t}\n\t\treturn;\n\t}\n\t\n\tif (flags & kStartingWriteTLS)\n\t{\n\t\tLogVerbose(@\"Waiting for SSL/TLS handshake to complete\");\n\t\t\n\t\t// The writeQueue is waiting for SSL/TLS handshake to complete.\n\t\t\n\t\tif (flags & kStartingReadTLS)\n\t\t{\n\t\t\tif ([self usingSecureTransportForTLS] && lastSSLHandshakeError == errSSLWouldBlock)\n\t\t\t{\n\t\t\t\t// We are in the process of a SSL Handshake.\n\t\t\t\t// We were waiting for available space in the socket's internal OS buffer to continue writing.\n\t\t\t\n\t\t\t\t[self ssl_continueSSLHandshake];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We are still waiting for the readQueue to drain and start the SSL/TLS process.\n\t\t\t// We now know we can write to the socket.\n\t\t\t\n\t\t\tif (![self usingCFStreamForTLS])\n\t\t\t{\n\t\t\t\t// Suspend the write source or else it will continue to fire nonstop.\n\t\t\t\t\n\t\t\t\t[self suspendWriteSource];\n\t\t\t}\n\t\t}\n\t\t\n\t\treturn;\n\t}\n\t\n\t// Note: This method is not called if currentWrite is a GCDAsyncSpecialPacket (startTLS packet)\n\t\n\tBOOL waiting = NO;\n\tNSError *error = nil;\n\tsize_t bytesWritten = 0;\n\t\n\tif (flags & kSocketSecure)\n\t{\n\t\tif ([self usingCFStreamForTLS])\n\t\t{\n\t\t\t#if TARGET_OS_IPHONE\n\t\t\t\n\t\t\t// \n\t\t\t// Writing data using CFStream (over internal TLS)\n\t\t\t// \n\t\t\t\n\t\t\tconst uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;\n\t\t\t\n\t\t\tNSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;\n\t\t\t\n\t\t\tif (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)\n\t\t\t{\n\t\t\t\tbytesToWrite = SIZE_MAX;\n\t\t\t}\n\t\t\n\t\t\tCFIndex result = CFWriteStreamWrite(writeStream, buffer, (CFIndex)bytesToWrite);\n\t\t\tLogVerbose(@\"CFWriteStreamWrite(%lu) = %li\", (unsigned long)bytesToWrite, result);\n\t\t\n\t\t\tif (result < 0)\n\t\t\t{\n\t\t\t\terror = (__bridge_transfer NSError *)CFWriteStreamCopyError(writeStream);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tbytesWritten = (size_t)result;\n\t\t\t\t\n\t\t\t\t// We always set waiting to true in this scenario.\n\t\t\t\t// CFStream may have altered our underlying socket to non-blocking.\n\t\t\t\t// Thus if we attempt to write without a callback, we may end up blocking our queue.\n\t\t\t\twaiting = YES;\n\t\t\t}\n\t\t\t\n\t\t\t#endif\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// We're going to use the SSLWrite function.\n\t\t\t// \n\t\t\t// OSStatus SSLWrite(SSLContextRef context, const void *data, size_t dataLength, size_t *processed)\n\t\t\t// \n\t\t\t// Parameters:\n\t\t\t// context     - An SSL session context reference.\n\t\t\t// data        - A pointer to the buffer of data to write.\n\t\t\t// dataLength  - The amount, in bytes, of data to write.\n\t\t\t// processed   - On return, the length, in bytes, of the data actually written.\n\t\t\t// \n\t\t\t// It sounds pretty straight-forward,\n\t\t\t// but there are a few caveats you should be aware of.\n\t\t\t// \n\t\t\t// The SSLWrite method operates in a non-obvious (and rather annoying) manner.\n\t\t\t// According to the documentation:\n\t\t\t// \n\t\t\t//   Because you may configure the underlying connection to operate in a non-blocking manner,\n\t\t\t//   a write operation might return errSSLWouldBlock, indicating that less data than requested\n\t\t\t//   was actually transferred. In this case, you should repeat the call to SSLWrite until some\n\t\t\t//   other result is returned.\n\t\t\t// \n\t\t\t// This sounds perfect, but when our SSLWriteFunction returns errSSLWouldBlock,\n\t\t\t// then the SSLWrite method returns (with the proper errSSLWouldBlock return value),\n\t\t\t// but it sets processed to dataLength !!\n\t\t\t// \n\t\t\t// In other words, if the SSLWrite function doesn't completely write all the data we tell it to,\n\t\t\t// then it doesn't tell us how many bytes were actually written. So, for example, if we tell it to\n\t\t\t// write 256 bytes then it might actually write 128 bytes, but then report 0 bytes written.\n\t\t\t// \n\t\t\t// You might be wondering:\n\t\t\t// If the SSLWrite function doesn't tell us how many bytes were written,\n\t\t\t// then how in the world are we supposed to update our parameters (buffer & bytesToWrite)\n\t\t\t// for the next time we invoke SSLWrite?\n\t\t\t// \n\t\t\t// The answer is that SSLWrite cached all the data we told it to write,\n\t\t\t// and it will push out that data next time we call SSLWrite.\n\t\t\t// If we call SSLWrite with new data, it will push out the cached data first, and then the new data.\n\t\t\t// If we call SSLWrite with empty data, then it will simply push out the cached data.\n\t\t\t// \n\t\t\t// For this purpose we're going to break large writes into a series of smaller writes.\n\t\t\t// This allows us to report progress back to the delegate.\n\t\t\t\n\t\t\tOSStatus result;\n\t\t\t\n\t\t\tBOOL hasCachedDataToWrite = (sslWriteCachedLength > 0);\n\t\t\tBOOL hasNewDataToWrite = YES;\n\t\t\t\n\t\t\tif (hasCachedDataToWrite)\n\t\t\t{\n\t\t\t\tsize_t processed = 0;\n\t\t\t\t\n\t\t\t\tresult = SSLWrite(sslContext, NULL, 0, &processed);\n\t\t\t\t\n\t\t\t\tif (result == noErr)\n\t\t\t\t{\n\t\t\t\t\tbytesWritten = sslWriteCachedLength;\n\t\t\t\t\tsslWriteCachedLength = 0;\n\t\t\t\t\t\n\t\t\t\t\tif ([currentWrite->buffer length] == (currentWrite->bytesDone + bytesWritten))\n\t\t\t\t\t{\n\t\t\t\t\t\t// We've written all data for the current write.\n\t\t\t\t\t\thasNewDataToWrite = NO;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tif (result == errSSLWouldBlock)\n\t\t\t\t\t{\n\t\t\t\t\t\twaiting = YES;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\terror = [self sslError:result];\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Can't write any new data since we were unable to write the cached data.\n\t\t\t\t\thasNewDataToWrite = NO;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (hasNewDataToWrite)\n\t\t\t{\n\t\t\t\tconst uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes]\n\t\t\t\t                                        + currentWrite->bytesDone\n\t\t\t\t                                        + bytesWritten;\n\t\t\t\t\n\t\t\t\tNSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone - bytesWritten;\n\t\t\t\t\n\t\t\t\tif (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)\n\t\t\t\t{\n\t\t\t\t\tbytesToWrite = SIZE_MAX;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tsize_t bytesRemaining = bytesToWrite;\n\t\t\t\t\n\t\t\t\tBOOL keepLooping = YES;\n\t\t\t\twhile (keepLooping)\n\t\t\t\t{\n\t\t\t\t\tconst size_t sslMaxBytesToWrite = 32768;\n\t\t\t\t\tsize_t sslBytesToWrite = MIN(bytesRemaining, sslMaxBytesToWrite);\n\t\t\t\t\tsize_t sslBytesWritten = 0;\n\t\t\t\t\t\n\t\t\t\t\tresult = SSLWrite(sslContext, buffer, sslBytesToWrite, &sslBytesWritten);\n\t\t\t\t\t\n\t\t\t\t\tif (result == noErr)\n\t\t\t\t\t{\n\t\t\t\t\t\tbuffer += sslBytesWritten;\n\t\t\t\t\t\tbytesWritten += sslBytesWritten;\n\t\t\t\t\t\tbytesRemaining -= sslBytesWritten;\n\t\t\t\t\t\t\n\t\t\t\t\t\tkeepLooping = (bytesRemaining > 0);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tif (result == errSSLWouldBlock)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twaiting = YES;\n\t\t\t\t\t\t\tsslWriteCachedLength = sslBytesToWrite;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror = [self sslError:result];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tkeepLooping = NO;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t} // while (keepLooping)\n\t\t\t\t\n\t\t\t} // if (hasNewDataToWrite)\n\t\t}\n\t}\n\telse\n\t{\n\t\t// \n\t\t// Writing data directly over raw socket\n\t\t// \n\t\t\n\t\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\t\n\t\tconst uint8_t *buffer = (const uint8_t *)[currentWrite->buffer bytes] + currentWrite->bytesDone;\n\t\t\n\t\tNSUInteger bytesToWrite = [currentWrite->buffer length] - currentWrite->bytesDone;\n\t\t\n\t\tif (bytesToWrite > SIZE_MAX) // NSUInteger may be bigger than size_t (write param 3)\n\t\t{\n\t\t\tbytesToWrite = SIZE_MAX;\n\t\t}\n\t\t\n\t\tssize_t result = write(socketFD, buffer, (size_t)bytesToWrite);\n\t\tLogVerbose(@\"wrote to socket = %zd\", result);\n\t\t\n\t\t// Check results\n\t\tif (result < 0)\n\t\t{\n\t\t\tif (errno == EWOULDBLOCK)\n\t\t\t{\n\t\t\t\twaiting = YES;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\terror = [self errnoErrorWithReason:@\"Error in write() function\"];\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tbytesWritten = result;\n\t\t}\n\t}\n\t\n\t// We're done with our writing.\n\t// If we explictly ran into a situation where the socket told us there was no room in the buffer,\n\t// then we immediately resume listening for notifications.\n\t// \n\t// We must do this before we dequeue another write,\n\t// as that may in turn invoke this method again.\n\t// \n\t// Note that if CFStream is involved, it may have maliciously put our socket in blocking mode.\n\t\n\tif (waiting)\n\t{\n\t\tflags &= ~kSocketCanAcceptBytes;\n\t\t\n\t\tif (![self usingCFStreamForTLS])\n\t\t{\n\t\t\t[self resumeWriteSource];\n\t\t}\n\t}\n\t\n\t// Check our results\n\t\n\tBOOL done = NO;\n\t\n\tif (bytesWritten > 0)\n\t{\n\t\t// Update total amount read for the current write\n\t\tcurrentWrite->bytesDone += bytesWritten;\n\t\tLogVerbose(@\"currentWrite->bytesDone = %lu\", (unsigned long)currentWrite->bytesDone);\n\t\t\n\t\t// Is packet done?\n\t\tdone = (currentWrite->bytesDone == [currentWrite->buffer length]);\n\t}\n\t\n\tif (done)\n\t{\n\t\t[self completeCurrentWrite];\n\t\t\n\t\tif (!error)\n\t\t{\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool{\n\t\t\t\t\n\t\t\t\t[self maybeDequeueWrite];\n\t\t\t}});\n\t\t}\n\t}\n\telse\n\t{\n\t\t// We were unable to finish writing the data,\n\t\t// so we're waiting for another callback to notify us of available space in the lower-level output buffer.\n\t\t\n\t\tif (!waiting && !error)\n\t\t{\n\t\t\t// This would be the case if our write was able to accept some data, but not all of it.\n\t\t\t\n\t\t\tflags &= ~kSocketCanAcceptBytes;\n\t\t\t\n\t\t\tif (![self usingCFStreamForTLS])\n\t\t\t{\n\t\t\t\t[self resumeWriteSource];\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (bytesWritten > 0)\n\t\t{\n\t\t\t// We're not done with the entire write, but we have written some bytes\n\t\t\t\n\t\t\t__strong id theDelegate = delegate;\n\n\t\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWritePartialDataOfLength:tag:)])\n\t\t\t{\n\t\t\t\tlong theWriteTag = currentWrite->tag;\n\t\t\t\t\n\t\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\t\n\t\t\t\t\t[theDelegate socket:self didWritePartialDataOfLength:bytesWritten tag:theWriteTag];\n\t\t\t\t}});\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Check for errors\n\t\n\tif (error)\n\t{\n\t\t[self closeWithError:[self errnoErrorWithReason:@\"Error in write() function\"]];\n\t}\n\t\n\t// Do not add any code here without first adding a return statement in the error case above.\n}\n\n- (void)completeCurrentWrite\n{\n\tLogTrace();\n\t\n\tNSAssert(currentWrite, @\"Trying to complete current write when there is no current write.\");\n\t\n\n\t__strong id theDelegate = delegate;\n\t\n\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didWriteDataWithTag:)])\n\t{\n\t\tlong theWriteTag = currentWrite->tag;\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t[theDelegate socket:self didWriteDataWithTag:theWriteTag];\n\t\t}});\n\t}\n\t\n\t[self endCurrentWrite];\n}\n\n- (void)endCurrentWrite\n{\n\tif (writeTimer)\n\t{\n\t\tdispatch_source_cancel(writeTimer);\n\t\twriteTimer = NULL;\n\t}\n\t\n\tcurrentWrite = nil;\n}\n\n- (void)setupWriteTimerWithTimeout:(NSTimeInterval)timeout\n{\n\tif (timeout >= 0.0)\n\t{\n\t\tunsigned long writeTimerMask = 0;\n\n\t\tif (config & kUseStrictTimers) {\n\t\t\twriteTimerMask = DISPATCH_TIMER_STRICT;\n\t\t}\n\n\t\twriteTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, writeTimerMask, socketQueue);\n\n\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\n\t\tdispatch_source_set_event_handler(writeTimer, ^{ @autoreleasepool {\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\tif (strongSelf == nil) return_from_block;\n\t\t\t\n\t\t\t[strongSelf doWriteTimeout];\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t}});\n\t\t\n\t\t#if !OS_OBJECT_USE_OBJC\n\t\tdispatch_source_t theWriteTimer = writeTimer;\n\t\tdispatch_source_set_cancel_handler(writeTimer, ^{\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\tLogVerbose(@\"dispatch_release(writeTimer)\");\n\t\t\tdispatch_release(theWriteTimer);\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t});\n\t\t#endif\n\t\t\n\t\tdispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC));\n\t\t\n\t\tdispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);\n\t\tdispatch_resume(writeTimer);\n\t}\n}\n\n- (void)doWriteTimeout\n{\n\t// This is a little bit tricky.\n\t// Ideally we'd like to synchronously query the delegate about a timeout extension.\n\t// But if we do so synchronously we risk a possible deadlock.\n\t// So instead we have to do so asynchronously, and callback to ourselves from within the delegate block.\n\t\n\tflags |= kWritesPaused;\n\t\n\t__strong id theDelegate = delegate;\n\n\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:shouldTimeoutWriteWithTag:elapsed:bytesDone:)])\n\t{\n\t\tGCDAsyncWritePacket *theWrite = currentWrite;\n\t\t\n\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\tNSTimeInterval timeoutExtension = 0.0;\n\t\t\t\n\t\t\ttimeoutExtension = [theDelegate socket:self shouldTimeoutWriteWithTag:theWrite->tag\n\t\t\t                                                              elapsed:theWrite->timeout\n\t\t\t                                                            bytesDone:theWrite->bytesDone];\n\t\t\t\n\t\t\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[self doWriteTimeoutWithExtension:timeoutExtension];\n\t\t\t}});\n\t\t}});\n\t}\n\telse\n\t{\n\t\t[self doWriteTimeoutWithExtension:0.0];\n\t}\n}\n\n- (void)doWriteTimeoutWithExtension:(NSTimeInterval)timeoutExtension\n{\n\tif (currentWrite)\n\t{\n\t\tif (timeoutExtension > 0.0)\n\t\t{\n\t\t\tcurrentWrite->timeout += timeoutExtension;\n\t\t\t\n\t\t\t// Reschedule the timer\n\t\t\tdispatch_time_t tt = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeoutExtension * NSEC_PER_SEC));\n\t\t\tdispatch_source_set_timer(writeTimer, tt, DISPATCH_TIME_FOREVER, 0);\n\t\t\t\n\t\t\t// Unpause writes, and continue\n\t\t\tflags &= ~kWritesPaused;\n\t\t\t[self doWriteData];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tLogVerbose(@\"WriteTimeout\");\n\t\t\t\n\t\t\t[self closeWithError:[self writeTimeoutError]];\n\t\t}\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Security\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (void)startTLS:(NSDictionary *)tlsSettings\n{\n\tLogTrace();\n\t\n\tif (tlsSettings == nil)\n    {\n        // Passing nil/NULL to CFReadStreamSetProperty will appear to work the same as passing an empty dictionary,\n        // but causes problems if we later try to fetch the remote host's certificate.\n        // \n        // To be exact, it causes the following to return NULL instead of the normal result:\n        // CFReadStreamCopyProperty(readStream, kCFStreamPropertySSLPeerCertificates)\n        // \n        // So we use an empty dictionary instead, which works perfectly.\n        \n        tlsSettings = [NSDictionary dictionary];\n    }\n\t\n\tGCDAsyncSpecialPacket *packet = [[GCDAsyncSpecialPacket alloc] initWithTLSSettings:tlsSettings];\n\t\n\tdispatch_async(socketQueue, ^{ @autoreleasepool {\n\t\t\n\t\tif ((flags & kSocketStarted) && !(flags & kQueuedTLS) && !(flags & kForbidReadsWrites))\n\t\t{\n\t\t\t[readQueue addObject:packet];\n\t\t\t[writeQueue addObject:packet];\n\t\t\t\n\t\t\tflags |= kQueuedTLS;\n\t\t\t\n\t\t\t[self maybeDequeueRead];\n\t\t\t[self maybeDequeueWrite];\n\t\t}\n\t}});\n\t\n}\n\n- (void)maybeStartTLS\n{\n\t// We can't start TLS until:\n\t// - All queued reads prior to the user calling startTLS are complete\n\t// - All queued writes prior to the user calling startTLS are complete\n\t// \n\t// We'll know these conditions are met when both kStartingReadTLS and kStartingWriteTLS are set\n\t\n\tif ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))\n\t{\n\t\tBOOL useSecureTransport = YES;\n\t\t\n\t\t#if TARGET_OS_IPHONE\n\t\t{\n\t\t\tGCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;\n            NSDictionary *tlsSettings = @{};\n            if (tlsPacket) {\n                tlsSettings = tlsPacket->tlsSettings;\n            }\n\t\t\tNSNumber *value = [tlsSettings objectForKey:GCDAsyncSocketUseCFStreamForTLS];\n\t\t\tif (value && [value boolValue])\n\t\t\t\tuseSecureTransport = NO;\n\t\t}\n\t\t#endif\n\t\t\n\t\tif (useSecureTransport)\n\t\t{\n\t\t\t[self ssl_startTLS];\n\t\t}\n\t\telse\n\t\t{\n\t\t#if TARGET_OS_IPHONE\n\t\t\t[self cf_startTLS];\n\t\t#endif\n\t\t}\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Security via SecureTransport\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n- (OSStatus)sslReadWithBuffer:(void *)buffer length:(size_t *)bufferLength\n{\n\tLogVerbose(@\"sslReadWithBuffer:%p length:%lu\", buffer, (unsigned long)*bufferLength);\n\t\n\tif ((socketFDBytesAvailable == 0) && ([sslPreBuffer availableBytes] == 0))\n\t{\n\t\tLogVerbose(@\"%@ - No data available to read...\", THIS_METHOD);\n\t\t\n\t\t// No data available to read.\n\t\t// \n\t\t// Need to wait for readSource to fire and notify us of\n\t\t// available data in the socket's internal read buffer.\n\t\t\n\t\t[self resumeReadSource];\n\t\t\n\t\t*bufferLength = 0;\n\t\treturn errSSLWouldBlock;\n\t}\n\t\n\tsize_t totalBytesRead = 0;\n\tsize_t totalBytesLeftToBeRead = *bufferLength;\n\t\n\tBOOL done = NO;\n\tBOOL socketError = NO;\n\t\n\t// \n\t// STEP 1 : READ FROM SSL PRE BUFFER\n\t// \n\t\n\tsize_t sslPreBufferLength = [sslPreBuffer availableBytes];\n\t\n\tif (sslPreBufferLength > 0)\n\t{\n\t\tLogVerbose(@\"%@: Reading from SSL pre buffer...\", THIS_METHOD);\n\t\t\n\t\tsize_t bytesToCopy;\n\t\tif (sslPreBufferLength > totalBytesLeftToBeRead)\n\t\t\tbytesToCopy = totalBytesLeftToBeRead;\n\t\telse\n\t\t\tbytesToCopy = sslPreBufferLength;\n\t\t\n\t\tLogVerbose(@\"%@: Copying %zu bytes from sslPreBuffer\", THIS_METHOD, bytesToCopy);\n\t\t\n\t\tmemcpy(buffer, [sslPreBuffer readBuffer], bytesToCopy);\n\t\t[sslPreBuffer didRead:bytesToCopy];\n\t\t\n\t\tLogVerbose(@\"%@: sslPreBuffer.length = %zu\", THIS_METHOD, [sslPreBuffer availableBytes]);\n\t\t\n\t\ttotalBytesRead += bytesToCopy;\n\t\ttotalBytesLeftToBeRead -= bytesToCopy;\n\t\t\n\t\tdone = (totalBytesLeftToBeRead == 0);\n\t\t\n\t\tif (done) LogVerbose(@\"%@: Complete\", THIS_METHOD);\n\t}\n\t\n\t// \n\t// STEP 2 : READ FROM SOCKET\n\t// \n\t\n\tif (!done && (socketFDBytesAvailable > 0))\n\t{\n\t\tLogVerbose(@\"%@: Reading from socket...\", THIS_METHOD);\n\t\t\n\t\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\t\n\t\tBOOL readIntoPreBuffer;\n\t\tsize_t bytesToRead;\n\t\tuint8_t *buf;\n\t\t\n\t\tif (socketFDBytesAvailable > totalBytesLeftToBeRead)\n\t\t{\n\t\t\t// Read all available data from socket into sslPreBuffer.\n\t\t\t// Then copy requested amount into dataBuffer.\n\t\t\t\n\t\t\tLogVerbose(@\"%@: Reading into sslPreBuffer...\", THIS_METHOD);\n\t\t\t\n\t\t\t[sslPreBuffer ensureCapacityForWrite:socketFDBytesAvailable];\n\t\t\t\n\t\t\treadIntoPreBuffer = YES;\n\t\t\tbytesToRead = (size_t)socketFDBytesAvailable;\n\t\t\tbuf = [sslPreBuffer writeBuffer];\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Read available data from socket directly into dataBuffer.\n\t\t\t\n\t\t\tLogVerbose(@\"%@: Reading directly into dataBuffer...\", THIS_METHOD);\n\t\t\t\n\t\t\treadIntoPreBuffer = NO;\n\t\t\tbytesToRead = totalBytesLeftToBeRead;\n\t\t\tbuf = (uint8_t *)buffer + totalBytesRead;\n\t\t}\n\t\t\n\t\tssize_t result = read(socketFD, buf, bytesToRead);\n\t\tLogVerbose(@\"%@: read from socket = %zd\", THIS_METHOD, result);\n\t\t\n\t\tif (result < 0)\n\t\t{\n\t\t\tLogVerbose(@\"%@: read errno = %i\", THIS_METHOD, errno);\n\t\t\t\n\t\t\tif (errno != EWOULDBLOCK)\n\t\t\t{\n\t\t\t\tsocketError = YES;\n\t\t\t}\n\t\t\t\n\t\t\tsocketFDBytesAvailable = 0;\n\t\t}\n\t\telse if (result == 0)\n\t\t{\n\t\t\tLogVerbose(@\"%@: read EOF\", THIS_METHOD);\n\t\t\t\n\t\t\tsocketError = YES;\n\t\t\tsocketFDBytesAvailable = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsize_t bytesReadFromSocket = result;\n\t\t\t\n\t\t\tif (socketFDBytesAvailable > bytesReadFromSocket)\n\t\t\t\tsocketFDBytesAvailable -= bytesReadFromSocket;\n\t\t\telse\n\t\t\t\tsocketFDBytesAvailable = 0;\n\t\t\t\n\t\t\tif (readIntoPreBuffer)\n\t\t\t{\n\t\t\t\t[sslPreBuffer didWrite:bytesReadFromSocket];\n\t\t\t\t\n\t\t\t\tsize_t bytesToCopy = MIN(totalBytesLeftToBeRead, bytesReadFromSocket);\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"%@: Copying %zu bytes out of sslPreBuffer\", THIS_METHOD, bytesToCopy);\n\t\t\t\t\n\t\t\t\tmemcpy((uint8_t *)buffer + totalBytesRead, [sslPreBuffer readBuffer], bytesToCopy);\n\t\t\t\t[sslPreBuffer didRead:bytesToCopy];\n\t\t\t\t\n\t\t\t\ttotalBytesRead += bytesToCopy;\n\t\t\t\ttotalBytesLeftToBeRead -= bytesToCopy;\n\t\t\t\t\n\t\t\t\tLogVerbose(@\"%@: sslPreBuffer.length = %zu\", THIS_METHOD, [sslPreBuffer availableBytes]);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\ttotalBytesRead += bytesReadFromSocket;\n\t\t\t\ttotalBytesLeftToBeRead -= bytesReadFromSocket;\n\t\t\t}\n\t\t\t\n\t\t\tdone = (totalBytesLeftToBeRead == 0);\n\t\t\t\n\t\t\tif (done) LogVerbose(@\"%@: Complete\", THIS_METHOD);\n\t\t}\n\t}\n\t\n\t*bufferLength = totalBytesRead;\n\t\n\tif (done)\n\t\treturn noErr;\n\t\n\tif (socketError)\n\t\treturn errSSLClosedAbort;\n\t\n\treturn errSSLWouldBlock;\n}\n\n- (OSStatus)sslWriteWithBuffer:(const void *)buffer length:(size_t *)bufferLength\n{\n\tif (!(flags & kSocketCanAcceptBytes))\n\t{\n\t\t// Unable to write.\n\t\t// \n\t\t// Need to wait for writeSource to fire and notify us of\n\t\t// available space in the socket's internal write buffer.\n\t\t\n\t\t[self resumeWriteSource];\n\t\t\n\t\t*bufferLength = 0;\n\t\treturn errSSLWouldBlock;\n\t}\n\t\n\tsize_t bytesToWrite = *bufferLength;\n\tsize_t bytesWritten = 0;\n\t\n\tBOOL done = NO;\n\tBOOL socketError = NO;\n\t\n\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\n\tssize_t result = write(socketFD, buffer, bytesToWrite);\n\t\n\tif (result < 0)\n\t{\n\t\tif (errno != EWOULDBLOCK)\n\t\t{\n\t\t\tsocketError = YES;\n\t\t}\n\t\t\n\t\tflags &= ~kSocketCanAcceptBytes;\n\t}\n\telse if (result == 0)\n\t{\n\t\tflags &= ~kSocketCanAcceptBytes;\n\t}\n\telse\n\t{\n\t\tbytesWritten = result;\n\t\t\n\t\tdone = (bytesWritten == bytesToWrite);\n\t}\n\t\n\t*bufferLength = bytesWritten;\n\t\n\tif (done)\n\t\treturn noErr;\n\t\n\tif (socketError)\n\t\treturn errSSLClosedAbort;\n\t\n\treturn errSSLWouldBlock;\n}\n\nstatic OSStatus SSLReadFunction(SSLConnectionRef connection, void *data, size_t *dataLength)\n{\n\tGCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;\n\t\n\tNSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @\"What the deuce?\");\n\t\n\treturn [asyncSocket sslReadWithBuffer:data length:dataLength];\n}\n\nstatic OSStatus SSLWriteFunction(SSLConnectionRef connection, const void *data, size_t *dataLength)\n{\n\tGCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)connection;\n\t\n\tNSCAssert(dispatch_get_specific(asyncSocket->IsOnSocketQueueOrTargetQueueKey), @\"What the deuce?\");\n\t\n\treturn [asyncSocket sslWriteWithBuffer:data length:dataLength];\n}\n\n- (void)ssl_startTLS\n{\n\tLogTrace();\n\t\n\tLogVerbose(@\"Starting TLS (via SecureTransport)...\");\n\t\n\tOSStatus status;\n\t\n\tGCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;\n\tif (tlsPacket == nil) // Code to quiet the analyzer\n\t{\n\t\tNSAssert(NO, @\"Logic error\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Logic error\"]];\n\t\treturn;\n\t}\n\tNSDictionary *tlsSettings = tlsPacket->tlsSettings;\n\t\n\t// Create SSLContext, and setup IO callbacks and connection ref\n\t\n\tBOOL isServer = [[tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLIsServer] boolValue];\n\t\n\t#if TARGET_OS_IPHONE || (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080)\n\t{\n\t\tif (isServer)\n\t\t\tsslContext = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);\n\t\telse\n\t\t\tsslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);\n\t\t\n\t\tif (sslContext == NULL)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLCreateContext\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\t#else // (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)\n\t{\n\t\tstatus = SSLNewContext(isServer, &sslContext);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLNewContext\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\t#endif\n\t\n\tstatus = SSLSetIOFuncs(sslContext, &SSLReadFunction, &SSLWriteFunction);\n\tif (status != noErr)\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in SSLSetIOFuncs\"]];\n\t\treturn;\n\t}\n\t\n\tstatus = SSLSetConnection(sslContext, (__bridge SSLConnectionRef)self);\n\tif (status != noErr)\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in SSLSetConnection\"]];\n\t\treturn;\n\t}\n\n\n\tBOOL shouldManuallyEvaluateTrust = [[tlsSettings objectForKey:GCDAsyncSocketManuallyEvaluateTrust] boolValue];\n\tif (shouldManuallyEvaluateTrust)\n\t{\n\t\tif (isServer)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Manual trust validation is not supported for server sockets\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tstatus = SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetSessionOption\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t#if !TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED < 1080)\n\t\t\n\t\t// Note from Apple's documentation:\n\t\t//\n\t\t// It is only necessary to call SSLSetEnableCertVerify on the Mac prior to OS X 10.8.\n\t\t// On OS X 10.8 and later setting kSSLSessionOptionBreakOnServerAuth always disables the\n\t\t// built-in trust evaluation. All versions of iOS behave like OS X 10.8 and thus\n\t\t// SSLSetEnableCertVerify is not available on that platform at all.\n\t\t\n\t\tstatus = SSLSetEnableCertVerify(sslContext, NO);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetEnableCertVerify\"]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\t#endif\n\t}\n\n\t// Configure SSLContext from given settings\n\t// \n\t// Checklist:\n\t//  1. kCFStreamSSLPeerName\n\t//  2. kCFStreamSSLCertificates\n\t//  3. GCDAsyncSocketSSLPeerID\n\t//  4. GCDAsyncSocketSSLProtocolVersionMin\n\t//  5. GCDAsyncSocketSSLProtocolVersionMax\n\t//  6. GCDAsyncSocketSSLSessionOptionFalseStart\n\t//  7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord\n\t//  8. GCDAsyncSocketSSLCipherSuites\n\t//  9. GCDAsyncSocketSSLDiffieHellmanParameters (Mac)\n\t//\n\t// Deprecated (throw error):\n\t// 10. kCFStreamSSLAllowsAnyRoot\n\t// 11. kCFStreamSSLAllowsExpiredRoots\n\t// 12. kCFStreamSSLAllowsExpiredCertificates\n\t// 13. kCFStreamSSLValidatesCertificateChain\n\t// 14. kCFStreamSSLLevel\n\t\n\tid value;\n\t\n\t// 1. kCFStreamSSLPeerName\n\t\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLPeerName];\n\tif ([value isKindOfClass:[NSString class]])\n\t{\n\t\tNSString *peerName = (NSString *)value;\n\t\t\n\t\tconst char *peer = [peerName UTF8String];\n\t\tsize_t peerLen = strlen(peer);\n\t\t\n\t\tstatus = SSLSetPeerDomainName(sslContext, peer, peerLen);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetPeerDomainName\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for kCFStreamSSLPeerName. Value must be of type NSString.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for kCFStreamSSLPeerName.\"]];\n\t\treturn;\n\t}\n\t\n\t// 2. kCFStreamSSLCertificates\n\t\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLCertificates];\n\tif ([value isKindOfClass:[NSArray class]])\n\t{\n\t\tCFArrayRef certs = (__bridge CFArrayRef)value;\n\t\t\n\t\tstatus = SSLSetCertificate(sslContext, certs);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetCertificate\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for kCFStreamSSLCertificates. Value must be of type NSArray.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for kCFStreamSSLCertificates.\"]];\n\t\treturn;\n\t}\n\t\n\t// 3. GCDAsyncSocketSSLPeerID\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLPeerID];\n\tif ([value isKindOfClass:[NSData class]])\n\t{\n\t\tNSData *peerIdData = (NSData *)value;\n\t\t\n\t\tstatus = SSLSetPeerID(sslContext, [peerIdData bytes], [peerIdData length]);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetPeerID\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLPeerID. Value must be of type NSData.\"\n\t\t             @\" (You can convert strings to data using a method like\"\n\t\t             @\" [string dataUsingEncoding:NSUTF8StringEncoding])\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLPeerID.\"]];\n\t\treturn;\n\t}\n\t\n\t// 4. GCDAsyncSocketSSLProtocolVersionMin\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMin];\n\tif ([value isKindOfClass:[NSNumber class]])\n\t{\n\t\tSSLProtocol minProtocol = (SSLProtocol)[(NSNumber *)value intValue];\n\t\tif (minProtocol != kSSLProtocolUnknown)\n\t\t{\n\t\t\tstatus = SSLSetProtocolVersionMin(sslContext, minProtocol);\n\t\t\tif (status != noErr)\n\t\t\t{\n\t\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetProtocolVersionMin\"]];\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLProtocolVersionMin. Value must be of type NSNumber.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLProtocolVersionMin.\"]];\n\t\treturn;\n\t}\n\t\n\t// 5. GCDAsyncSocketSSLProtocolVersionMax\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLProtocolVersionMax];\n\tif ([value isKindOfClass:[NSNumber class]])\n\t{\n\t\tSSLProtocol maxProtocol = (SSLProtocol)[(NSNumber *)value intValue];\n\t\tif (maxProtocol != kSSLProtocolUnknown)\n\t\t{\n\t\t\tstatus = SSLSetProtocolVersionMax(sslContext, maxProtocol);\n\t\t\tif (status != noErr)\n\t\t\t{\n\t\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetProtocolVersionMax\"]];\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLProtocolVersionMax. Value must be of type NSNumber.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLProtocolVersionMax.\"]];\n\t\treturn;\n\t}\n\t\n\t// 6. GCDAsyncSocketSSLSessionOptionFalseStart\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionFalseStart];\n\tif ([value isKindOfClass:[NSNumber class]])\n\t{\n\t\tstatus = SSLSetSessionOption(sslContext, kSSLSessionOptionFalseStart, [value boolValue]);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetSessionOption (kSSLSessionOptionFalseStart)\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart. Value must be of type NSNumber.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLSessionOptionFalseStart.\"]];\n\t\treturn;\n\t}\n\t\n\t// 7. GCDAsyncSocketSSLSessionOptionSendOneByteRecord\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLSessionOptionSendOneByteRecord];\n\tif ([value isKindOfClass:[NSNumber class]])\n\t{\n\t\tstatus = SSLSetSessionOption(sslContext, kSSLSessionOptionSendOneByteRecord, [value boolValue]);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:\n\t\t\t  [self otherError:@\"Error in SSLSetSessionOption (kSSLSessionOptionSendOneByteRecord)\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord.\"\n\t\t             @\" Value must be of type NSNumber.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLSessionOptionSendOneByteRecord.\"]];\n\t\treturn;\n\t}\n\t\n\t// 8. GCDAsyncSocketSSLCipherSuites\n\t\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLCipherSuites];\n\tif ([value isKindOfClass:[NSArray class]])\n\t{\n\t\tNSArray *cipherSuites = (NSArray *)value;\n\t\tNSUInteger numberCiphers = [cipherSuites count];\n\t\tSSLCipherSuite ciphers[numberCiphers];\n\t\t\n\t\tNSUInteger cipherIndex;\n\t\tfor (cipherIndex = 0; cipherIndex < numberCiphers; cipherIndex++)\n\t\t{\n\t\t\tNSNumber *cipherObject = [cipherSuites objectAtIndex:cipherIndex];\n\t\t\tciphers[cipherIndex] = [cipherObject intValue];\n\t\t}\n\t\t\n\t\tstatus = SSLSetEnabledCiphers(sslContext, ciphers, numberCiphers);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetEnabledCiphers\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLCipherSuites. Value must be of type NSArray.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLCipherSuites.\"]];\n\t\treturn;\n\t}\n\t\n\t// 9. GCDAsyncSocketSSLDiffieHellmanParameters\n\t\n\t#if !TARGET_OS_IPHONE\n\tvalue = [tlsSettings objectForKey:GCDAsyncSocketSSLDiffieHellmanParameters];\n\tif ([value isKindOfClass:[NSData class]])\n\t{\n\t\tNSData *diffieHellmanData = (NSData *)value;\n\t\t\n\t\tstatus = SSLSetDiffieHellmanParams(sslContext, [diffieHellmanData bytes], [diffieHellmanData length]);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self otherError:@\"Error in SSLSetDiffieHellmanParams\"]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (value)\n\t{\n\t\tNSAssert(NO, @\"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters. Value must be of type NSData.\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Invalid value for GCDAsyncSocketSSLDiffieHellmanParameters.\"]];\n\t\treturn;\n\t}\n\t#endif\n\t\n\t// DEPRECATED checks\n\t\n\t// 10. kCFStreamSSLAllowsAnyRoot\n\t\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsAnyRoot];\n\t#pragma clang diagnostic pop\n\tif (value)\n\t{\n\t\tNSAssert(NO, @\"Security option unavailable - kCFStreamSSLAllowsAnyRoot\"\n\t\t             @\" - You must use manual trust evaluation\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Security option unavailable - kCFStreamSSLAllowsAnyRoot\"]];\n\t\treturn;\n\t}\n\t\n\t// 11. kCFStreamSSLAllowsExpiredRoots\n\t\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredRoots];\n\t#pragma clang diagnostic pop\n\tif (value)\n\t{\n\t\tNSAssert(NO, @\"Security option unavailable - kCFStreamSSLAllowsExpiredRoots\"\n\t\t             @\" - You must use manual trust evaluation\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Security option unavailable - kCFStreamSSLAllowsExpiredRoots\"]];\n\t\treturn;\n\t}\n\t\n\t// 12. kCFStreamSSLValidatesCertificateChain\n\t\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLValidatesCertificateChain];\n\t#pragma clang diagnostic pop\n\tif (value)\n\t{\n\t\tNSAssert(NO, @\"Security option unavailable - kCFStreamSSLValidatesCertificateChain\"\n\t\t             @\" - You must use manual trust evaluation\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Security option unavailable - kCFStreamSSLValidatesCertificateChain\"]];\n\t\treturn;\n\t}\n\t\n\t// 13. kCFStreamSSLAllowsExpiredCertificates\n\t\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLAllowsExpiredCertificates];\n\t#pragma clang diagnostic pop\n\tif (value)\n\t{\n\t\tNSAssert(NO, @\"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates\"\n\t\t             @\" - You must use manual trust evaluation\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Security option unavailable - kCFStreamSSLAllowsExpiredCertificates\"]];\n\t\treturn;\n\t}\n\t\n\t// 14. kCFStreamSSLLevel\n\t\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\tvalue = [tlsSettings objectForKey:(__bridge NSString *)kCFStreamSSLLevel];\n\t#pragma clang diagnostic pop\n\tif (value)\n\t{\n\t\tNSAssert(NO, @\"Security option unavailable - kCFStreamSSLLevel\"\n\t\t             @\" - You must use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMax\");\n\t\t\n\t\t[self closeWithError:[self otherError:@\"Security option unavailable - kCFStreamSSLLevel\"]];\n\t\treturn;\n\t}\n\t\n\t// Setup the sslPreBuffer\n\t// \n\t// Any data in the preBuffer needs to be moved into the sslPreBuffer,\n\t// as this data is now part of the secure read stream.\n\t\n\tsslPreBuffer = [[GCDAsyncSocketPreBuffer alloc] initWithCapacity:(1024 * 4)];\n\t\n\tsize_t preBufferLength  = [preBuffer availableBytes];\n\t\n\tif (preBufferLength > 0)\n\t{\n\t\t[sslPreBuffer ensureCapacityForWrite:preBufferLength];\n\t\t\n\t\tmemcpy([sslPreBuffer writeBuffer], [preBuffer readBuffer], preBufferLength);\n\t\t[preBuffer didRead:preBufferLength];\n\t\t[sslPreBuffer didWrite:preBufferLength];\n\t}\n\t\n\tsslErrCode = lastSSLHandshakeError = noErr;\n\t\n\t// Start the SSL Handshake process\n\t\n\t[self ssl_continueSSLHandshake];\n}\n\n- (void)ssl_continueSSLHandshake\n{\n\tLogTrace();\n\t\n\t// If the return value is noErr, the session is ready for normal secure communication.\n\t// If the return value is errSSLWouldBlock, the SSLHandshake function must be called again.\n\t// If the return value is errSSLServerAuthCompleted, we ask delegate if we should trust the\n\t// server and then call SSLHandshake again to resume the handshake or close the connection\n\t// errSSLPeerBadCert SSL error.\n\t// Otherwise, the return value indicates an error code.\n\t\n\tOSStatus status = SSLHandshake(sslContext);\n\tlastSSLHandshakeError = status;\n\t\n\tif (status == noErr)\n\t{\n\t\tLogVerbose(@\"SSLHandshake complete\");\n\t\t\n\t\tflags &= ~kStartingReadTLS;\n\t\tflags &= ~kStartingWriteTLS;\n\t\t\n\t\tflags |=  kSocketSecure;\n\t\t\n\t\t__strong id theDelegate = delegate;\n\n\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])\n\t\t{\n\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[theDelegate socketDidSecure:self];\n\t\t\t}});\n\t\t}\n\t\t\n\t\t[self endCurrentRead];\n\t\t[self endCurrentWrite];\n\t\t\n\t\t[self maybeDequeueRead];\n\t\t[self maybeDequeueWrite];\n\t}\n\telse if (status == errSSLPeerAuthCompleted)\n\t{\n\t\tLogVerbose(@\"SSLHandshake peerAuthCompleted - awaiting delegate approval\");\n\t\t\n\t\t__block SecTrustRef trust = NULL;\n\t\tstatus = SSLCopyPeerTrust(sslContext, &trust);\n\t\tif (status != noErr)\n\t\t{\n\t\t\t[self closeWithError:[self sslError:status]];\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tint aStateIndex = stateIndex;\n\t\tdispatch_queue_t theSocketQueue = socketQueue;\n\t\t\n\t\t__weak GCDAsyncSocket *weakSelf = self;\n\t\t\n\t\tvoid (^comletionHandler)(BOOL) = ^(BOOL shouldTrust){ @autoreleasepool {\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\t\n\t\t\tdispatch_async(theSocketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tif (trust) {\n\t\t\t\t\tCFRelease(trust);\n\t\t\t\t\ttrust = NULL;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t__strong GCDAsyncSocket *strongSelf = weakSelf;\n\t\t\t\tif (strongSelf)\n\t\t\t\t{\n\t\t\t\t\t[strongSelf ssl_shouldTrustPeer:shouldTrust stateIndex:aStateIndex];\n\t\t\t\t}\n\t\t\t}});\n\t\t\t\n\t\t#pragma clang diagnostic pop\n\t\t}};\n\t\t\n\t\t__strong id theDelegate = delegate;\n\t\t\n\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socket:didReceiveTrust:completionHandler:)])\n\t\t{\n\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\n\t\t\t\t[theDelegate socket:self didReceiveTrust:trust completionHandler:comletionHandler];\n\t\t\t}});\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (trust) {\n\t\t\t\tCFRelease(trust);\n\t\t\t\ttrust = NULL;\n\t\t\t}\n\t\t\t\n\t\t\tNSString *msg = @\"GCDAsyncSocketManuallyEvaluateTrust specified in tlsSettings,\"\n\t\t\t                @\" but delegate doesn't implement socket:shouldTrustPeer:\";\n\t\t\t\n\t\t\t[self closeWithError:[self otherError:msg]];\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (status == errSSLWouldBlock)\n\t{\n\t\tLogVerbose(@\"SSLHandshake continues...\");\n\t\t\n\t\t// Handshake continues...\n\t\t// \n\t\t// This method will be called again from doReadData or doWriteData.\n\t}\n\telse\n\t{\n\t\t[self closeWithError:[self sslError:status]];\n\t}\n}\n\n- (void)ssl_shouldTrustPeer:(BOOL)shouldTrust stateIndex:(int)aStateIndex\n{\n\tLogTrace();\n\t\n\tif (aStateIndex != stateIndex)\n\t{\n\t\tLogInfo(@\"Ignoring ssl_shouldTrustPeer - invalid state (maybe disconnected)\");\n\t\t\n\t\t// One of the following is true\n\t\t// - the socket was disconnected\n\t\t// - the startTLS operation timed out\n\t\t// - the completionHandler was already invoked once\n\t\t\n\t\treturn;\n\t}\n\t\n\t// Increment stateIndex to ensure completionHandler can only be called once.\n\tstateIndex++;\n\t\n\tif (shouldTrust)\n\t{\n        NSAssert(lastSSLHandshakeError == errSSLPeerAuthCompleted, @\"ssl_shouldTrustPeer called when last error is %d and not errSSLPeerAuthCompleted\", (int)lastSSLHandshakeError);\n\t\t[self ssl_continueSSLHandshake];\n\t}\n\telse\n\t{\n\t\t[self closeWithError:[self sslError:errSSLPeerBadCert]];\n\t}\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Security via CFStream\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#if TARGET_OS_IPHONE\n\n- (void)cf_finishSSLHandshake\n{\n\tLogTrace();\n\t\n\tif ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))\n\t{\n\t\tflags &= ~kStartingReadTLS;\n\t\tflags &= ~kStartingWriteTLS;\n\t\t\n\t\tflags |= kSocketSecure;\n\t\t\n\t\t__strong id theDelegate = delegate;\n\n\t\tif (delegateQueue && [theDelegate respondsToSelector:@selector(socketDidSecure:)])\n\t\t{\n\t\t\tdispatch_async(delegateQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\t[theDelegate socketDidSecure:self];\n\t\t\t}});\n\t\t}\n\t\t\n\t\t[self endCurrentRead];\n\t\t[self endCurrentWrite];\n\t\t\n\t\t[self maybeDequeueRead];\n\t\t[self maybeDequeueWrite];\n\t}\n}\n\n- (void)cf_abortSSLHandshake:(NSError *)error\n{\n\tLogTrace();\n\t\n\tif ((flags & kStartingReadTLS) && (flags & kStartingWriteTLS))\n\t{\n\t\tflags &= ~kStartingReadTLS;\n\t\tflags &= ~kStartingWriteTLS;\n\t\t\n\t\t[self closeWithError:error];\n\t}\n}\n\n- (void)cf_startTLS\n{\n\tLogTrace();\n\t\n\tLogVerbose(@\"Starting TLS (via CFStream)...\");\n\t\n\tif ([preBuffer availableBytes] > 0)\n\t{\n\t\tNSString *msg = @\"Invalid TLS transition. Handshake has already been read from socket.\";\n\t\t\n\t\t[self closeWithError:[self otherError:msg]];\n\t\treturn;\n\t}\n\t\n\t[self suspendReadSource];\n\t[self suspendWriteSource];\n\t\n\tsocketFDBytesAvailable = 0;\n\tflags &= ~kSocketCanAcceptBytes;\n\tflags &= ~kSecureSocketHasBytesAvailable;\n\t\n\tflags |=  kUsingCFStreamForTLS;\n\t\n\tif (![self createReadAndWriteStream])\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in CFStreamCreatePairWithSocket\"]];\n\t\treturn;\n\t}\n\t\n\tif (![self registerForStreamCallbacksIncludingReadWrite:YES])\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in CFStreamSetClient\"]];\n\t\treturn;\n\t}\n\t\n\tif (![self addStreamsToRunLoop])\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in CFStreamScheduleWithRunLoop\"]];\n\t\treturn;\n\t}\n\t\n\tNSAssert([currentRead isKindOfClass:[GCDAsyncSpecialPacket class]], @\"Invalid read packet for startTLS\");\n\tNSAssert([currentWrite isKindOfClass:[GCDAsyncSpecialPacket class]], @\"Invalid write packet for startTLS\");\n\t\n\tGCDAsyncSpecialPacket *tlsPacket = (GCDAsyncSpecialPacket *)currentRead;\n\tCFDictionaryRef tlsSettings = (__bridge CFDictionaryRef)tlsPacket->tlsSettings;\n\t\n\t// Getting an error concerning kCFStreamPropertySSLSettings ?\n\t// You need to add the CFNetwork framework to your iOS application.\n\t\n\tBOOL r1 = CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, tlsSettings);\n\tBOOL r2 = CFWriteStreamSetProperty(writeStream, kCFStreamPropertySSLSettings, tlsSettings);\n\t\n\t// For some reason, starting around the time of iOS 4.3,\n\t// the first call to set the kCFStreamPropertySSLSettings will return true,\n\t// but the second will return false.\n\t// \n\t// Order doesn't seem to matter.\n\t// So you could call CFReadStreamSetProperty and then CFWriteStreamSetProperty, or you could reverse the order.\n\t// Either way, the first call will return true, and the second returns false.\n\t// \n\t// Interestingly, this doesn't seem to affect anything.\n\t// Which is not altogether unusual, as the documentation seems to suggest that (for many settings)\n\t// setting it on one side of the stream automatically sets it for the other side of the stream.\n\t// \n\t// Although there isn't anything in the documentation to suggest that the second attempt would fail.\n\t// \n\t// Furthermore, this only seems to affect streams that are negotiating a security upgrade.\n\t// In other words, the socket gets connected, there is some back-and-forth communication over the unsecure\n\t// connection, and then a startTLS is issued.\n\t// So this mostly affects newer protocols (XMPP, IMAP) as opposed to older protocols (HTTPS).\n\t\n\tif (!r1 && !r2) // Yes, the && is correct - workaround for apple bug.\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in CFStreamSetProperty\"]];\n\t\treturn;\n\t}\n\t\n\tif (![self openStreams])\n\t{\n\t\t[self closeWithError:[self otherError:@\"Error in CFStreamOpen\"]];\n\t\treturn;\n\t}\n\t\n\tLogVerbose(@\"Waiting for SSL Handshake to complete...\");\n}\n\n#endif\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark CFStream\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#if TARGET_OS_IPHONE\n\n+ (void)ignore:(id)_\n{}\n\n+ (void)startCFStreamThreadIfNeeded\n{\n\tLogTrace();\n\t\n\tstatic dispatch_once_t predicate;\n\tdispatch_once(&predicate, ^{\n\t\t\n\t\tcfstreamThreadRetainCount = 0;\n\t\tcfstreamThreadSetupQueue = dispatch_queue_create(\"GCDAsyncSocket-CFStreamThreadSetup\", DISPATCH_QUEUE_SERIAL);\n\t});\n\t\n\tdispatch_sync(cfstreamThreadSetupQueue, ^{ @autoreleasepool {\n\t\t\n\t\tif (++cfstreamThreadRetainCount == 1)\n\t\t{\n\t\t\tcfstreamThread = [[NSThread alloc] initWithTarget:self\n\t\t\t                                         selector:@selector(cfstreamThread)\n\t\t\t                                           object:nil];\n\t\t\t[cfstreamThread start];\n\t\t}\n\t}});\n}\n\n+ (void)stopCFStreamThreadIfNeeded\n{\n\tLogTrace();\n\t\n\t// The creation of the cfstreamThread is relatively expensive.\n\t// So we'd like to keep it available for recycling.\n\t// However, there's a tradeoff here, because it shouldn't remain alive forever.\n\t// So what we're going to do is use a little delay before taking it down.\n\t// This way it can be reused properly in situations where multiple sockets are continually in flux.\n\t\n\tint delayInSeconds = 30;\n\tdispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));\n\tdispatch_after(when, cfstreamThreadSetupQueue, ^{ @autoreleasepool {\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic warning \"-Wimplicit-retain-self\"\n\t\t\n\t\tif (cfstreamThreadRetainCount == 0)\n\t\t{\n\t\t\tLogWarn(@\"Logic error concerning cfstreamThread start / stop\");\n\t\t\treturn_from_block;\n\t\t}\n\t\t\n\t\tif (--cfstreamThreadRetainCount == 0)\n\t\t{\n\t\t\t[cfstreamThread cancel]; // set isCancelled flag\n\t\t\t\n\t\t\t// wake up the thread\n            [[self class] performSelector:@selector(ignore:)\n                                 onThread:cfstreamThread\n                               withObject:[NSNull null]\n                            waitUntilDone:NO];\n            \n\t\t\tcfstreamThread = nil;\n\t\t}\n\t\t\n\t#pragma clang diagnostic pop\n\t}});\n}\n\n+ (void)cfstreamThread { @autoreleasepool\n{\n\t[[NSThread currentThread] setName:GCDAsyncSocketThreadName];\n\t\n\tLogInfo(@\"CFStreamThread: Started\");\n\t\n\t// We can't run the run loop unless it has an associated input source or a timer.\n\t// So we'll just create a timer that will never fire - unless the server runs for decades.\n\t[NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]\n\t                                 target:self\n\t                               selector:@selector(ignore:)\n\t                               userInfo:nil\n\t                                repeats:YES];\n\t\n\tNSThread *currentThread = [NSThread currentThread];\n\tNSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];\n\t\n\tBOOL isCancelled = [currentThread isCancelled];\n\t\n\twhile (!isCancelled && [currentRunLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]])\n\t{\n\t\tisCancelled = [currentThread isCancelled];\n\t}\n\t\n\tLogInfo(@\"CFStreamThread: Stopped\");\n}}\n\n+ (void)scheduleCFStreams:(GCDAsyncSocket *)asyncSocket\n{\n\tLogTrace();\n\tNSAssert([NSThread currentThread] == cfstreamThread, @\"Invoked on wrong thread\");\n\t\n\tCFRunLoopRef runLoop = CFRunLoopGetCurrent();\n\t\n\tif (asyncSocket->readStream)\n\t\tCFReadStreamScheduleWithRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);\n\t\n\tif (asyncSocket->writeStream)\n\t\tCFWriteStreamScheduleWithRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);\n}\n\n+ (void)unscheduleCFStreams:(GCDAsyncSocket *)asyncSocket\n{\n\tLogTrace();\n\tNSAssert([NSThread currentThread] == cfstreamThread, @\"Invoked on wrong thread\");\n\t\n\tCFRunLoopRef runLoop = CFRunLoopGetCurrent();\n\t\n\tif (asyncSocket->readStream)\n\t\tCFReadStreamUnscheduleFromRunLoop(asyncSocket->readStream, runLoop, kCFRunLoopDefaultMode);\n\t\n\tif (asyncSocket->writeStream)\n\t\tCFWriteStreamUnscheduleFromRunLoop(asyncSocket->writeStream, runLoop, kCFRunLoopDefaultMode);\n}\n\nstatic void CFReadStreamCallback (CFReadStreamRef stream, CFStreamEventType type, void *pInfo)\n{\n\tGCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;\n\t\n\tswitch(type)\n\t{\n\t\tcase kCFStreamEventHasBytesAvailable:\n\t\t{\n\t\t\tdispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tLogCVerbose(@\"CFReadStreamCallback - HasBytesAvailable\");\n\t\t\t\t\n\t\t\t\tif (asyncSocket->readStream != stream)\n\t\t\t\t\treturn_from_block;\n\t\t\t\t\n\t\t\t\tif ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))\n\t\t\t\t{\n\t\t\t\t\t// If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.\n\t\t\t\t\t// (A callback related to the tcp stream, but not to the SSL layer).\n\t\t\t\t\t\n\t\t\t\t\tif (CFReadStreamHasBytesAvailable(asyncSocket->readStream))\n\t\t\t\t\t{\n\t\t\t\t\t\tasyncSocket->flags |= kSecureSocketHasBytesAvailable;\n\t\t\t\t\t\t[asyncSocket cf_finishSSLHandshake];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tasyncSocket->flags |= kSecureSocketHasBytesAvailable;\n\t\t\t\t\t[asyncSocket doReadData];\n\t\t\t\t}\n\t\t\t}});\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tNSError *error = (__bridge_transfer  NSError *)CFReadStreamCopyError(stream);\n\t\t\t\n\t\t\tif (error == nil && type == kCFStreamEventEndEncountered)\n\t\t\t{\n\t\t\t\terror = [asyncSocket connectionClosedError];\n\t\t\t}\n\t\t\t\n\t\t\tdispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tLogCVerbose(@\"CFReadStreamCallback - Other\");\n\t\t\t\t\n\t\t\t\tif (asyncSocket->readStream != stream)\n\t\t\t\t\treturn_from_block;\n\t\t\t\t\n\t\t\t\tif ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))\n\t\t\t\t{\n\t\t\t\t\t[asyncSocket cf_abortSSLHandshake:error];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[asyncSocket closeWithError:error];\n\t\t\t\t}\n\t\t\t}});\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n}\n\nstatic void CFWriteStreamCallback (CFWriteStreamRef stream, CFStreamEventType type, void *pInfo)\n{\n\tGCDAsyncSocket *asyncSocket = (__bridge GCDAsyncSocket *)pInfo;\n\t\n\tswitch(type)\n\t{\n\t\tcase kCFStreamEventCanAcceptBytes:\n\t\t{\n\t\t\tdispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tLogCVerbose(@\"CFWriteStreamCallback - CanAcceptBytes\");\n\t\t\t\t\n\t\t\t\tif (asyncSocket->writeStream != stream)\n\t\t\t\t\treturn_from_block;\n\t\t\t\t\n\t\t\t\tif ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))\n\t\t\t\t{\n\t\t\t\t\t// If we set kCFStreamPropertySSLSettings before we opened the streams, this might be a lie.\n\t\t\t\t\t// (A callback related to the tcp stream, but not to the SSL layer).\n\t\t\t\t\t\n\t\t\t\t\tif (CFWriteStreamCanAcceptBytes(asyncSocket->writeStream))\n\t\t\t\t\t{\n\t\t\t\t\t\tasyncSocket->flags |= kSocketCanAcceptBytes;\n\t\t\t\t\t\t[asyncSocket cf_finishSSLHandshake];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tasyncSocket->flags |= kSocketCanAcceptBytes;\n\t\t\t\t\t[asyncSocket doWriteData];\n\t\t\t\t}\n\t\t\t}});\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tNSError *error = (__bridge_transfer NSError *)CFWriteStreamCopyError(stream);\n\t\t\t\n\t\t\tif (error == nil && type == kCFStreamEventEndEncountered)\n\t\t\t{\n\t\t\t\terror = [asyncSocket connectionClosedError];\n\t\t\t}\n\t\t\t\n\t\t\tdispatch_async(asyncSocket->socketQueue, ^{ @autoreleasepool {\n\t\t\t\t\n\t\t\t\tLogCVerbose(@\"CFWriteStreamCallback - Other\");\n\t\t\t\t\n\t\t\t\tif (asyncSocket->writeStream != stream)\n\t\t\t\t\treturn_from_block;\n\t\t\t\t\n\t\t\t\tif ((asyncSocket->flags & kStartingReadTLS) && (asyncSocket->flags & kStartingWriteTLS))\n\t\t\t\t{\n\t\t\t\t\t[asyncSocket cf_abortSSLHandshake:error];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t[asyncSocket closeWithError:error];\n\t\t\t\t}\n\t\t\t}});\n\t\t\t\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n}\n\n- (BOOL)createReadAndWriteStream\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\t\n\t\n\tif (readStream || writeStream)\n\t{\n\t\t// Streams already created\n\t\treturn YES;\n\t}\n\t\n\tint socketFD = (socket4FD != SOCKET_NULL) ? socket4FD : (socket6FD != SOCKET_NULL) ? socket6FD : socketUN;\n\t\n\tif (socketFD == SOCKET_NULL)\n\t{\n\t\t// Cannot create streams without a file descriptor\n\t\treturn NO;\n\t}\n\t\n\tif (![self isConnected])\n\t{\n\t\t// Cannot create streams until file descriptor is connected\n\t\treturn NO;\n\t}\n\t\n\tLogVerbose(@\"Creating read and write stream...\");\n\t\n\tCFStreamCreatePairWithSocket(NULL, (CFSocketNativeHandle)socketFD, &readStream, &writeStream);\n\t\n\t// The kCFStreamPropertyShouldCloseNativeSocket property should be false by default (for our case).\n\t// But let's not take any chances.\n\t\n\tif (readStream)\n\t\tCFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);\n\tif (writeStream)\n\t\tCFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);\n\t\n\tif ((readStream == NULL) || (writeStream == NULL))\n\t{\n\t\tLogWarn(@\"Unable to create read and write stream...\");\n\t\t\n\t\tif (readStream)\n\t\t{\n\t\t\tCFReadStreamClose(readStream);\n\t\t\tCFRelease(readStream);\n\t\t\treadStream = NULL;\n\t\t}\n\t\tif (writeStream)\n\t\t{\n\t\t\tCFWriteStreamClose(writeStream);\n\t\t\tCFRelease(writeStream);\n\t\t\twriteStream = NULL;\n\t\t}\n\t\t\n\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n- (BOOL)registerForStreamCallbacksIncludingReadWrite:(BOOL)includeReadWrite\n{\n\tLogVerbose(@\"%@ %@\", THIS_METHOD, (includeReadWrite ? @\"YES\" : @\"NO\"));\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\tNSAssert((readStream != NULL && writeStream != NULL), @\"Read/Write stream is null\");\n\t\n\tstreamContext.version = 0;\n\tstreamContext.info = (__bridge void *)(self);\n\tstreamContext.retain = nil;\n\tstreamContext.release = nil;\n\tstreamContext.copyDescription = nil;\n\t\n\tCFOptionFlags readStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;\n\tif (includeReadWrite)\n\t\treadStreamEvents |= kCFStreamEventHasBytesAvailable;\n\t\n\tif (!CFReadStreamSetClient(readStream, readStreamEvents, &CFReadStreamCallback, &streamContext))\n\t{\n\t\treturn NO;\n\t}\n\t\n\tCFOptionFlags writeStreamEvents = kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered;\n\tif (includeReadWrite)\n\t\twriteStreamEvents |= kCFStreamEventCanAcceptBytes;\n\t\n\tif (!CFWriteStreamSetClient(writeStream, writeStreamEvents, &CFWriteStreamCallback, &streamContext))\n\t{\n\t\treturn NO;\n\t}\n\t\n\treturn YES;\n}\n\n- (BOOL)addStreamsToRunLoop\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\tNSAssert((readStream != NULL && writeStream != NULL), @\"Read/Write stream is null\");\n\t\n\tif (!(flags & kAddedStreamsToRunLoop))\n\t{\n\t\tLogVerbose(@\"Adding streams to runloop...\");\n\t\t\n\t\t[[self class] startCFStreamThreadIfNeeded];\n        dispatch_sync(cfstreamThreadSetupQueue, ^{\n            [[self class] performSelector:@selector(scheduleCFStreams:)\n                                 onThread:cfstreamThread\n                               withObject:self\n                            waitUntilDone:YES];\n        });\n\t\tflags |= kAddedStreamsToRunLoop;\n\t}\n\t\n\treturn YES;\n}\n\n- (void)removeStreamsFromRunLoop\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\tNSAssert((readStream != NULL && writeStream != NULL), @\"Read/Write stream is null\");\n\t\n\tif (flags & kAddedStreamsToRunLoop)\n\t{\n\t\tLogVerbose(@\"Removing streams from runloop...\");\n        \n        dispatch_sync(cfstreamThreadSetupQueue, ^{\n            [[self class] performSelector:@selector(unscheduleCFStreams:)\n                                 onThread:cfstreamThread\n                               withObject:self\n                            waitUntilDone:YES];\n        });\n\t\t[[self class] stopCFStreamThreadIfNeeded];\n\t\t\n\t\tflags &= ~kAddedStreamsToRunLoop;\n\t}\n}\n\n- (BOOL)openStreams\n{\n\tLogTrace();\n\t\n\tNSAssert(dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey), @\"Must be dispatched on socketQueue\");\n\tNSAssert((readStream != NULL && writeStream != NULL), @\"Read/Write stream is null\");\n\t\n\tCFStreamStatus readStatus = CFReadStreamGetStatus(readStream);\n\tCFStreamStatus writeStatus = CFWriteStreamGetStatus(writeStream);\n\t\n\tif ((readStatus == kCFStreamStatusNotOpen) || (writeStatus == kCFStreamStatusNotOpen))\n\t{\n\t\tLogVerbose(@\"Opening read and write stream...\");\n\t\t\n\t\tBOOL r1 = CFReadStreamOpen(readStream);\n\t\tBOOL r2 = CFWriteStreamOpen(writeStream);\n\t\t\n\t\tif (!r1 || !r2)\n\t\t{\n\t\t\tLogError(@\"Error in CFStreamOpen\");\n\t\t\treturn NO;\n\t\t}\n\t}\n\t\n\treturn YES;\n}\n\n#endif\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Advanced\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n/**\n * See header file for big discussion of this method.\n**/\n- (BOOL)autoDisconnectOnClosedReadStream\n{\n\t// Note: YES means kAllowHalfDuplexConnection is OFF\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn ((config & kAllowHalfDuplexConnection) == 0);\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\t\t\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = ((config & kAllowHalfDuplexConnection) == 0);\n\t\t});\n\t\t\n\t\treturn result;\n\t}\n}\n\n/**\n * See header file for big discussion of this method.\n**/\n- (void)setAutoDisconnectOnClosedReadStream:(BOOL)flag\n{\n\t// Note: YES means kAllowHalfDuplexConnection is OFF\n\t\n\tdispatch_block_t block = ^{\n\t\t\n\t\tif (flag)\n\t\t\tconfig &= ~kAllowHalfDuplexConnection;\n\t\telse\n\t\t\tconfig |= kAllowHalfDuplexConnection;\n\t};\n\t\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n\n/**\n * See header file for big discussion of this method.\n**/\n- (void)markSocketQueueTargetQueue:(dispatch_queue_t)socketNewTargetQueue\n{\n\tvoid *nonNullUnusedPointer = (__bridge void *)self;\n\tdispatch_queue_set_specific(socketNewTargetQueue, IsOnSocketQueueOrTargetQueueKey, nonNullUnusedPointer, NULL);\n}\n\n/**\n * See header file for big discussion of this method.\n**/\n- (void)unmarkSocketQueueTargetQueue:(dispatch_queue_t)socketOldTargetQueue\n{\n\tdispatch_queue_set_specific(socketOldTargetQueue, IsOnSocketQueueOrTargetQueueKey, NULL, NULL);\n}\n\n/**\n * See header file for big discussion of this method.\n**/\n- (void)performBlock:(dispatch_block_t)block\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_sync(socketQueue, block);\n}\n\n/**\n * Questions? Have you read the header file?\n**/\n- (int)socketFD\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn SOCKET_NULL;\n\t}\n\t\n\tif (socket4FD != SOCKET_NULL)\n\t\treturn socket4FD;\n\telse\n\t\treturn socket6FD;\n}\n\n/**\n * Questions? Have you read the header file?\n**/\n- (int)socket4FD\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn SOCKET_NULL;\n\t}\n\t\n\treturn socket4FD;\n}\n\n/**\n * Questions? Have you read the header file?\n**/\n- (int)socket6FD\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn SOCKET_NULL;\n\t}\n\t\n\treturn socket6FD;\n}\n\n#if TARGET_OS_IPHONE\n\n/**\n * Questions? Have you read the header file?\n**/\n- (CFReadStreamRef)readStream\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn NULL;\n\t}\n\t\n\tif (readStream == NULL)\n\t\t[self createReadAndWriteStream];\n\t\n\treturn readStream;\n}\n\n/**\n * Questions? Have you read the header file?\n**/\n- (CFWriteStreamRef)writeStream\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn NULL;\n\t}\n\t\n\tif (writeStream == NULL)\n\t\t[self createReadAndWriteStream];\n\t\n\treturn writeStream;\n}\n\n- (BOOL)enableBackgroundingOnSocketWithCaveat:(BOOL)caveat\n{\n\tif (![self createReadAndWriteStream])\n\t{\n\t\t// Error occurred creating streams (perhaps socket isn't open)\n\t\treturn NO;\n\t}\n\t\n\tBOOL r1, r2;\n\t\n\tLogVerbose(@\"Enabling backgrouding on socket\");\n\t\n\tr1 = CFReadStreamSetProperty(readStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);\n\tr2 = CFWriteStreamSetProperty(writeStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP);\n\t\n\tif (!r1 || !r2)\n\t{\n\t\treturn NO;\n\t}\n\t\n\tif (!caveat)\n\t{\n\t\tif (![self openStreams])\n\t\t{\n\t\t\treturn NO;\n\t\t}\n\t}\n\t\n\treturn YES;\n}\n\n/**\n * Questions? Have you read the header file?\n**/\n- (BOOL)enableBackgroundingOnSocket\n{\n\tLogTrace();\n\t\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn NO;\n\t}\n\t\n\treturn [self enableBackgroundingOnSocketWithCaveat:NO];\n}\n\n- (BOOL)enableBackgroundingOnSocketWithCaveat // Deprecated in iOS 4.???\n{\n\t// This method was created as a workaround for a bug in iOS.\n\t// Apple has since fixed this bug.\n\t// I'm not entirely sure which version of iOS they fixed it in...\n\t\n\tLogTrace();\n\t\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn NO;\n\t}\n\t\n\treturn [self enableBackgroundingOnSocketWithCaveat:YES];\n}\n\n#endif\n\n- (SSLContextRef)sslContext\n{\n\tif (!dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\tLogWarn(@\"%@ - Method only available from within the context of a performBlock: invocation\", THIS_METHOD);\n\t\treturn NULL;\n\t}\n\t\n\treturn sslContext;\n}\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n#pragma mark Class Utilities\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n+ (NSMutableArray *)lookupHost:(NSString *)host port:(uint16_t)port error:(NSError **)errPtr\n{\n\tLogTrace();\n\t\n\tNSMutableArray *addresses = nil;\n\tNSError *error = nil;\n\t\n\tif ([host isEqualToString:@\"localhost\"] || [host isEqualToString:@\"loopback\"])\n\t{\n\t\t// Use LOOPBACK address\n\t\tstruct sockaddr_in nativeAddr4;\n\t\tnativeAddr4.sin_len         = sizeof(struct sockaddr_in);\n\t\tnativeAddr4.sin_family      = AF_INET;\n\t\tnativeAddr4.sin_port        = htons(port);\n\t\tnativeAddr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);\n\t\tmemset(&(nativeAddr4.sin_zero), 0, sizeof(nativeAddr4.sin_zero));\n\t\t\n\t\tstruct sockaddr_in6 nativeAddr6;\n\t\tnativeAddr6.sin6_len        = sizeof(struct sockaddr_in6);\n\t\tnativeAddr6.sin6_family     = AF_INET6;\n\t\tnativeAddr6.sin6_port       = htons(port);\n\t\tnativeAddr6.sin6_flowinfo   = 0;\n\t\tnativeAddr6.sin6_addr       = in6addr_loopback;\n\t\tnativeAddr6.sin6_scope_id   = 0;\n\t\t\n\t\t// Wrap the native address structures\n\t\t\n\t\tNSData *address4 = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];\n\t\tNSData *address6 = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];\n\t\t\n\t\taddresses = [NSMutableArray arrayWithCapacity:2];\n\t\t[addresses addObject:address4];\n\t\t[addresses addObject:address6];\n\t}\n\telse\n\t{\n\t\tNSString *portStr = [NSString stringWithFormat:@\"%hu\", port];\n\t\t\n\t\tstruct addrinfo hints, *res, *res0;\n\t\t\n\t\tmemset(&hints, 0, sizeof(hints));\n\t\thints.ai_family   = PF_UNSPEC;\n\t\thints.ai_socktype = SOCK_STREAM;\n\t\thints.ai_protocol = IPPROTO_TCP;\n\t\t\n\t\tint gai_error = getaddrinfo([host UTF8String], [portStr UTF8String], &hints, &res0);\n\t\t\n\t\tif (gai_error)\n\t\t{\n\t\t\terror = [self gaiError:gai_error];\n\t\t}\n\t\telse\n\t\t{\n\t\t\tNSUInteger capacity = 0;\n\t\t\tfor (res = res0; res; res = res->ai_next)\n\t\t\t{\n\t\t\t\tif (res->ai_family == AF_INET || res->ai_family == AF_INET6) {\n\t\t\t\t\tcapacity++;\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\taddresses = [NSMutableArray arrayWithCapacity:capacity];\n\t\t\t\n\t\t\tfor (res = res0; res; res = res->ai_next)\n\t\t\t{\n\t\t\t\tif (res->ai_family == AF_INET)\n\t\t\t\t{\n\t\t\t\t\t// Found IPv4 address.\n\t\t\t\t\t// Wrap the native address structure, and add to results.\n\t\t\t\t\t\n\t\t\t\t\tNSData *address4 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];\n\t\t\t\t\t[addresses addObject:address4];\n\t\t\t\t}\n\t\t\t\telse if (res->ai_family == AF_INET6)\n\t\t\t\t{\n\t\t\t\t\t// Fixes connection issues with IPv6\n\t\t\t\t\t// https://github.com/robbiehanson/CocoaAsyncSocket/issues/429#issuecomment-222477158\n\t\t\t\t\t\n\t\t\t\t\t// Found IPv6 address.\n\t\t\t\t\t// Wrap the native address structure, and add to results.\n\t\t\t\t\t\n\t\t\t\t\tstruct sockaddr_in6 *sockaddr = (struct sockaddr_in6 *)res->ai_addr;\n\t\t\t\t\tin_port_t *portPtr = &sockaddr->sin6_port;\n\t\t\t\t\tif ((portPtr != NULL) && (*portPtr == 0)) {\n\t\t\t\t\t        *portPtr = htons(port);\n\t\t\t\t\t}\n\n\t\t\t\t\tNSData *address6 = [NSData dataWithBytes:res->ai_addr length:res->ai_addrlen];\n\t\t\t\t\t[addresses addObject:address6];\n\t\t\t\t}\n\t\t\t}\n\t\t\tfreeaddrinfo(res0);\n\t\t\t\n\t\t\tif ([addresses count] == 0)\n\t\t\t{\n\t\t\t\terror = [self gaiError:EAI_FAIL];\n\t\t\t}\n\t\t}\n\t}\n\t\n\tif (errPtr) *errPtr = error;\n\treturn addresses;\n}\n\n+ (NSString *)hostFromSockaddr4:(const struct sockaddr_in *)pSockaddr4\n{\n\tchar addrBuf[INET_ADDRSTRLEN];\n\t\n\tif (inet_ntop(AF_INET, &pSockaddr4->sin_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)\n\t{\n\t\taddrBuf[0] = '\\0';\n\t}\n\t\n\treturn [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];\n}\n\n+ (NSString *)hostFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6\n{\n\tchar addrBuf[INET6_ADDRSTRLEN];\n\t\n\tif (inet_ntop(AF_INET6, &pSockaddr6->sin6_addr, addrBuf, (socklen_t)sizeof(addrBuf)) == NULL)\n\t{\n\t\taddrBuf[0] = '\\0';\n\t}\n\t\n\treturn [NSString stringWithCString:addrBuf encoding:NSASCIIStringEncoding];\n}\n\n+ (uint16_t)portFromSockaddr4:(const struct sockaddr_in *)pSockaddr4\n{\n\treturn ntohs(pSockaddr4->sin_port);\n}\n\n+ (uint16_t)portFromSockaddr6:(const struct sockaddr_in6 *)pSockaddr6\n{\n\treturn ntohs(pSockaddr6->sin6_port);\n}\n\n+ (NSURL *)urlFromSockaddrUN:(const struct sockaddr_un *)pSockaddr\n{\n\tNSString *path = [NSString stringWithUTF8String:pSockaddr->sun_path];\n\treturn [NSURL fileURLWithPath:path];\n}\n\n+ (NSString *)hostFromAddress:(NSData *)address\n{\n\tNSString *host;\n\t\n\tif ([self getHost:&host port:NULL fromAddress:address])\n\t\treturn host;\n\telse\n\t\treturn nil;\n}\n\n+ (uint16_t)portFromAddress:(NSData *)address\n{\n\tuint16_t port;\n\t\n\tif ([self getHost:NULL port:&port fromAddress:address])\n\t\treturn port;\n\telse\n\t\treturn 0;\n}\n\n+ (BOOL)isIPv4Address:(NSData *)address\n{\n\tif ([address length] >= sizeof(struct sockaddr))\n\t{\n\t\tconst struct sockaddr *sockaddrX = [address bytes];\n\t\t\n\t\tif (sockaddrX->sa_family == AF_INET) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\t\n\treturn NO;\n}\n\n+ (BOOL)isIPv6Address:(NSData *)address\n{\n\tif ([address length] >= sizeof(struct sockaddr))\n\t{\n\t\tconst struct sockaddr *sockaddrX = [address bytes];\n\t\t\n\t\tif (sockaddrX->sa_family == AF_INET6) {\n\t\t\treturn YES;\n\t\t}\n\t}\n\t\n\treturn NO;\n}\n\n+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr fromAddress:(NSData *)address\n{\n\treturn [self getHost:hostPtr port:portPtr family:NULL fromAddress:address];\n}\n\n+ (BOOL)getHost:(NSString **)hostPtr port:(uint16_t *)portPtr family:(sa_family_t *)afPtr fromAddress:(NSData *)address\n{\n\tif ([address length] >= sizeof(struct sockaddr))\n\t{\n\t\tconst struct sockaddr *sockaddrX = [address bytes];\n\t\t\n\t\tif (sockaddrX->sa_family == AF_INET)\n\t\t{\n\t\t\tif ([address length] >= sizeof(struct sockaddr_in))\n\t\t\t{\n\t\t\t\tstruct sockaddr_in sockaddr4;\n\t\t\t\tmemcpy(&sockaddr4, sockaddrX, sizeof(sockaddr4));\n\t\t\t\t\n\t\t\t\tif (hostPtr) *hostPtr = [self hostFromSockaddr4:&sockaddr4];\n\t\t\t\tif (portPtr) *portPtr = [self portFromSockaddr4:&sockaddr4];\n\t\t\t\tif (afPtr)   *afPtr   = AF_INET;\n\t\t\t\t\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\t\telse if (sockaddrX->sa_family == AF_INET6)\n\t\t{\n\t\t\tif ([address length] >= sizeof(struct sockaddr_in6))\n\t\t\t{\n\t\t\t\tstruct sockaddr_in6 sockaddr6;\n\t\t\t\tmemcpy(&sockaddr6, sockaddrX, sizeof(sockaddr6));\n\t\t\t\t\n\t\t\t\tif (hostPtr) *hostPtr = [self hostFromSockaddr6:&sockaddr6];\n\t\t\t\tif (portPtr) *portPtr = [self portFromSockaddr6:&sockaddr6];\n\t\t\t\tif (afPtr)   *afPtr   = AF_INET6;\n\t\t\t\t\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\t}\n\t\n\treturn NO;\n}\n\n+ (NSData *)CRLFData\n{\n\treturn [NSData dataWithBytes:\"\\x0D\\x0A\" length:2];\n}\n\n+ (NSData *)CRData\n{\n\treturn [NSData dataWithBytes:\"\\x0D\" length:1];\n}\n\n+ (NSData *)LFData\n{\n\treturn [NSData dataWithBytes:\"\\x0A\" length:1];\n}\n\n+ (NSData *)ZeroData\n{\n\treturn [NSData dataWithBytes:\"\" length:1];\n}\n\n#pragma mark -\n#pragma mark Third Party Modifications\n\n- (BOOL)useStrictTimers\n{\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t{\n\t\treturn (config & kUseStrictTimers);\n\t}\n\telse\n\t{\n\t\t__block BOOL result;\n\n\t\tdispatch_sync(socketQueue, ^{\n\t\t\tresult = (config & kUseStrictTimers);\n\t\t});\n\n\t\treturn result;\n\t}\n}\n\n- (void)setUseStrictTimers:(BOOL)flag\n{\n\tdispatch_block_t block = ^{\n\t\tif (flag)\n\t\t\tconfig |= kUseStrictTimers;\n\t\telse\n\t\t\tconfig &= ~kUseStrictTimers;\n\t};\n\n\tif (dispatch_get_specific(IsOnSocketQueueOrTargetQueueKey))\n\t\tblock();\n\telse\n\t\tdispatch_async(socketQueue, block);\n}\n\n@end\t\n"
  },
  {
    "path": "Sources/Shared/Library/External Libraries/Sockets/GCDAsyncSocketExtensions.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"GCDAsyncSocketExtensions.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation GCDAsyncSocket (GCDsyncSocketExtensions)\n\n+ (instancetype)socketWithDelegate:(id)aDelegate delegateQueue:(dispatch_queue_t)dq socketQueue:(dispatch_queue_t)sq\n{\n\treturn [[self alloc] initWithDelegate:aDelegate delegateQueue:dq socketQueue:sq];\n}\n\n- (tls_protocol_version_t)tlsNegotiatedProtocol\n{\n\t__block SSLProtocol protocol;\n\n\tdispatch_block_t block = ^{\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t\tOSStatus status = SSLGetNegotiatedProtocolVersion(self.sslContext, &protocol);\nTEXTUAL_IGNORE_DEPRECATION_END\n\n#pragma unused(status)\n\t};\n\n\t[self performBlock:block];\n\n\treturn [RCMSecureTransport protocolTypeFromDeprecated:protocol];\n}\n\n- (tls_ciphersuite_t)tlsNegotiatedCipherSuite\n{\n\t__block SSLCipherSuite cipher;\n\n\tdispatch_block_t block = ^{\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t\tOSStatus status = SSLGetNegotiatedCipher(self.sslContext, &cipher);\nTEXTUAL_IGNORE_DEPRECATION_END\n\n#pragma unused(status)\n\t};\n\n\t[self performBlock:block];\n\n\t/* This can be easily cast because they refer to the same code points. */\n\treturn (tls_ciphersuite_t)cipher;\n}\n\n- (SecTrustRef)tlsTrustRef\n{\n\t__block SecTrustRef trust;\n\n\tdispatch_block_t block = ^{\nTEXTUAL_IGNORE_DEPRECATION_BEGIN\n\t\tOSStatus status = SSLCopyPeerTrust(self.sslContext, &trust);\nTEXTUAL_IGNORE_DEPRECATION_END\n\n#pragma unused(status)\n\t};\n\n\t[self performBlock:block];\n\n\treturn trust;\n}\n\n- (nullable NSArray<NSData *> *)tlsCertificateChainData\n{\n\tSecTrustRef trustRef = self.tlsTrustRef;\n\n\tif (trustRef == NULL) {\n\t\treturn nil;\n\t}\n\n\treturn [RCMSecureTransport certificatesInTrust:trustRef];\n}\n\n- (nullable NSString *)tlsPolicyName\n{\n\tSecTrustRef trustRef = self.tlsTrustRef;\n\n\tif (trustRef == NULL) {\n\t\treturn nil;\n\t}\n\n\treturn [RCMSecureTransport policyNameInTrust:trustRef];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Library/TLOLocalization.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOLocalization.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Extension declared by TLOLocalization.swift */\n@interface NSString (LocalizationPrivate)\n+ (NSString *)_swift_localizedKey:(NSString *)string bundle:(NSBundle *)bundle;\n@end\n\nNSString *TXTLS(NSString *key, ...)\n{\n\tNSCParameterAssert(key != nil);\n\n\tva_list arguments;\n\tva_start(arguments, key);\n\n\tNSString *result = TXLocalizedString(RZMainBundle(), key, arguments);\n\n\tva_end(arguments);\n\n\treturn result;\n}\n\nNSString *TXLocalizedString(NSBundle *bundle, NSString *key, va_list arguments)\n{\n\tNSCParameterAssert(bundle != nil);\n\tNSCParameterAssert(key != nil);\n\tNSCParameterAssert(arguments != NULL);\n\n\tNSString *localValue = [NSString _swift_localizedKey:key bundle:bundle];\n\n\treturn [[NSString alloc] initWithFormat:localValue arguments:arguments];\n}\n\nNSString *TXLocalizedStringAlternative(NSBundle *bundle, NSString *key, ...)\n{\n\tNSCParameterAssert(bundle != nil);\n\tNSCParameterAssert(key != nil);\n\n\tva_list arguments;\n\tva_start(arguments, key);\n\n\tNSString *result = TXLocalizedString(bundle, key, arguments);\n\n\tva_end(arguments);\n\n\treturn result;\n}\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Library/TLOLocalization.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n*    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n///\n/// Given an input string, table, and bundle; these helpers perform localization.\n///\n/// • \"BasicLanguage\" is the default localization table.\n/// • The main bundle is the default localization bundle.\n///\n/// When the \"specialKey\" argument is false, the input string is not treated special.\n/// It and the other arguments are handed directly to NSLocalizedString().\n///\n/// Textual has a unique localization system, which is enabled by setting \"specialKey\" to true.\n/// When set to true, the input string is expected to be in the format: \"<table>[<key>]\"\n///\n/// Everything left of the first open bracket (\"[\") is treated as the table name.\n/// Everything inside of the first open bracket (\"[\") and first close bracket (\"]\")\n/// is treated as the \"key\" - The key is typically just a random combination of characters.\n///\n/// For example: \"'7r2-4h' = 'Some text'\"; in Common.strings is accessed with \"Common[7r2-4h]\"\n///\n/// When the key is assigned in the strings file, it is not prefaced by the table name.\n///\n\n///\n/// Performs localization with a special key\n///\npublic func LocalizedKey(_ key: String, _ arguments: CVarArg..., table: String = \"BasicLanguage\", bundle: Bundle = Bundle.main) -> String\n{\n\treturn localize(string: key, arguments: arguments, table: table, bundle: bundle, specialKey: true)\n}\n\n///\n/// Performs localization with input string\n///\npublic func LocalizedString(_ string: String, _ arguments: CVarArg..., table: String = \"BasicLanguage\", bundle: Bundle = Bundle.main) -> String\n{\n\treturn localize(string: string, arguments: arguments, table: table, bundle: bundle, specialKey: false)\n}\n\n@inline(__always)\nfileprivate func localize(string: String, arguments: [CVarArg], table: String, bundle: Bundle, specialKey: Bool) -> String\n{\n\tlet formatter = String(localized: string, table: table, bundle: bundle, specialKey: specialKey)\n\n\tif (arguments.isEmpty) {\n\t\treturn formatter\n\t}\n\n\treturn String(format: formatter, arguments: arguments)\n}\n\nfileprivate extension String\n{\n\tinit (localized string: String, table: String, bundle: Bundle, specialKey: Bool)\n\t{\n\t\tguard specialKey,\n\t\t\tlet openBracket = string.firstIndex(of: \"[\"),\n\t\t\tlet closeBracket = string.firstIndex(of: \"]\") else\n\t\t{\n\t\t\tself = bundle.localizedString(forKey: string, value: nil, table: table)\n\n\t\t\treturn\n\t\t}\n\n\t\t/* Given keys in the format \"<table>[<key>]\",\n\t\textract the two values and lookup the result. */\n\t\tlet tableName = String(string[string.startIndex ..< openBracket])\n\t\tlet tableKey = String(string[(string.index(openBracket, offsetBy: 1)) ..< closeBracket])\n\n\t\t/* Backwards compatibility for plugins */\n\t\t//\n\t\t// The format of key assignments changed in version 7.1.0.\n\t\t// In prior versions, the table name was included in the assignment.\n\t\t//\n\t\t// Assignment in 7.1.0:\n\t\t//     \"7r2-4h\" = \"Some text\";\n\t\t//\n\t\t// Assignment before 7.1.0:\n\t\t//     \"Common[0001]\" = \"Some text\";\n\t\t//\n\t\t// To support plugins that still have the old format compiled in,\n\t\t// we check whether the key we have contains a dash.\n\t\t//\n\t\t// Keys prior to version 7.0.10 /should/ not ever contain a dash.\n\t\t//\n\t\t// If a dash is present, then we use the original input string as key.\n\t\t//\n\t\tif (tableKey.contains(\"-\")) {\n\t\t\tself = bundle.localizedString(forKey: tableKey, value: nil, table: tableName)\n\t\t} else {\n\t\t\tself = bundle.localizedString(forKey: string, value: nil, table: tableName)\n\t\t}\n\t}\n}\n\n//\n// This extension gives TXTLS() and its sister C functions access\n// to the logic needed to pluck out a localized string.\n// Those functions will perform argument formatting on their end\n// given the result because you can't pass arguments from C -> Swift.\n//\nextension NSString\n{\n\t@objc(_swift_localizedKey:bundle:)\n\tclass func localize(key: String, bundle: Bundle) -> NSString\n\t{\n\t\treturn String(localized: key, table: \"BasicLanguage\", bundle: bundle, specialKey: true) as NSString\n\t}\n}\n"
  },
  {
    "path": "Sources/Shared/Library/TLOTimer.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TLOTimer.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface TLOTimer ()\n@property (nonatomic, copy, readwrite) TLOTimerActionBlock actionBlock;\n@property (nonatomic, assign, readwrite) NSTimeInterval startTime;\n@property (nonatomic, assign, readwrite) NSTimeInterval interval;\n@property (nonatomic, assign, readwrite) BOOL repeatTimer;\n@property (nonatomic, assign, readwrite) NSUInteger iterations;\n@property (nonatomic, assign, readwrite) NSUInteger currentIteration;\n@property (nonatomic, strong, nullable) dispatch_source_t timerSource;\n@end\n\n@implementation TLOTimer\n\n+ (instancetype)timerWithActionBlock:(TLOTimerActionBlock)actionBlock\n{\n\tNSParameterAssert(actionBlock != NULL);\n\n\treturn [[self alloc] initWithActionBlock:actionBlock onQueue:nil];\n}\n\n+ (instancetype)timerWithActionBlock:(TLOTimerActionBlock)actionBlock onQueue:(dispatch_queue_t)queue\n{\n\tNSParameterAssert(actionBlock != NULL);\n\tNSParameterAssert(queue != NULL);\n\n\treturn [[self alloc] initWithActionBlock:actionBlock onQueue:queue];\n}\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithActionBlock:(TLOTimerActionBlock)actionBlock\n{\n\treturn [self initWithActionBlock:actionBlock onQueue:nil];\n}\n\n- (instancetype)initWithActionBlock:(TLOTimerActionBlock)actionBlock onQueue:(dispatch_queue_t)queue\n{\n\tNSParameterAssert(actionBlock != NULL);\n\n\tif ((self = [super init])) {\n\t\tself.actionBlock = actionBlock;\n\n\t\tself.queue = queue;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)dealloc\n{\n\t[self stop];\n}\n\n- (BOOL)timerIsActive\n{\n\treturn (self.timerSource != nil);\n}\n\n- (NSTimeInterval)timeRemaining\n{\n\treturn (self.interval - (CFAbsoluteTimeGetCurrent() - self.startTime));\n}\n\n- (void)start:(NSTimeInterval)timerInterval\n{\n\t[self start:timerInterval onRepeat:NO iterations:0];\n}\n\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer\n{\n\t[self start:timerInterval onRepeat:repeatTimer iterations:0];\n}\n\n- (void)start:(NSTimeInterval)timerInterval onRepeat:(BOOL)repeatTimer iterations:(NSUInteger)iterations\n{\n\tNSParameterAssert(timerInterval > 0);\n\n\t[self stop];\n\n\tdispatch_queue_t sourceQueue = self.queue;\n\n\tif (sourceQueue == nil) {\n\t\tsourceQueue = dispatch_get_main_queue();\n\t}\n\n\tdispatch_source_t timerSource = XRScheduleBlockOnQueue(sourceQueue, ^{\n\t\t[self fireTimer];\n\t}, timerInterval, repeatTimer);\n\n\tself.interval = timerInterval;\n\tself.repeatTimer = repeatTimer;\n\tself.iterations = iterations;\n\tself.currentIteration = 0;\n\n\tself.timerSource = timerSource;\n\n\tXRResumeScheduledBlock(timerSource);\n\n\tself.startTime = CFAbsoluteTimeGetCurrent();\n}\n\n- (void)stop\n{\n\tdispatch_source_t timerSource = self.timerSource;\n\n\tif (timerSource == nil) {\n\t\treturn;\n\t}\n\n\tXRCancelScheduledBlock(timerSource);\n\n\tself.timerSource = nil;\n}\n\n- (void)stopIfNeeded\n{\n\tif (self.iterations > 0 &&\n\t\tself.iterations == self.currentIteration)\n\t{\n\t\t[self stop];\n\t}\n}\n\n- (void)fireTimer\n{\n\tself.currentIteration += 1;\n\n\t/* In the logic presented below, we call\n\t -stopIfNeeded before the action. */\n\t/* We should probably always keep this progression so\n\t that the action can know when the iterations limit\n\t has been reached by the fact the timer has stopped. */\n\n\t/* Perform block */\n\tTLOTimerActionBlock actionBlock = self.actionBlock;\n\n\t[self stopIfNeeded];\n\n\tactionBlock(self);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Preferences/TPCPreferences.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2008 - 2010 Satoshi Nakagawa <psychs AT limechat DOT net>\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"TPCPreferencesPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation TPCPreferences\n\n#pragma mark -\n#pragma mark Inline Image Size\n\n+ (uint64_t)inlineImagesMaxFilesize\n{\n\tNSUInteger filesizeTag = [RZUserDefaults() unsignedIntegerForKey:@\"InlineMediaMaximumFilesize\"];\n\n\tswitch (filesizeTag) {\n#define _dv(key, value)\t\tcase (key): { return (value); }\n\n\t\t_dv(1, (uint64_t)1048576) // 1 MB\n\t\t_dv(2, (uint64_t)2097152) // 2 MB\n\t\t_dv(3, (uint64_t)3145728) // 3 MB\n\t\t_dv(4, (uint64_t)4194304) // 4 MB\n\t\t_dv(5, (uint64_t)5242880) // 5 MB\n\t\t_dv(6, (uint64_t)10485760) // 10 MB\n\t\t_dv(7, (uint64_t)15728640) // 15 MB\n\t\t_dv(8, (uint64_t)20971520) // 20 MB\n\t\t_dv(9, (uint64_t)52428800) // 50 MB\n\t\t_dv(10, (uint64_t)104857600) // 100 MB\n\n#undef _dv\n\t}\n\n\treturn (uint64_t)2097152; // 2 MB\n}\n\n+ (NSUInteger)inlineMediaMaxWidth\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"InlineMediaScalingWidth\"];\n}\n\n+ (NSUInteger)inlineMediaMaxHeight\n{\n\treturn [RZUserDefaults() unsignedIntegerForKey:@\"InlineMediaMaximumHeight\"];\n}\n\n+ (void)setInlineMediaMaxWidth:(NSUInteger)value\n{\n\t[RZUserDefaults() setUnsignedInteger:value forKey:@\"InlineMediaScalingWidth\"];\n}\n\n+ (void)setInlineMediaMaxHeight:(NSUInteger)value\n{\n\t[RZUserDefaults() setUnsignedInteger:value forKey:@\"InlineMediaMaximumHeight\"];\n}\n\n+ (BOOL)inlineMediaLimitToBasics\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaLimitToBasics\"];\n}\n\n+ (void)setInlineMediaLimitToBasics:(BOOL)inlineMediaLimitToBasics\n{\n\t[RZUserDefaults() setBool:inlineMediaLimitToBasics forKey:@\"InlineMediaLimitToBasics\"];\n}\n\n+ (BOOL)inlineMediaLimitBasicsToFiles\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaLimitBasicsToFiles\"];\n}\n\n+ (void)setInlineMediaLimitBasicsToFiles:(BOOL)inlineMediaLimitBasicsToFiles\n{\n\t[RZUserDefaults() setBool:inlineMediaLimitBasicsToFiles forKey:@\"InlineMediaLimitBasicsToFiles\"];\n}\n\n+ (BOOL)inlineMediaLimitInsecureContent\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaLimitInsecureContent\"];\n}\n\n+ (BOOL)inlineMediaLimitNaughtyContent\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaLimitNaughtyContent\"];\n}\n\n+ (BOOL)inlineMediaLimitUnsafeContent\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaLimitUnsafeContent\"];\n}\n\n+ (BOOL)inlineMediaCheckEverything\n{\n\treturn [RZUserDefaults() boolForKey:@\"InlineMediaCheckEverything\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Preferences/TPCPreferencesUserDefaults.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#include \"BuildConfig.h\"\n\n#import \"TPCPreferencesUserDefaults.h\"\n\n/* TPCPreferencesUserDefaults is specifically designed for reading and writing\n from the main app's preferences file, even within an XPC service. */\n/* NSUserDefaults can be used in an XPC service if service specific preferences\n need to be retained somehow. */\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const TPCPreferencesUserDefaultsDidChangeNotification = @\"TPCPreferencesUserDefaultsDidChangeNotification\";\n\n#pragma mark -\n#pragma mark Reading & Writing\n\n@implementation TPCPreferencesUserDefaults\n\n+ (TPCPreferencesUserDefaults *)sharedUserDefaults\n{\n\tstatic id sharedSelf = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsharedSelf = [[self alloc] _initGroupContainer];\n\t});\n\n\treturn sharedSelf;\n}\n\n- (instancetype)_initGroupContainer\n{\n\tTPCPreferencesUserDefaults *defaults = [super initWithSuiteName:TXBundleBuildGroupContainerIdentifier];\n\n\treturn defaults;\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wobjc-designated-initializers\"\n- (instancetype)init\n{\n\treturn [self.class sharedUserDefaults];\n}\n\n- (nullable instancetype)initWithSuiteName:(nullable NSString *)suitename\n{\n\treturn [self.class sharedUserDefaults];\n}\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n- (nullable instancetype)initWithUser:(NSString *)username\n{\n\treturn [self.class sharedUserDefaults];\n}\n#pragma clang diagnostic pop\n#pragma clang diagnostic pop\n\n- (void)_setObject:(nullable id)value forKey:(NSString *)defaultName\n{\n\t[super setObject:value forKey:defaultName];\n}\n\n- (void)setObject:(nullable id)value forKey:(NSString *)defaultName\n{\n\t[self setObject:value forKey:defaultName postNotification:YES];\n}\n\n- (void)setObject:(nullable id)value forKey:(NSString *)defaultName postNotification:(BOOL)postNotification\n{\n\tNSParameterAssert(defaultName != nil);\n\n\tid oldValue = [self objectForKey:defaultName];\n\n\tif (oldValue && oldValue == value) {\n\t\treturn;\n\t}\n\n\t[self willChangeValueForKey:defaultName];\n\n\tif (value == nil) {\n\t\tif (oldValue) {\n\t\t\t[self _setObject:nil forKey:defaultName];\n\t\t}\n\t} else {\n\t\t[self _setObject:value forKey:defaultName];\n\t}\n\n\t[self didChangeValueForKey:defaultName];\n\n\tif (postNotification) {\n\t\t[RZNotificationCenter() postNotificationName:TPCPreferencesUserDefaultsDidChangeNotification\n\t\t\t\t\t\t\t\t\t\t\t  object:self\n\t\t\t\t\t\t\t\t\t\t\tuserInfo:@{@\"changedKey\" : defaultName}];\n\n\t\t/* We currently don't need to communicate preferences changes between the\n\t\t main app and XPC services, but if we do, then we should enable this code. */\n#if 0\n\t\t[RZDistributedNotificationCenter() postNotificationName:TPCPreferencesUserDefaultsDidChangeNotification\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t object:@\"TPCPreferencesUserDefaults\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t   userInfo:@{@\"changedKey\" : defaultName}];\n#endif\n\t}\n}\n\n- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setUnsignedInteger:(NSUInteger)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setShort:(short)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setUnsignedShort:(unsigned short)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setLong:(long)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setUnsignedLong:(unsigned long)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setLongLong:(long long)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setUnsignedLongLong:(unsigned long long)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setFloat:(float)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setDouble:(double)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setBool:(BOOL)value forKey:(NSString *)defaultName\n{\n\t[self setObject:@(value) forKey:defaultName];\n}\n\n- (void)setURL:(nullable NSURL *)value forKey:(NSString *)defaultName\n{\n\t[self setObject:value forKey:defaultName];\n}\n\n- (void)removeObjectForKey:(NSString *)defaultName\n{\n\t[self setObject:nil forKey:defaultName];\n}\n\n- (void)registerDefault:(id <NSCopying>)value forKey:(NSString *)defaultName\n{\n\tNSParameterAssert(value != nil);\n\tNSParameterAssert(defaultName != nil);\n\n\t[self registerDefaults:@{defaultName : value}];\n}\n\n- (NSDictionary<NSString *, id> *)registeredDefaults\n{\n\treturn [self volatileDomainForName:NSRegistrationDomain];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Object KVO Proxying\n\n@implementation TPCPreferencesUserDefaultsController\n\n- (instancetype)_initWithSharedDefaults\n{\n\tTPCPreferencesUserDefaults *defaults = [TPCPreferencesUserDefaults sharedUserDefaults];\n\n\treturn [super initWithDefaults:defaults initialValues:nil];\n}\n\n- (instancetype)init\n{\n\treturn [self _initWithSharedDefaults];\n}\n\n- (nullable instancetype)initWithCoder:(NSCoder *)coder\n{\n\treturn [self _initWithSharedDefaults];\n}\n\n- (instancetype)initWithDefaults:(nullable NSUserDefaults *)defaults initialValues:(nullable NSDictionary<NSString *, id> *)initialValues\n{\n\treturn [self _initWithSharedDefaults];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "Sources/Shared/Views/Channel View/TVCLogLineXPC.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TVCLogLineXPCPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* TVCLogLineXPC is a container class for TVCLogLine when stored in a\n Core Data store. -data is the secure coded version of the class which is\n portable and can be stored in an offline database. */\n@interface TVCLogLineXPC ()\n@property (nonatomic, copy, readwrite) NSData *data;\n@property (nonatomic, copy, readwrite) NSString *uniqueIdentifier;\n@property (nonatomic, copy, readwrite) NSString *viewIdentifier;\n@property (nonatomic, assign, readwrite) NSUInteger sessionIdentifier;\n@property (nonatomic, assign, readwrite) NSTimeInterval creationDate;\n@end\n\n@implementation TVCLogLineXPC\n\n- (instancetype)initWithLogLineData:(NSData *)data uniqueIdentifier:(NSString *)uniqueIdentifier viewIdentifier:(NSString *)viewIdentifier sessionIdentifier:(NSUInteger)sessionIdentifier\n{\n\tNSParameterAssert(data != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(viewIdentifier != nil);\n\n\tif ((self = [super init])) {\n\t\tself.data = data;\n\t\tself.uniqueIdentifier = uniqueIdentifier;\n\t\tself.viewIdentifier = viewIdentifier;\n\t\tself.sessionIdentifier = sessionIdentifier;\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject\n{\n\tNSParameterAssert(managedObject != nil);\n\n\tif ((self = [super init])) {\n\t\tself.data = [managedObject valueForKey:@\"logLineData\"];\n\t\tself.uniqueIdentifier = [managedObject valueForKey:@\"logLineUniqueIdentifier\"];\n\t\tself.viewIdentifier = [managedObject valueForKey:@\"logLineViewIdentifier\"];\n\t\tself.sessionIdentifier = [[managedObject valueForKey:@\"sessionIdentifier\"] integerValue];\n\t\tself.creationDate = [[managedObject valueForKey:@\"entryCreationDate\"] doubleValue];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder\n{\n\tNSParameterAssert(aDecoder != nil);\n\n\tif ((self = [super init])) {\n\t\t[self decodeWithCoder:aDecoder];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)decodeWithCoder:(NSCoder *)aDecoder\n{\n\tNSParameterAssert(aDecoder != nil);\n\n\tself->_data = [aDecoder decodeDataForKey:@\"data\"];\n\tself->_uniqueIdentifier = [aDecoder decodeStringForKey:@\"uniqueIdentifier\"];\n\tself->_viewIdentifier = [aDecoder decodeStringForKey:@\"viewIdentifier\"];\n\tself->_sessionIdentifier = [aDecoder decodeIntegerForKey:@\"sessionIdentifier\"];\n\tself->_creationDate = [aDecoder decodeDoubleForKey:@\"entryCreationDate\"];\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder\n{\n\tNSParameterAssert(aCoder != nil);\n\n\t[aCoder encodeData:self.data forKey:@\"data\"];\n\t[aCoder encodeObject:self.uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\t[aCoder encodeObject:self.viewIdentifier forKey:@\"viewIdentifier\"];\n\t[aCoder encodeInteger:self.sessionIdentifier forKey:@\"sessionIdentifier\"];\n\t[aCoder encodeDouble:self.creationDate forKey:@\"entryCreationDate\"];\n}\n\n+ (BOOL)supportsSecureCoding\n{\n\treturn YES;\n}\n\n- (NSString *)description\n{\n\treturn [NSString stringWithFormat:@\"<TVCLogLineXPC %@ - %f>\", self.uniqueIdentifier, self.creationDate];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/HLSHistoricLogLineEntityMigration.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation HLSHistoricLogLineEntityMigration\n\n- (NSString *)newLogLineUniqueIdentifier\n{\n\tNSString *printIdentifier = [NSString stringWithUUID]; // Example: 68753A44-4D6F-1226-9C60-0050E4C00067\n\n\treturn [printIdentifier substringFromIndex:19]; // Example: 9C60-0050E4C00067\n}\n\n- (NSNumber *)newSessionIdentifier\n{\n\tstatic NSUInteger sessionIdentifier = 0;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsessionIdentifier = arc4random_uniform(999999);\n\t});\n\n\treturn @(sessionIdentifier);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/HLSHistoricLogProcessMain.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferencesUserDefaults.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, HLSHistoricLogUniqueIdentifierFetchType)\n{\n\tHLSHistoricLogReturnEntriesUniqueIdentifierTypeBefore,\n\tHLSHistoricLogReturnEntriesUniqueIdentifierTypeAfter\n};\n\n@interface HLSHistoricLogProcessMain ()\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@property (nonatomic, assign) BOOL isPerformingSave;\n@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;\n@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;\n@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;\n@property (nonatomic, copy) NSString *databasePath; // Path to database file\n@property (nonatomic, copy) NSString *databaseDirectory; // Path to database directory\n/* contextObjects is mutable. It should only be accessed in a queue. Use the global context's queue. */\n@property (nonatomic, strong) NSMutableDictionary<NSString *, HLSHistoricLogViewContext *> *contextObjects;\n@property (nonatomic, assign) NSUInteger maximumLineCount;\n@property (nonatomic, strong) dispatch_source_t saveTimer;\n@end\n\n@implementation HLSHistoricLogProcessMain\n\n- (instancetype)initWithConnection:(NSXPCConnection *)connection\n{\n\tNSParameterAssert(connection != nil);\n\n\tif ((self = [super init])) {\n\t\tself.serviceConnection = connection;\n\n\t\tLogToConsoleSetDefaultSubsystemToMainBundle(@\"General\");\n\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.contextObjects = [NSMutableDictionary dictionary];\n\n\tself.maximumLineCount = 100;\n}\n\n- (void)_resetDatabaseFilename\n{\n\tNSString *filename = [NSString stringWithFormat:@\"logControllerHistoricLog_%@.sqlite\", [NSString stringWithUUID]];\n\n\t[RZUserDefaults() setObject:filename forKey:@\"TVCLogControllerHistoricLogFileSavePath_v3\"];\n}\n\n- (NSString *)_databaseSaveFilename\n{\n\tNSString *filename = [RZUserDefaults() objectForKey:@\"TVCLogControllerHistoricLogFileSavePath_v3\"];\n\n\tif (filename == nil) {\n\t\t[self _resetDatabaseFilename];\n\t}\n\n\treturn filename;\n}\n\n- (void)_setDatabasePathInDirectory:(NSString *)databaseDirectory\n{\n\tNSParameterAssert(databaseDirectory != nil);\n\n\tself.databaseDirectory = databaseDirectory;\n\n\t[self _setDatabasePath];\n}\n\n- (void)_setDatabasePath\n{\n\tNSString *filename = [self _databaseSaveFilename];\n\n\tNSString *databasePath = [self.databaseDirectory stringByAppendingPathComponent:filename];\n\n\tself.databasePath = databasePath;\n}\n\n- (void)_resetDatabasePath\n{\n\t[self _resetDatabaseFilename];\n\n\t[self _setDatabasePath];\n}\n\n- (void)openDatabaseInDirectory:(NSString *)databaseDirectory withCompletionBlock:(void (NS_NOESCAPE ^ _Nullable)(BOOL))completionBlock\n{\n\tNSParameterAssert(databaseDirectory != nil);\n\n\t[self _setDatabasePathInDirectory:databaseDirectory];\n\n\tLogToConsoleInfo(\"Opening database at path: %{public}@\", self.databasePath.standardizedTildePath);\n\n\tBOOL success = [self _createBaseModel];\n\n\tif (completionBlock) {\n\t\tcompletionBlock(success);\n\t}\n\n\tif (success == NO) {\n\t\treturn;\n\t}\n\n\t[self _rescheduleSave];\n}\n\n- (void)setMaximumLineCount:(NSUInteger)maximumLineCount\n{\n\tNSParameterAssert(maximumLineCount > 0);\n\n\tif (self->_maximumLineCount != maximumLineCount) {\n\t\tself->_maximumLineCount = maximumLineCount;\n\t}\n}\n\n- (NSFetchRequest *)_fetchRequestForView:(NSString *)viewId\n\t\t\t\t\t\t\t  fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\t\t\t\t limitToDate:(nullable NSDate *)limitToDate\n\t\t\t\t\t\t\t  resultType:(NSFetchRequestResultType)resultType\n{\n\n\treturn [self _fetchRequestForView:viewId\n\t\t\t\t\t\t\tascending:YES\n\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\tlowestEntryIdentifier:0\n\t\t\t   highestEntryIdentifier:NSIntegerMax\n\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t   resultType:resultType];\n}\n\n- (NSFetchRequest *)_fetchRequestForView:(NSString *)viewId\n\t\t\t\t\t\t\t   ascending:(BOOL)ascending\n\t\t\t\t\t\t\t  fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\t\t\t\t limitToDate:(nullable NSDate *)limitToDate\n\t\t\t\t\t\t\t  resultType:(NSFetchRequestResultType)resultType\n{\n\treturn [self _fetchRequestForView:viewId\n\t\t\t\t\t\t\tascending:ascending\n\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\tlowestEntryIdentifier:0\n\t\t\t   highestEntryIdentifier:NSIntegerMax\n\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t   resultType:resultType];\n}\n\n- (NSFetchRequest *)_fetchRequestForView:(NSString *)viewId\n\t\t\t\t\t\t\t   ascending:(BOOL)ascending\n\t\t\t\t\t\t\t  fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\t   lowestEntryIdentifier:(NSUInteger)lowestEntryIdentifier\n\t\t\t\t  highestEntryIdentifier:(NSUInteger)highestEntryIdentifier\n\t\t\t\t\t\t\t limitToDate:(nullable NSDate *)limitToDate\n\t\t\t\t\t\t\t  resultType:(NSFetchRequestResultType)resultType\n{\n\tNSParameterAssert(viewId != nil);\n\n\tif (limitToDate == nil) {\n\t\tlimitToDate = [NSDate distantFuture];\n\t}\n\n\tNSDictionary *substitutionVariables = @{\n\t\t@\"view_id\" : viewId,\n\t\t@\"entry_id_lowest\" : @(lowestEntryIdentifier),\n\t\t@\"entry_id_highest\" : @(highestEntryIdentifier),\n\t\t@\"creation_date\" : @([limitToDate timeIntervalSince1970])\n\t};\n\n\tNSFetchRequest *fetchRequest =\n\t[self.managedObjectModel fetchRequestFromTemplateWithName:@\"GenericConditional\"\n\t\t\t\t\t\t\t\t\t\tsubstitutionVariables:substitutionVariables];\n\n\tif (fetchLimit > 0) {\n\t\tfetchRequest.fetchLimit = fetchLimit;\n\t}\n\n\tfetchRequest.includesPendingChanges = YES;\n\tfetchRequest.includesPropertyValues = YES;\n\tfetchRequest.returnsObjectsAsFaults = NO;\n\n\tfetchRequest.resultType = resultType;\n\n\tfetchRequest.sortDescriptors = @[[[NSSortDescriptor alloc] initWithKey:@\"entryCreationDate\" ascending:ascending]];\n\n\treturn fetchRequest;\n}\n\n- (void)forgetView:(NSString *)viewId\n{\n\tNSParameterAssert(viewId != nil);\n\n\tLogToConsoleDebug(\"Forgetting view: %{public}@\", viewId);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\t[self cancelResizeInViewContext:viewContext];\n\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:0\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\t[self _deleteDataInViewContext:viewContext withFetchRequest:fetchRequest performOnQueue:NO];\n\n\t\t[viewContext reset];\n\t}];\n\n\tNSManagedObjectContext *parentContext = self.managedObjectContext;\n\n\t[parentContext performBlockAndWait:^{\n\t\t[self.contextObjects removeObjectForKey:viewId];\n\t}];\n}\n\n- (void)resetDataForView:(NSString *)viewId\n{\n\tNSParameterAssert(viewId != nil);\n\n\tLogToConsoleDebug(\"Resetting the contents of view: %{public}@\", viewId);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\t[self cancelResizeInViewContext:viewContext];\n\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:0\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\t[self _deleteDataInViewContext:viewContext withFetchRequest:fetchRequest performOnQueue:NO];\n\n\t\t[viewContext reset];\n\t}];\n}\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t beforeUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\treturn [self fetchEntriesForView:viewId\n\t\t\t\twithUniqueIdentifier:uniqueId\n\t\t\t\t\t\t   fetchType:HLSHistoricLogReturnEntriesUniqueIdentifierTypeBefore\n\t\t\t\t\t\t  fetchLimit:fetchLimit\n\t\t\t\t\t\t limitToDate:limitToDate\n\t\t\t\t withCompletionBlock:completionBlock];\n}\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t  afterUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\treturn [self fetchEntriesForView:viewId\n\t\t\t\twithUniqueIdentifier:uniqueId\n\t\t\t\t\t\t   fetchType:HLSHistoricLogReturnEntriesUniqueIdentifierTypeAfter\n\t\t\t\t\t\t  fetchLimit:fetchLimit\n\t\t\t\t\t\t limitToDate:limitToDate\n\t\t\t\t withCompletionBlock:completionBlock];\n}\n\n/* This method is used to get line matching unique identifier and any that surround it. */\n- (void)fetchEntriesForView:(NSString *)viewId\n\t   withUniqueIdentifier:(NSString *)uniqueId\n\t\t   beforeFetchLimit:(NSUInteger)fetchLimitBefore\n\t\t\tafterFetchLimit:(NSUInteger)fetchLimitAfter\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\tNSParameterAssert(viewId != nil);\n\tNSParameterAssert(uniqueId != nil);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\tNSUInteger firstEntryId = [self _identifierInViewContext:viewContext\n\t\t\t\t\t\t\t\t\t\t\t forUniqueIdentifier:uniqueId\n\t\t\t\t\t\t\t\t\t\t\t\t  performOnQueue:NO];\n\n\t\tif (firstEntryId == NSNotFound) {\n\t\t\tcompletionBlock(@[]);\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSInteger lowestEntryId = (firstEntryId - fetchLimitBefore);\n\t\tNSInteger highestEntryId = (firstEntryId + fetchLimitAfter);\n\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tascending:YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:0\n\t\t\t\t\t\t\t\t\t\t\tlowestEntryIdentifier:lowestEntryId\n\t\t\t\t\t\t\t\t\t\t   highestEntryIdentifier:highestEntryId\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tLogToConsoleError(\"Error occurred fetching objects: %{public}@\",\n\t\t\t\t\t\t\t  fetchRequestError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\n\t\tLogToConsoleDebug(\"%{public}lu results fetched for view %{public}@\",\n\t\t\t\t\t\t  fetchedObjects.count, viewId);\n\n\t\t@autoreleasepool {\n\t\t\tNSArray<TVCLogLineXPC *> *fetchedEntries = [self _logLineXPCObjectsFromManagedObjects:fetchedObjects];\n\n\t\t\tcompletionBlock([fetchedEntries copy]);\n\t\t}\n\t}];\n}\n\n/* This method is used to get a list of lines between two unique identifiers. */\n- (void)fetchEntriesForView:(NSString *)viewId\n\t  afterUniqueIdentifier:(NSString *)uniqueIdAfter\n\t beforeUniqueIdentifier:(NSString *)uniqueIdBefore\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\tNSParameterAssert(viewId != nil);\n\tNSParameterAssert(uniqueIdAfter != nil);\n\tNSParameterAssert(uniqueIdBefore != nil);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\tNSUInteger firstEntryId = [self _identifierInViewContext:viewContext\n\t\t\t\t\t\t\t\t\t\t\t forUniqueIdentifier:uniqueIdAfter\n\t\t\t\t\t\t\t\t\t\t\t\t  performOnQueue:NO];\n\n\t\tNSUInteger secondEntryId = [self _identifierInViewContext:viewContext\n\t\t\t\t\t\t\t\t\t\t\t  forUniqueIdentifier:uniqueIdBefore\n\t\t\t\t\t\t\t\t\t\t\t\t   performOnQueue:NO];\n\n\t\tif (firstEntryId == NSNotFound ||\n\t\t\tsecondEntryId == NSNotFound)\n\t\t{\n\t\t\tcompletionBlock(@[]);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* We are getting the lines in-between these two lines which means we subtract self. */\n\t\tNSInteger lowestEntryId = (firstEntryId + 1);\n\t\tNSInteger highestEntryId = (secondEntryId - 1);\n\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tascending:YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t\t\tlowestEntryIdentifier:lowestEntryId\n\t\t\t\t\t\t\t\t\t\t   highestEntryIdentifier:highestEntryId\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tLogToConsoleError(\"Error occurred fetching objects: %{public}@\",\n\t\t\t\t\t\t\t  fetchRequestError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\n\t\tLogToConsoleDebug(\"%{public}lu results fetched for view %{public}@\",\n\t\t\t\t\t\t  fetchedObjects.count, viewId);\n\n\t\t@autoreleasepool {\n\t\t\tNSArray<TVCLogLineXPC *> *fetchedEntries = [self _logLineXPCObjectsFromManagedObjects:fetchedObjects];\n\n\t\t\tcompletionBlock([fetchedEntries copy]);\n\t\t}\n\t}];\n}\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t   withUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t  fetchType:(HLSHistoricLogUniqueIdentifierFetchType)fetchType\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\tNSParameterAssert(viewId != nil);\n\tNSParameterAssert(uniqueId != nil);\n\tNSParameterAssert(completionBlock != nil);\n\tNSParameterAssert(fetchLimit > 0);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\t/* Unique identifiers are strings. We find what is the the entry identifier\n\t\t for this string. The entry identifier is an integer. We can then subtract\n\t\t or add the fetch limit to that to get the entries we are interested in. */\n\t\tNSUInteger firstEntryId = [self _identifierInViewContext:viewContext\n\t\t\t\t\t\t\t\t\t\t\t forUniqueIdentifier:uniqueId\n\t\t\t\t\t\t\t\t\t\t\t\t  performOnQueue:NO];\n\n\t\tif (firstEntryId == NSNotFound) {\n\t\t\tcompletionBlock(@[]);\n\n\t\t\treturn;\n\t\t}\n\n\t\tNSInteger lowestEntryId = 0;\n\t\tNSInteger highestEntryId = 0;\n\n\t\tswitch (fetchType) {\n\t\t\tcase HLSHistoricLogReturnEntriesUniqueIdentifierTypeBefore:\n\t\t\t{\n\t\t\t\t/* 1 is subtracted so we can still return fetchLimit\n\t\t\t\t while accounting for the fact that firstEntryId is\n\t\t\t\t not a value we are interested in. */\n\t\t\t\tlowestEntryId = (firstEntryId - fetchLimit);\n\n\t\t\t\thighestEntryId = (firstEntryId - 1);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase HLSHistoricLogReturnEntriesUniqueIdentifierTypeAfter:\n\t\t\t{\n\t\t\t\tlowestEntryId = (firstEntryId + 1);\n\n\t\t\t\thighestEntryId = (firstEntryId + fetchLimit);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t{\n\t\t\t\tNSAssert(NO, @\"Bad 'fetchType' value\");\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tascending:YES\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t\t\tlowestEntryIdentifier:lowestEntryId\n\t\t\t\t\t\t\t\t\t\t   highestEntryIdentifier:highestEntryId\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tLogToConsoleError(\"Error occurred fetching objects: %{public}@\",\n\t\t\t\t\t\t\t  fetchRequestError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\n\t\tLogToConsoleDebug(\"%{public}lu results fetched for view %{public}@\",\n\t\t\t\t\t\t  fetchedObjects.count, viewId);\n\n\t\t@autoreleasepool {\n\t\t\tNSArray<TVCLogLineXPC *> *fetchedEntries = [self _logLineXPCObjectsFromManagedObjects:fetchedObjects];\n\n\t\t\tcompletionBlock([fetchedEntries copy]);\n\t\t}\n\t}];\n}\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t\t\t\t  ascending:(BOOL)ascending\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock\n{\n\tNSParameterAssert(viewId != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlockAndWait:^{\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tascending:ascending\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:fetchLimit\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:limitToDate\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tLogToConsoleError(\"Error occurred fetching objects: %{public}@\",\n\t\t\t\t\t\t\t  fetchRequestError.localizedDescription);\n\n\t\t\treturn;\n\t\t}\n\n\t\tLogToConsoleDebug(\"%{public}lu results fetched for view %{public}@\",\n\t\t\t\t\t\t  fetchedObjects.count, viewId);\n\n\t\t@autoreleasepool {\n\t\t\tNSArray<TVCLogLineXPC *> *fetchedEntries = [self _logLineXPCObjectsFromManagedObjects:fetchedObjects];\n\n\t\t\tcompletionBlock([fetchedEntries copy]);\n\t\t}\n\t}];\n}\n\n- (NSArray<TVCLogLineXPC *> *)_logLineXPCObjectsFromManagedObjects:(NSArray<NSManagedObject *> *)managedObjects\n{\n\tNSParameterAssert(managedObjects != nil);\n\n\tNSMutableArray<TVCLogLineXPC *> *xpcObjects = [NSMutableArray arrayWithCapacity:managedObjects.count];\n\n\tfor (NSManagedObject *managedObject in managedObjects) {\n\t\tTVCLogLineXPC *xpcObject = [[TVCLogLineXPC alloc] initWithManagedObject:managedObject];\n\n\t\t[xpcObjects addObject:xpcObject];\n\t}\n\n\treturn [xpcObjects copy];\n}\n\n- (void)writeLogLine:(TVCLogLineXPC *)logLine\n{\n\tNSParameterAssert(logLine != nil);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:logLine.viewIdentifier];\n\n\t[viewContext performBlockAndWait:^{\n\t\tNSEntityDescription *entity = [NSEntityDescription entityForName:@\"LogLine2\" inManagedObjectContext:viewContext];\n\n\t\tNSManagedObject *newEntry = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:viewContext];\n\n\t\tNSUInteger newestIdentifier = [self _incrementNewestIdentifierInViewContext:viewContext];\n\n\t\t[newEntry setValue:@(newestIdentifier) forKey:@\"entryIdentifier\"];\n\n\t\t[newEntry setValue:@([[NSDate date] timeIntervalSince1970]) forKey:@\"entryCreationDate\"];\n\n\t\t[newEntry setValue:logLine.viewIdentifier forKey:@\"logLineViewIdentifier\"];\n\n\t\t[newEntry setValue:logLine.data forKey:@\"logLineData\"];\n\n\t\t[newEntry setValue:logLine.uniqueIdentifier forKey:@\"logLineUniqueIdentifier\"];\n\n\t\t[newEntry setValue:@(logLine.sessionIdentifier) forKey:@\"sessionIdentifier\"];\n\n\t\t[self scheduleResizeInViewContext:viewContext];\n\t}];\n}\n\n- (BOOL)_createBaseModel\n{\n\treturn [self _createBaseModelWithRecursion:0];\n}\n\n- (BOOL)_createBaseModelWithRecursion:(NSUInteger)recursionDepth\n{\n\tNSURL *modelPath = [[NSBundle mainBundle] URLForResource:@\"HistoricLogFileStorageModel\" withExtension:@\"momd\"];\n\n\tNSManagedObjectModel *managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelPath];\n\n\tNSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];\n\n\tNSDictionary *pragmaOptions = @{\n\t\t@\"synchronous\" : @\"NORMAL\",\n\t\t@\"journal_mode\" : @\"WAL\"\n\t};\n\n\tNSDictionary *persistentStoreOptions = @{\n\t\tNSMigratePersistentStoresAutomaticallyOption : @(YES),\n\t\tNSInferMappingModelAutomaticallyOption : @(YES),\n\t\tNSSQLitePragmasOption : pragmaOptions\n\t};\n\n\tNSURL *persistentStorePath = [NSURL fileURLWithPath:self.databasePath];\n\n\tNSError *addPersistentStoreError = nil;\n\n\tNSPersistentStore *persistentStore =\n\t[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType\n\t\t\t\t\t\t\t\t\t\t\t configuration:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   URL:persistentStorePath\n\t\t\t\t\t\t\t\t\t\t\t\t   options:persistentStoreOptions\n\t\t\t\t\t\t\t\t\t\t\t\t\t error:&addPersistentStoreError];\n\n\tif (persistentStore == nil)\n\t{\n\t\tLogToConsoleError(\"Error Creating Persistent Store: %{public}@\",\n\t\t\t\t\t\t  addPersistentStoreError.localizedDescription);\n\n\t\tif (recursionDepth == 0) {\n\t\t\tLogToConsoleInfo(\"Attempting to create a new persistent store\");\n\n\t\t\t/* If we failed to load our store, we create a brand new one at a new path\n\t\t\t incase the old one is corrupted. */\n\t\t\t[self _resetDatabasePath]; // Destroy any data that may exist\n\n\t\t\treturn [self _createBaseModelWithRecursion:1];\n\t\t}\n\n\t\treturn NO;\n\t}\n\telse\n\t{\n\t\tNSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];\n\n\t\tmanagedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator;\n\n\t\tmanagedObjectContext.retainsRegisteredObjects = YES;\n\n\t\tmanagedObjectContext.undoManager = nil;\n\n\t\tself.managedObjectContext = managedObjectContext;\n\t\tself.managedObjectModel = managedObjectModel;\n\n\t\tself.persistentStoreCoordinator = persistentStoreCoordinator;\n\n\t\treturn YES;\n\t}\n}\n\n- (void)_rescheduleSave\n{\n\tif (self.saveTimer) {\n\t\tXRCancelScheduledBlock(self.saveTimer);\n\t}\n\n\tstatic NSTimeInterval saveTimerInterval = (60 * 2); // 2 minutes\n\n\tdispatch_source_t saveTimer =\n\tXRScheduleBlockOnQueue(dispatch_get_main_queue(), ^{\n\t\t[self saveDataWithCompletionBlock:nil];\n\t}, saveTimerInterval, YES);\n\n\tXRResumeScheduledBlock(saveTimer);\n\n\tself.saveTimer = saveTimer;\n}\n\n- (void)_quickSaveContext:(NSManagedObjectContext *)context\n{\n\tNSParameterAssert(context != nil);\n\n\tif ([context hasChanges] == NO) {\n\t\treturn;\n\t}\n\n\tNSError *saveError = nil;\n\n\tif ([context save:&saveError] == NO) {\n\t\tLogToConsoleError(\"Failed to perform save: %{public}@\",\n\t\t\t\t\t\t  saveError.localizedDescription);\n\t}\n\n\t[context reset];\n}\n\n- (void)saveDataWithCompletionBlock:(void (NS_NOESCAPE ^ _Nullable)(void))completionBlock\n{\n\tif (self.isPerformingSave == NO) {\n\t\tself.isPerformingSave = YES;\n\t} else {\n\t\treturn;\n\t}\n\n\tNSManagedObjectContext *context = self.managedObjectContext;\n\n\t[context performBlock:^{\n\t\tLogToConsoleDebug(\"Performing save\");\n\n\t\t[self _rescheduleSave];\n\n\t\t[self.contextObjects enumerateKeysAndObjectsUsingBlock:^(NSString *viewId, HLSHistoricLogViewContext *viewContext, BOOL *stop) {\n\t\t\t[context performBlockAndWait:^{\n\t\t\t\t[self _quickSaveContext:viewContext];\n\t\t\t}];\n\t\t}];\n\n\t\t[self _quickSaveContext:context];\n\n\t\tself.isPerformingSave = NO;\n\n\t\tif (completionBlock) {\n\t\t\tcompletionBlock();\n\t\t}\n\t}];\n}\n\n#pragma mark -\n#pragma mark View Resize Logic\n\n- (void)cancelResizeInViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(viewContext != nil);\n\n\tif (viewContext.hls_resizeTimer == nil) {\n\t\treturn;\n\t}\n\n\tXRCancelScheduledBlock(viewContext.hls_resizeTimer);\n\n\tviewContext.hls_resizeTimer = nil;\n}\n\n- (void)scheduleResizeInViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(viewContext != nil);\n\n\tif (viewContext.hls_resizeTimer != nil) {\n\t\treturn;\n\t}\n\n\tif (viewContext.hls_totalLineCount < self.maximumLineCount) {\n\t\treturn;\n\t}\n\n\tNSString *viewId = viewContext.hls_viewId;\n\n\tNSTimeInterval resizeTimerInterval = (NSTimeInterval)arc4random_uniform(60 * 30); // Somewhere in 30 minutes\n\n\tdispatch_source_t resizeTimer =\n\tXRScheduleBlockOnQueue(dispatch_get_main_queue(), ^{\n\t\t[self resizeView:viewId];\n\t}, resizeTimerInterval, NO);\n\n\tXRResumeScheduledBlock(resizeTimer);\n\n\tviewContext.hls_resizeTimer = resizeTimer;\n\n\tLogToConsoleDebug(\"Scheduled to resize %{public}@ in %{public}f seconds\",\n\t\t\t\t\t  viewId, resizeTimerInterval);\n}\n\n- (void)resizeView:(NSString *)viewId\n{\n\tNSParameterAssert(viewId != nil);\n\n\tHLSHistoricLogViewContext *viewContext = [self contextForView:viewId];\n\n\t[viewContext performBlock:^{\n\t\t[self _resizeViewContext:viewContext];\n\t}];\n}\n\n- (void)_resizeViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(viewContext != nil);\n\n\tLogToConsoleDebug(\"Resizing view %{public}@\", viewContext.hls_viewId);\n\n\tviewContext.hls_resizeTimer = nil;\n\n\tNSString *viewId = viewContext.hls_viewId;\n\n\tNSInteger lowestIdentifier = (viewContext.hls_newestIdentifier - self.maximumLineCount);\n\n\tNSDictionary *substitutionVariables = @{\n\t\t@\"view_id\" : viewId,\n\t\t@\"entry_id_lowest\" : @(lowestIdentifier)\n\t};\n\n\tNSFetchRequest *fetchRequest =\n\t[self.managedObjectModel fetchRequestFromTemplateWithName:@\"Truncate\"\n\t\t\t\t\t\t\t\t\t\tsubstitutionVariables:substitutionVariables];\n\n\tfetchRequest.includesPendingChanges = YES;\n\tfetchRequest.includesPropertyValues = YES;\n\tfetchRequest.returnsObjectsAsFaults = NO;\n\n\tNSUInteger rowsDeleted =\n\t[self _deleteDataInViewContext:viewContext withFetchRequest:fetchRequest performOnQueue:NO];\n\n\tviewContext.hls_totalLineCount -= rowsDeleted;\n}\n\n#pragma mark -\n#pragma mark Batch Delete Logic\n\n- (NSUInteger)_deleteDataInViewContext:(HLSHistoricLogViewContext *)viewContext withFetchRequest:(NSFetchRequest *)fetchRequest performOnQueue:(BOOL)performOnQueue\n{\n\tNSParameterAssert(viewContext != nil);\n\tNSParameterAssert(fetchRequest != nil);\n\n\t__block NSUInteger rowsDeleted = 0;\n\n\tdispatch_block_t blockToPerform = ^{\n\t\t/* Batch delete is not used at the time of this commit because we want the value\n\t\t of a specific property from each managed object before deleting, which old school\n\t\t delete allows us to obtain at the same time we perform delete. */\n//\t\tif (XRRunningOnOSXElCapitanOrLater()) {\n//\t\t\trowsDeleted = [self __deleteDataForFetchRequestUsingBatch:fetchRequest inViewContext:viewContext];\n//\t\t} else {\n\t\t\trowsDeleted = [self __deleteDataForFetchRequestUsingEnumeration:fetchRequest inViewContext:viewContext];\n//\t\t}\n\t};\n\n\tif (performOnQueue) {\n\t\t[viewContext performBlockAndWait:blockToPerform];\n\t} else {\n\t\tblockToPerform();\n\t}\n\n\tLogToConsoleDebug(\"Deleted %{public}lu rows in %{public}@\", rowsDeleted, viewContext.hls_viewId);\n\n\treturn rowsDeleted;\n}\n\n/*\n- (NSUInteger)__deleteDataForFetchRequestUsingBatch:(NSFetchRequest *)fetchRequest inViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(fetchRequest != nil);\n\tNSParameterAssert(viewContext != nil);\n\n\tNSBatchDeleteRequest *batchDeleteRequest = [[NSBatchDeleteRequest alloc] initWithFetchRequest:fetchRequest];\n\n\tbatchDeleteRequest.resultType = NSBatchDeleteResultTypeObjectIDs;\n\n\tNSError *batchDeleteError = nil;\n\n\tNSBatchDeleteResult *batchDeleteResult =\n\t[viewContext executeRequest:batchDeleteRequest error:&batchDeleteError];\n\n\tif (batchDeleteResult == nil) {\n\t\tLogToConsoleError(\"Failed to perform batch delete: %{public}@\",\n\t\t\t\t\t\t  batchDeleteError.localizedDescription);\n\n\t\treturn 0;\n\t}\n\n\tNSArray<NSManagedObjectID *> *rowsDeleted = batchDeleteResult.result;\n\n\tNSUInteger rowsDeletedCount = rowsDeleted.count;\n\n\tif (rowsDeletedCount > 0) {\n\t\t[NSManagedObjectContext mergeChangesFromRemoteContextSave:@{NSDeletedObjectsKey : rowsDeleted} intoContexts:@[viewContext]];\n\n\t\t[self _quickSaveContext:viewContext];\n\t}\n\n\treturn rowsDeletedCount;\n}\n*/\n\n- (NSUInteger)__deleteDataForFetchRequestUsingEnumeration:(NSFetchRequest *)fetchRequest inViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(fetchRequest != nil);\n\tNSParameterAssert(viewContext != nil);\n\n\tNSError *fetchRequestError = nil;\n\n\tNSArray *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\tif (fetchedObjects == nil) {\n\t\tLogToConsoleError(\"Error occurred fetching objects: %{public}@\",\n\t\t\t\t\t\t  fetchRequestError.localizedDescription);\n\n\t\treturn 0;\n\t}\n\n\tif (fetchedObjects.count == 0) {\n\t\treturn 0;\n\t}\n\n\tNSMutableArray<NSString *> *uniqueIdentifiers = [NSMutableArray arrayWithCapacity:fetchedObjects.count];\n\n\tfor (NSManagedObject *object in fetchedObjects) {\n\t\t/* Record unique identifier */\n\t\tNSString *uniqueIdentifier = [object valueForKey:@\"logLineUniqueIdentifier\"];\n\n\t\tif (uniqueIdentifier) {\n\t\t\t[uniqueIdentifiers addObject:uniqueIdentifier];\n\t\t}\n\n\t\t/* Delete object */\n\t\t[viewContext deleteObject:object];\n\t}\n\n\t[self _quickSaveContext:viewContext];\n\n\t[self __notifyClientOfDeletedUniqueIdentifiers:[uniqueIdentifiers copy]\n\t\t\t\t\t\t\t\t\t inViewContext:viewContext];\n\n\treturn fetchedObjects.count;\n}\n\n/* Notify XPC client of intent to delete these unique identifiers. */\n/* Deletes can happen based on a timer, without the client asking for it,\n which means we need a way to inform it of the delete. */\n- (void)__notifyClientOfDeletedUniqueIdentifiers:(NSArray<NSString *> *)uniqueIdentifiers inViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(uniqueIdentifiers != nil);\n\tNSParameterAssert(viewContext != nil);\n\n\t[[self remoteObjectProxy] willDeleteUniqueIdentifiers:uniqueIdentifiers\n\t\t\t\t\t\t\t\t\t\t\t\t   inView:viewContext.hls_viewId];\n}\n\n#pragma mark -\n#pragma mark Identifier Cache Management\n\n- (HLSHistoricLogViewContext *)contextForView:(NSString *)viewId\n{\n\tNSParameterAssert(viewId != nil);\n\n\t@synchronized(self.contextObjects) {\n\t\t/* Returned cached object or create new */\n\t\tHLSHistoricLogViewContext *viewContext = self.contextObjects[viewId];\n\n\t\tif (viewContext != nil) {\n\t\t\treturn viewContext;\n\t\t}\n\n\t\tNSManagedObjectContext *parentObjectContext = self.managedObjectContext;\n\n\t\tviewContext = [[HLSHistoricLogViewContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];\n\n\t\t/* Properties specific to NSManagedObjectContext */\n\t\tviewContext.parentContext = parentObjectContext;\n\n\t\tviewContext.retainsRegisteredObjects = YES;\n\n\t\tviewContext.undoManager = nil;\n\n\t\t/* Properties specific to HLSHistoricLogViewContext */\n\t\tviewContext.hls_viewId = viewId;\n\n\t\tviewContext.hls_totalLineCount = [self _lineCountInViewContextFromDatabase:viewContext performOnQueue:YES];\n\n\t\tviewContext.hls_newestIdentifier = [self _newestIdentifierInViewContextFromDatabase:viewContext performOnQueue:YES];\n\n\t\t/* Log information for debugging */\n\t\tLogToConsoleDebug(\"Context created for %{public}@ - Line count: %{public}lu, Newest identifier: %{public}lu\",\n\t\t\t\t\t\t  viewContext.hls_viewId,\n\t\t\t\t\t\t  viewContext.hls_totalLineCount,\n\t\t\t\t\t\t  viewContext.hls_newestIdentifier);\n\n\t\t/* Cache new object and return it */\n\t\t[parentObjectContext performBlockAndWait:^{\n\t\t\tself.contextObjects[viewId] = viewContext;\n\t\t}];\n\n\t\treturn viewContext;\n\t}\n}\n\n- (NSUInteger)_incrementNewestIdentifierInViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(viewContext != nil);\n\n\tviewContext.hls_totalLineCount += 1;\n\n\tviewContext.hls_newestIdentifier += 1;\n\n\treturn viewContext.hls_newestIdentifier;\n}\n\n- (NSUInteger)_newestIdentifierInViewContext:(HLSHistoricLogViewContext *)viewContext\n{\n\tNSParameterAssert(viewContext != nil);\n\n\treturn viewContext.hls_newestIdentifier;\n}\n\n- (NSUInteger)_newestIdentifierInViewContextFromDatabase:(HLSHistoricLogViewContext *)viewContext performOnQueue:(BOOL)performOnQueue\n{\n\tNSParameterAssert(viewContext != nil);\n\n\t__block NSUInteger newestIdentifier = 0;\n\n\tdispatch_block_t blockToPerform = ^{\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tascending:NO\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:1\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSManagedObjectResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tNSAssert1(NO, @\"Error occurred fetching objects: %@\",\n\t\t\t\t\t  fetchRequestError.localizedDescription);\n\t\t}\n\n\t\tNSManagedObject *fetchedObject = fetchedObjects.firstObject;\n\n\t\tif (fetchedObject == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSNumber *newestIdentifierObject = [fetchedObject valueForKey:@\"entryIdentifier\"];\n\n\t\tnewestIdentifier = newestIdentifierObject.unsignedIntegerValue;\n\t};\n\n\tif (performOnQueue) {\n\t\t[viewContext performBlockAndWait:blockToPerform];\n\t} else {\n\t\tblockToPerform();\n\t}\n\n\treturn newestIdentifier;\n}\n\n- (NSUInteger)_lineCountInViewContextFromDatabase:(HLSHistoricLogViewContext *)viewContext performOnQueue:(BOOL)performOnQueue\n{\n\tNSParameterAssert(viewContext != nil);\n\n\t__block NSUInteger lineCount = 0;\n\n\tdispatch_block_t blockToPerform = ^{\n\t\tNSFetchRequest *fetchRequest = [self _fetchRequestForView:viewContext.hls_viewId\n\t\t\t\t\t\t\t\t\t\t\t\t\t   fetchLimit:0\n\t\t\t\t\t\t\t\t\t\t\t\t\t  limitToDate:nil\n\t\t\t\t\t\t\t\t\t\t\t\t\t   resultType:NSCountResultType];\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tlineCount = [viewContext countForFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (lineCount == NSNotFound) {\n\t\t\tNSAssert1(NO, @\"Error occurred fetching objects: %@\",\n\t\t\t\t\t  fetchRequestError.localizedDescription);\n\t\t}\n\t};\n\n\tif (performOnQueue) {\n\t\t[viewContext performBlockAndWait:blockToPerform];\n\t} else {\n\t\tblockToPerform();\n\t}\n\n\treturn lineCount;\n}\n\n/* Given a logLineUniqueIdentifier, figure out which entryIdentifier is associated with it. */\n- (NSUInteger)_identifierInViewContext:(HLSHistoricLogViewContext *)viewContext forUniqueIdentifier:(NSString *)uniqueIdentifier performOnQueue:(BOOL)performOnQueue\n{\n\tNSUInteger identifier = [self _identifierInViewContextFromDatabase:viewContext\n\t\t\t\t\t\t\t\t\t\t\t\t   forUniqueIdentifier:uniqueIdentifier\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tperformOnQueue:performOnQueue];\n\n\treturn identifier;\n}\n\n- (NSUInteger)_identifierInViewContextFromDatabase:(HLSHistoricLogViewContext *)viewContext forUniqueIdentifier:(NSString *)uniqueIdentifier performOnQueue:(BOOL)performOnQueue\n{\n\tNSParameterAssert(viewContext != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\n\t__block NSUInteger identifier = NSNotFound;\n\n\tdispatch_block_t blockToPerform = ^{\n\t\tNSString *viewId = viewContext.hls_viewId;\n\n\t\tNSDictionary *substitutionVariables = @{\n\t\t\t@\"view_id\" : viewId,\n\t\t\t@\"unique_id\" : uniqueIdentifier\n\t\t};\n\n\t\tNSFetchRequest *fetchRequest =\n\t\t[self.managedObjectModel fetchRequestFromTemplateWithName:@\"UniqueIdToEntryId\"\n\t\t\t\t\t\t\t\t\t\t\tsubstitutionVariables:substitutionVariables];\n\n\t\tfetchRequest.includesPendingChanges = YES;\n\t\tfetchRequest.includesPropertyValues = YES;\n\t\tfetchRequest.returnsObjectsAsFaults = NO;\n\n\t\tNSError *fetchRequestError = nil;\n\n\t\tNSArray<NSManagedObject *> *fetchedObjects = [viewContext executeFetchRequest:fetchRequest error:&fetchRequestError];\n\n\t\tif (fetchedObjects == nil) {\n\t\t\tNSAssert1(NO, @\"Error occurred fetching objects: %@\",\n\t\t\t\t\t  fetchRequestError.localizedDescription);\n\t\t}\n\n\t\tNSManagedObject *fetchedObject = fetchedObjects.firstObject;\n\n\t\tif (fetchedObject == nil) {\n\t\t\treturn;\n\t\t}\n\n\t\tNSNumber *identifierObject = [fetchedObject valueForKey:@\"entryIdentifier\"];\n\n\t\tidentifier = identifierObject.unsignedIntegerValue;\n\t};\n\n\tif (performOnQueue) {\n\t\t[viewContext performBlockAndWait:blockToPerform];\n\t} else {\n\t\tblockToPerform();\n\t}\n\n\treturn identifier;\n}\n\n#pragma mark -\n#pragma mark XPC Connection\n\n- (id <HLSHistoricLogClientProtocol>)remoteObjectProxy\n{\n\treturn self.serviceConnection.remoteObjectProxy;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/HLSHistoricLogViewContext.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation HLSHistoricLogViewContext\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/HSLHistoricLogProcessDelegate.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation HSLHistoricLogProcessDelegate\n\n- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection\n{\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HLSHistoricLogServerProtocol)];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:ascending:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:YES];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:withUniqueIdentifier:beforeFetchLimit:afterFetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:YES];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:beforeUniqueIdentifier:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:YES];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:afterUniqueIdentifier:fetchLimit:limitToDate:withCompletionBlock:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:YES];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [TVCLogLineXPC class], nil]\n\t\t\t\t\t  forSelector:@selector(fetchEntriesForView:afterUniqueIdentifier:beforeUniqueIdentifier:fetchLimit:withCompletionBlock:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:YES];\n\n\tnewConnection.exportedInterface = exportedInterface;\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(HLSHistoricLogClientProtocol)];\n\n\tnewConnection.remoteObjectInterface = remoteObjectInterface;\n\n\tHLSHistoricLogProcessMain *exportedObject = [[HLSHistoricLogProcessMain alloc] initWithConnection:newConnection];\n\n\tnewConnection.exportedObject = exportedObject;\n\n\t[newConnection resume];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HLSHistoricLogLineEntityMigrationPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface HLSHistoricLogLineEntityMigration : NSEntityMigrationPolicy\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HLSHistoricLogProcessMainPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface HLSHistoricLogProcessMain : NSObject <HLSHistoricLogServerProtocol>\n- (instancetype)initWithConnection:(NSXPCConnection *)connection;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HLSHistoricLogProtocol.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* *** XPC PROTOCOL HEADERS ARE PRIVATE *** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class TVCLogLineXPC;\n\n#pragma mark -\n#pragma mark Server Protocol\n\n@protocol HLSHistoricLogServerProtocol\n- (void)openDatabaseInDirectory:(NSString *)databaseDirectory withCompletionBlock:(void (NS_NOESCAPE ^ _Nullable)(BOOL))completionBlock;\n\n- (void)writeLogLine:(TVCLogLineXPC *)logLine;\n\n- (void)saveDataWithCompletionBlock:(void (NS_NOESCAPE ^ _Nullable)(void))completionBlock;\n\n- (void)forgetView:(NSString *)viewId;\n- (void)resetDataForView:(NSString *)viewId;\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t\t\t\t  ascending:(BOOL)ascending\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit // optional (0 == no limit)\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock;\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t   withUniqueIdentifier:(NSString *)uniqueId\n\t\t   beforeFetchLimit:(NSUInteger)fetchLimitBefore // optional (0 == only uniqueId)\n\t\t\tafterFetchLimit:(NSUInteger)fetchLimitAfter // optional (0 == only uniqueId)\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock;\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t beforeUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit // required (> 0)\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock;\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t  afterUniqueIdentifier:(NSString *)uniqueId\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit // required (> 0)\n\t\t\t\tlimitToDate:(nullable NSDate *)limitToDate\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock;\n\n- (void)fetchEntriesForView:(NSString *)viewId\n\t  afterUniqueIdentifier:(NSString *)uniqueIdAfter\n\t beforeUniqueIdentifier:(NSString *)uniqueIdBefore\n\t\t\t\t fetchLimit:(NSUInteger)fetchLimit // optional (0 == no limit)\n\t\twithCompletionBlock:(void (NS_NOESCAPE ^)(NSArray<TVCLogLineXPC *> *entries))completionBlock;\n\n- (void)setMaximumLineCount:(NSUInteger)maximumLineCount;\n@end\n\n#pragma mark -\n#pragma mark Client Protocol\n\n@protocol HLSHistoricLogClientProtocol\n- (void)willDeleteUniqueIdentifiers:(NSArray<NSString *> *)uniqueIdentifiers\n\t\t\t\t\t\t\t inView:(NSString *)viewId;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HLSHistoricLogViewContextPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface HLSHistoricLogViewContext : NSManagedObjectContext\n@property (nonatomic, copy) NSString *hls_viewId;\n@property (nonatomic, assign) NSUInteger hls_totalLineCount;\n@property (nonatomic, assign) NSUInteger hls_newestIdentifier;\n@property (nonatomic, strong, nullable) dispatch_source_t hls_resizeTimer;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HSLHistoricLogPCHPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CocoaExtensions/CocoaExtensions.h>\n\n#import <CoreData/CoreData.h>\n\n#import \"StaticDefinitions.h\"\n#import \"TVCLogLineXPCPrivate.h\"\n\n#import \"HLSHistoricLogProtocol.h\"\n#import \"HLSHistoricLogLineEntityMigrationPrivate.h\"\n#import \"HLSHistoricLogViewContextPrivate.h\"\n#import \"HLSHistoricLogProcessMainPrivate.h\"\n#import \"HSLHistoricLogProcessDelegatePrivate.h\"\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/Headers/Private/HSLHistoricLogProcessDelegatePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface HSLHistoricLogProcessDelegate : NSObject <NSXPCListenerDelegate>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Classes/main.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2016 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wnullability-inferred-on-nested-type\"\n\nint main(int argc, const char *argv[])\n{\n\tHSLHistoricLogProcessDelegate *delegate = [HSLHistoricLogProcessDelegate new];\n\n\tNSXPCListener *listener = [NSXPCListener serviceListener];\n\n\tlistener.delegate = delegate;\n\n\t[listener resume];\n\n\treturn 0;\n}\n\n#pragma clang diagnostic pop\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Configurations/Sandbox/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>8482Q6EPL6.com.codeux.apps.textual</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Historic Log File Manager.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C469E4F20EC5E5300094EA4 /* HSLHistoricLogProcessDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E4220EC5E5300094EA4 /* HSLHistoricLogProcessDelegate.m */; };\n\t\t4C469E5020EC5E5300094EA4 /* HLSHistoricLogViewContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E4320EC5E5300094EA4 /* HLSHistoricLogViewContext.m */; };\n\t\t4C469E5120EC5E5300094EA4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E4420EC5E5300094EA4 /* main.m */; };\n\t\t4C469E5220EC5E5300094EA4 /* HLSHistoricLogProcessMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E4D20EC5E5300094EA4 /* HLSHistoricLogProcessMain.m */; };\n\t\t4C469E5320EC5E5300094EA4 /* HLSHistoricLogLineEntityMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E4E20EC5E5300094EA4 /* HLSHistoricLogLineEntityMigration.m */; };\n\t\t4C469E9620EC5ED500094EA4 /* TVCLogLineXPC.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E9520EC5ED500094EA4 /* TVCLogLineXPC.m */; };\n\t\t4C469E9C20EC5F7700094EA4 /* HistoricLogFileStorageModel.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E9820EC5F7700094EA4 /* HistoricLogFileStorageModel.xcmappingmodel */; };\n\t\t4C469E9D20EC5F7700094EA4 /* HistoricLogFileStorageModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 4C469E9920EC5F7700094EA4 /* HistoricLogFileStorageModel.xcdatamodeld */; };\n\t\t4C58C6E21E15428300934680 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C58C6E11E15428300934680 /* CoreData.framework */; };\n\t\t4CBDFBEA2C3ED3920003B272 /* TPCPreferencesUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CBDFBE72C3ED3920003B272 /* TPCPreferencesUserDefaults.m */; };\n\t\t4CE1461E20EC10F4000E01C9 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE145E420EC0F5C000E01C9 /* CocoaExtensions.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C442C881E13B3D200B187F4 /* Scrollback History Manager.xpc */ = {isa = PBXFileReference; explicitFileType = \"wrapper.xpc-service\"; includeInIndex = 0; path = \"Scrollback History Manager.xpc\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C469E4220EC5E5300094EA4 /* HSLHistoricLogProcessDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSLHistoricLogProcessDelegate.m; sourceTree = \"<group>\"; };\n\t\t4C469E4320EC5E5300094EA4 /* HLSHistoricLogViewContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLSHistoricLogViewContext.m; sourceTree = \"<group>\"; };\n\t\t4C469E4420EC5E5300094EA4 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t4C469E4720EC5E5300094EA4 /* HLSHistoricLogViewContextPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLSHistoricLogViewContextPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E4820EC5E5300094EA4 /* HSLHistoricLogProcessDelegatePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSLHistoricLogProcessDelegatePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E4920EC5E5300094EA4 /* HLSHistoricLogProcessMainPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLSHistoricLogProcessMainPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E4A20EC5E5300094EA4 /* HLSHistoricLogLineEntityMigrationPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HLSHistoricLogLineEntityMigrationPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E4B20EC5E5300094EA4 /* HSLHistoricLogPCHPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSLHistoricLogPCHPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E4D20EC5E5300094EA4 /* HLSHistoricLogProcessMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLSHistoricLogProcessMain.m; sourceTree = \"<group>\"; };\n\t\t4C469E4E20EC5E5300094EA4 /* HLSHistoricLogLineEntityMigration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HLSHistoricLogLineEntityMigration.m; sourceTree = \"<group>\"; };\n\t\t4C469E7520EC5E9C00094EA4 /* TVCLogLineXPCPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TVCLogLineXPCPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469E9520EC5ED500094EA4 /* TVCLogLineXPC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TVCLogLineXPC.m; sourceTree = \"<group>\"; };\n\t\t4C469E9820EC5F7700094EA4 /* HistoricLogFileStorageModel.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = HistoricLogFileStorageModel.xcmappingmodel; sourceTree = \"<group>\"; };\n\t\t4C469E9A20EC5F7700094EA4 /* LogControllerStorageModel (model 2).xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = \"LogControllerStorageModel (model 2).xcdatamodel\"; sourceTree = \"<group>\"; };\n\t\t4C469E9B20EC5F7700094EA4 /* LogControllerStorageModel (model 3).xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = \"LogControllerStorageModel (model 3).xcdatamodel\"; sourceTree = \"<group>\"; };\n\t\t4C469E9F20EC5FA000094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A01120EC64FA00094EA4 /* HLSHistoricLogProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HLSHistoricLogProtocol.h; path = Classes/Headers/Private/HLSHistoricLogProtocol.h; sourceTree = SOURCE_ROOT; };\n\t\t4C58C6E11E15428300934680 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };\n\t\t4CBDFBE42C3ED32A0003B272 /* TPCPreferencesUserDefaultsPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesUserDefaultsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4CBDFBE72C3ED3920003B272 /* TPCPreferencesUserDefaults.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesUserDefaults.m; sourceTree = \"<group>\"; };\n\t\t4CE145E420EC0F5C000E01C9 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CE145EB20EC0F7F000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145EE20EC0F7F000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145F020EC0F7F000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145FE20EC0F7F000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145FF20EC0F7F000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1460220EC0F7F000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1460320EC0F7F000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1460520EC0F7F000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1461320EC0F7F000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1461620EC0F7F000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1461820EC0F7F000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1461C20EC0FAF000E01C9 /* Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4C442C851E13B3D200B187F4 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C58C6E21E15428300934680 /* CoreData.framework in Frameworks */,\n\t\t\t\t4CE1461E20EC10F4000E01C9 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4C442C7F1E13B3D200B187F4 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E4120EC5E5300094EA4 /* Classes */,\n\t\t\t\t4C442CA81E13B42900B187F4 /* Resources */,\n\t\t\t\t4C442CBE1E13B77200B187F4 /* Frameworks */,\n\t\t\t\t4C442C891E13B3D200B187F4 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C442C891E13B3D200B187F4 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C442C881E13B3D200B187F4 /* Scrollback History Manager.xpc */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C442CA81E13B42900B187F4 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C761BE21E1565D800A505B7 /* Build Settings */,\n\t\t\t\t4C469E9720EC5F7700094EA4 /* Data Models */,\n\t\t\t\t4C469E9E20EC5FA000094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C442CAF1E13B55900B187F4 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145E720EC0F7F000E01C9 /* Build */,\n\t\t\t\t4CE1461920EC0F7F000E01C9 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C442CBE1E13B77200B187F4 /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C58C6D61E15372B00934680 /* External Frameworks */,\n\t\t\t\t4C560E291E1558BA00D3ACB9 /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E4120EC5E5300094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E5420EC5E9C00094EA4 /* Shared */,\n\t\t\t\t4C469E4520EC5E5300094EA4 /* Headers */,\n\t\t\t\t4C469E4E20EC5E5300094EA4 /* HLSHistoricLogLineEntityMigration.m */,\n\t\t\t\t4C469E4D20EC5E5300094EA4 /* HLSHistoricLogProcessMain.m */,\n\t\t\t\t4C469E4320EC5E5300094EA4 /* HLSHistoricLogViewContext.m */,\n\t\t\t\t4C469E4220EC5E5300094EA4 /* HSLHistoricLogProcessDelegate.m */,\n\t\t\t\t4C469E4420EC5E5300094EA4 /* main.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E4520EC5E5300094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E4620EC5E5300094EA4 /* Private */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E4620EC5E5300094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E4A20EC5E5300094EA4 /* HLSHistoricLogLineEntityMigrationPrivate.h */,\n\t\t\t\t4C469E4920EC5E5300094EA4 /* HLSHistoricLogProcessMainPrivate.h */,\n\t\t\t\t4C469E4720EC5E5300094EA4 /* HLSHistoricLogViewContextPrivate.h */,\n\t\t\t\t4C469E4B20EC5E5300094EA4 /* HSLHistoricLogPCHPrivate.h */,\n\t\t\t\t4C469E4820EC5E5300094EA4 /* HSLHistoricLogProcessDelegatePrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E5420EC5E9C00094EA4 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBDFBE82C3ED3920003B272 /* Preferences */,\n\t\t\t\t4C469E6320EC5E9C00094EA4 /* Headers */,\n\t\t\t\t4C469E9320EC5ED500094EA4 /* Views */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tpath = ../../Sources/Shared;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C469E6320EC5E9C00094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A00E20EC64FA00094EA4 /* Services */,\n\t\t\t\t4C469E7120EC5E9C00094EA4 /* Private */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E7120EC5E9C00094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBDFBE42C3ED32A0003B272 /* TPCPreferencesUserDefaultsPrivate.h */,\n\t\t\t\t4C469E7520EC5E9C00094EA4 /* TVCLogLineXPCPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E9320EC5ED500094EA4 /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E9420EC5ED500094EA4 /* Channel View */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E9420EC5ED500094EA4 /* Channel View */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E9520EC5ED500094EA4 /* TVCLogLineXPC.m */,\n\t\t\t);\n\t\t\tpath = \"Channel View\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E9720EC5F7700094EA4 /* Data Models */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E9820EC5F7700094EA4 /* HistoricLogFileStorageModel.xcmappingmodel */,\n\t\t\t\t4C469E9920EC5F7700094EA4 /* HistoricLogFileStorageModel.xcdatamodeld */,\n\t\t\t);\n\t\t\tpath = \"Data Models\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469E9E20EC5FA000094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E9F20EC5FA000094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A00E20EC64FA00094EA4 /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A01120EC64FA00094EA4 /* HLSHistoricLogProtocol.h */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C560E291E1558BA00D3ACB9 /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C58C6E11E15428300934680 /* CoreData.framework */,\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C58C6D61E15372B00934680 /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145E420EC0F5C000E01C9 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C761BE21E1565D800A505B7 /* Build Settings */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C442CAF1E13B55900B187F4 /* Configurations */,\n\t\t\t);\n\t\t\tname = \"Build Settings\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CBDFBE82C3ED3920003B272 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CBDFBE72C3ED3920003B272 /* TPCPreferencesUserDefaults.m */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145E720EC0F7F000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145FB20EC0F7F000E01C9 /* Common */,\n\t\t\t\t4CE1461020EC0F7F000E01C9 /* Debug */,\n\t\t\t\t4CE145E820EC0F7F000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145E820EC0F7F000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145F020EC0F7F000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE145EB20EC0F7F000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE145EE20EC0F7F000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145FB20EC0F7F000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1460520EC0F7F000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE1460220EC0F7F000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE145FF20EC0F7F000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE145FE20EC0F7F000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1460320EC0F7F000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1461020EC0F7F000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1461820EC0F7F000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1461320EC0F7F000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1461620EC0F7F000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1461920EC0F7F000E01C9 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1461C20EC0FAF000E01C9 /* Release.entitlements */,\n\t\t\t);\n\t\t\tname = Sandbox;\n\t\t\tpath = Configurations/Sandbox;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t4C442C871E13B3D200B187F4 /* Historic Log File Manager */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4C442C941E13B3D200B187F4 /* Build configuration list for PBXNativeTarget \"Historic Log File Manager\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4C442C861E13B3D200B187F4 /* Resources */,\n\t\t\t\t4C442C851E13B3D200B187F4 /* Frameworks */,\n\t\t\t\t4C442C841E13B3D200B187F4 /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Historic Log File Manager\";\n\t\t\tproductName = \"Historic Log File Manager\";\n\t\t\tproductReference = 4C442C881E13B3D200B187F4 /* Scrollback History Manager.xpc */;\n\t\t\tproductType = \"com.apple.product-type.xpc-service\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4C442C801E13B3D200B187F4 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tORGANIZATIONNAME = \"Codeux Software, LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4C442C871E13B3D200B187F4 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tDevelopmentTeam = 8482Q6EPL6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4C442C831E13B3D200B187F4 /* Build configuration list for PBXProject \"Historic Log File Manager\" */;\n\t\t\tcompatibilityVersion = \"Xcode 3.2\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4C442C7F1E13B3D200B187F4;\n\t\t\tproductRefGroup = 4C442C891E13B3D200B187F4 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4C442C871E13B3D200B187F4 /* Historic Log File Manager */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4C442C861E13B3D200B187F4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4C442C841E13B3D200B187F4 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469E5020EC5E5300094EA4 /* HLSHistoricLogViewContext.m in Sources */,\n\t\t\t\t4C469E5320EC5E5300094EA4 /* HLSHistoricLogLineEntityMigration.m in Sources */,\n\t\t\t\t4C469E5220EC5E5300094EA4 /* HLSHistoricLogProcessMain.m in Sources */,\n\t\t\t\t4C469E9620EC5ED500094EA4 /* TVCLogLineXPC.m in Sources */,\n\t\t\t\t4C469E4F20EC5E5300094EA4 /* HSLHistoricLogProcessDelegate.m in Sources */,\n\t\t\t\t4C469E9D20EC5F7700094EA4 /* HistoricLogFileStorageModel.xcdatamodeld in Sources */,\n\t\t\t\t4CBDFBEA2C3ED3920003B272 /* TPCPreferencesUserDefaults.m in Sources */,\n\t\t\t\t4C469E5120EC5E5300094EA4 /* main.m in Sources */,\n\t\t\t\t4C469E9C20EC5F7700094EA4 /* HistoricLogFileStorageModel.xcmappingmodel in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4C442C921E13B3D200B187F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1461620EC0F7F000E01C9 /* XPC Services.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C442C931E13B3D200B187F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE145EE20EC0F7F000E01C9 /* XPC Services.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C442C951E13B3D200B187F4 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${SRCROOT}/Classes/Headers/Private/HSLHistoricLogPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-ScrollbackHistoryManager\";\n\t\t\t\tPRODUCT_NAME = \"Scrollback History Manager\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C442C961E13B3D200B187F4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${SRCROOT}/Classes/Headers/Private/HSLHistoricLogPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-ScrollbackHistoryManager\";\n\t\t\t\tPRODUCT_NAME = \"Scrollback History Manager\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4C442C831E13B3D200B187F4 /* Build configuration list for PBXProject \"Historic Log File Manager\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C442C921E13B3D200B187F4 /* Debug */,\n\t\t\t\t4C442C931E13B3D200B187F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4C442C941E13B3D200B187F4 /* Build configuration list for PBXNativeTarget \"Historic Log File Manager\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C442C951E13B3D200B187F4 /* Debug */,\n\t\t\t\t4C442C961E13B3D200B187F4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCVersionGroup section */\n\t\t4C469E9920EC5F7700094EA4 /* HistoricLogFileStorageModel.xcdatamodeld */ = {\n\t\t\tisa = XCVersionGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469E9A20EC5F7700094EA4 /* LogControllerStorageModel (model 2).xcdatamodel */,\n\t\t\t\t4C469E9B20EC5F7700094EA4 /* LogControllerStorageModel (model 3).xcdatamodel */,\n\t\t\t);\n\t\t\tcurrentVersion = 4C469E9B20EC5F7700094EA4 /* LogControllerStorageModel (model 3).xcdatamodel */;\n\t\t\tpath = HistoricLogFileStorageModel.xcdatamodeld;\n\t\t\tsourceTree = \"<group>\";\n\t\t\tversionGroupType = wrapper.xcdatamodel;\n\t\t};\n/* End XCVersionGroup section */\n\t};\n\trootObject = 4C442C801E13B3D200B187F4 /* Project object */;\n}\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Resources/Data Models/HistoricLogFileStorageModel.xcdatamodeld/.xccurrentversion",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>_XCCurrentVersionName</key>\n\t<string>LogControllerStorageModel (model 3).xcdatamodel</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Resources/Data Models/HistoricLogFileStorageModel.xcdatamodeld/LogControllerStorageModel (model 2).xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"13233.4\" systemVersion=\"\" minimumToolsVersion=\"Xcode 7.0\" sourceLanguage=\"Objective-C\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"LogLine\" representedClassName=\"NSManagedObject\" syncable=\"YES\">\n        <attribute name=\"channelId\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"creationDate\" optional=\"YES\" attributeType=\"Double\" defaultValueString=\"0.0\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"data\" optional=\"YES\" attributeType=\"Binary\" syncable=\"YES\"/>\n        <attribute name=\"id\" optional=\"YES\" attributeType=\"Integer 64\" defaultValueString=\"0\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n    </entity>\n    <elements>\n        <element name=\"LogLine\" positionX=\"0\" positionY=\"0\" width=\"128\" height=\"105\"/>\n    </elements>\n</model>"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Resources/Data Models/HistoricLogFileStorageModel.xcdatamodeld/LogControllerStorageModel (model 3).xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"14270.9\" systemVersion=\"\" minimumToolsVersion=\"Xcode 7.0\" sourceLanguage=\"Objective-C\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"LogLine2\" representedClassName=\"NSManagedObject\" syncable=\"YES\">\n        <attribute name=\"entryCreationDate\" optional=\"YES\" attributeType=\"Double\" defaultValueString=\"0.0\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"entryIdentifier\" optional=\"YES\" attributeType=\"Integer 64\" defaultValueString=\"0\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n        <attribute name=\"logLineData\" optional=\"YES\" attributeType=\"Binary\" syncable=\"YES\"/>\n        <attribute name=\"logLineUniqueIdentifier\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"logLineViewIdentifier\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"sessionIdentifier\" attributeType=\"Integer 64\" defaultValueString=\"0\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n    </entity>\n    <fetchRequest name=\"GenericConditional\" entity=\"LogLine2\" predicateString=\"logLineViewIdentifier == $view_id AND entryIdentifier &gt;= $entry_id_lowest AND entryIdentifier &lt;= $entry_id_highest AND entryCreationDate &lt; $creation_date\" fetchBatchSize=\"100\" includePropertyValues=\"YES\" includesPendingChanges=\"YES\" resultType=\"1\"/>\n    <fetchRequest name=\"Truncate\" entity=\"LogLine2\" predicateString=\"logLineViewIdentifier == $view_id AND entryIdentifier &lt;= $entry_id_lowest\" includePropertyValues=\"YES\" includesPendingChanges=\"YES\"/>\n    <fetchRequest name=\"UniqueIdToEntryId\" entity=\"LogLine2\" predicateString=\"logLineViewIdentifier == $view_id AND logLineUniqueIdentifier == $unique_id\" fetchLimit=\"1\" includePropertyValues=\"YES\" includesPendingChanges=\"YES\"/>\n    <elements>\n        <element name=\"LogLine2\" positionX=\"0\" positionY=\"0\" width=\"128\" height=\"135\"/>\n    </elements>\n</model>"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Resources/Data Models/HistoricLogFileStorageModel.xcmappingmodel/xcmapping.xml",
    "content": "<?xml version=\"1.0\" standalone=\"yes\"?>\n<!DOCTYPE database SYSTEM \"file:///System/Library/DTDs/CoreData.dtd\">\n\n<database>\n    <databaseInfo>\n        <version>134481920</version>\n        <UUID>031BCA3F-445F-483C-93E8-91708E39F5A1</UUID>\n        <nextObjectID>122</nextObjectID>\n        <metadata>\n            <plist version=\"1.0\">\n                <dict>\n                    <key>NSPersistenceFrameworkVersion</key>\n                    <integer>847</integer>\n                    <key>NSStoreModelVersionHashes</key>\n                    <dict>\n                        <key>XDDevAttributeMapping</key>\n                        <data>\n\t\t0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc=\n\t\t</data>\n                        <key>XDDevEntityMapping</key>\n                        <data>\n\t\tqeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI=\n\t\t</data>\n                        <key>XDDevMappingModel</key>\n                        <data>\n\t\tEqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ=\n\t\t</data>\n                        <key>XDDevPropertyMapping</key>\n                        <data>\n\t\tXN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA=\n\t\t</data>\n                        <key>XDDevRelationshipMapping</key>\n                        <data>\n\t\takYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs=\n\t\t</data>\n                    </dict>\n                    <key>NSStoreModelVersionHashesVersion</key>\n                    <integer>3</integer>\n                    <key>NSStoreModelVersionIdentifiers</key>\n                    <array>\n                        <string></string>\n                    </array>\n                </dict>\n            </plist>\n        </metadata>\n    </databaseInfo>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z102\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGLC1YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKkH\nCBMUGRoiJilVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAhfEBpuZXdMb2dMaW5lVW5pcXVlSWRlbnRpZmllctMVCw0WFxhaTlNWYXJpYWJsZYAEEAKABVxlbnRpdHlQb2xpY3nSGxwdHlokY2xhc3NuYW1lWCRjbGFzc2VzXxAUTlNWYXJpYWJsZUV4cHJlc3Npb26jHyAhXxAUTlNWYXJpYWJsZUV4cHJlc3Npb25cTlNFeHByZXNzaW9uWE5TT2JqZWN00iMNJCVaTlMub2JqZWN0c6CAB9IbHCcoV05TQXJyYXmiJyHSGxwqK18QFE5TRnVuY3Rpb25FeHByZXNzaW9uoyogIV8QD05TS2V5ZWRBcmNoaXZlctEuL1Ryb290gAEACAARABoAIwAtADIANwBBAEcAUgBcAGsAfgCKAJEAkwCVAJcAmQCbALgAvwDKAMwAzgDQAN0A4gDtAPYBDQERASgBNQE+AUMBTgFPAVEBVgFeAWEBZgF9AYEBkwGWAZsAAAAAAAACAQAAAAAAAAAwAAAAAAAAAAAAAAAAAAABnQ==\n</attribute>\n        <attribute name=\"name\" type=\"string\">logLineUniqueIdentifier</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVMAPPINGMODEL\" id=\"z103\">\n        <attribute name=\"sourcemodelpath\" type=\"string\">Resources/Data Models/HistoricLogFileStorageModel.xcdatamodeld/LogControllerStorageModel (model 2).xcdatamodel</attribute>\n        <attribute name=\"sourcemodeldata\" type=\"binary\">YnBsaXN0MDDUAAEAAgADAAQABQAGBrcGuFgkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv\ncBIAAYagrxCyAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APgAWAEIARcBGwEfAS4BNAE1AT0BTAFNAVYBYgFjAWQBZQFmAXsBfAGEAYUBhgGSAaYBpwGoAakBqgGrAawBrQGuAb0BzAHbAd8B7gH9Af4CDQIcAisCNwJJAkoCSwJMAk0CTgJPAlACXwJgAm8CfgKNAo4CnQKsArsCwwLYAtkC4QLtAwEDEAMfAy4DMgNBA1ADXwNuA30DiQObA6oDuQPIA9cD2APnA/YEBQQaBBsEIwQvBEMEUgRhBHAEdASDBJIEoQSwBL8EywTdBOwE7QT8BQsFGgUbBSoFOQVIBV0FXgVmBXIFhgWVBaQFswW3BcYF1QXkBfMGAgYOBiAGLwY+Bk0GXAZdBmwGewaKBosGjgaXBpsGnwajBqsGrgayBrNVJG51bGzXAAkACgALAAwADQAOAA8AEAARABIAEwAUABMAFl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoCxgK6AAICvgACAsN4AGAAZABoAGwAcAB0AHgAKAB8AIAAhACIAIwAkACUAJgAnACgAJQATACsALAAtAC4ALwAlACUAE18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABICsgKqAAYAEgACAq4CtEACABYADgASABIAAUFNZRVPTADYANwAKADgAOgA8V05TLmtleXNaTlMub2JqZWN0c6EAOYAGoQA7gAeAJVdMb2dMaW5l3xAQAD8AQABBAEIAHQBDAEQAHwBFAEYACgAhAEcASAAkAEkASgBLACUAJQAQAE8AUAAtACUASgBTADkASgBWAFcAWF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZV8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc2R1cGxpY2F0ZXNfECRYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zb3JkZXJlZF8QIVhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zc3RvcmFnZVtfaXNBYnN0cmFjdIAJgC2ABIAEgAKACoCngASACYCpgAaACYCogAgIErmKi6pXb3JkZXJlZNMANgA3AAoAXABeADyhAF2AC6EAX4AMgCVeWERfUFN0ZXJlb3R5cGXZAB0AIQBjAAoAJABkAB8ASQBlADsAXQBKAGkAEwAlAC0AWABtXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgAeAC4AJgCyAAIAECIAN0wA2ADcACgBvAHkAPKkAcABxAHIAcwB0AHUAdgB3AHiADoAPgBCAEYASgBOAFIAVgBapAHoAewB8AH0AfgB/AIAAgQCCgBeAG4AcgB6AH4AhgCOAJoAqgCVfEBNYRFBNQ29tcG91bmRJbmRleGVzXxAQWERfUFNLX2VsZW1lbnRJRF8QGVhEUE1VbmlxdWVuZXNzQ29uc3RyYWludHNfEBpYRF9QU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QGVhEX1BTS19mZXRjaFJlcXVlc3RzQXJyYXlfEBFYRF9QU0tfaXNBYnN0cmFjdF8QD1hEX1BTS191c2VySW5mb18QE1hEX1BTS19jbGFzc01hcHBpbmdfEBZYRF9QU0tfZW50aXR5Q2xhc3NOYW1l3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAmQATAF8AWABYAFgALQBYAKAAcABYAFgAEwBYVV90eXBlWF9kZWZhdWx0XF9hc3NvY2lhdGlvbltfaXNSZWFkT25seVlfaXNTdGF0aWNZX2lzVW5pcXVlWl9pc0Rlcml2ZWRaX2lzT3JkZXJlZFxfaXNDb21wb3NpdGVXX2lzTGVhZoAAgBiAAIAMCAgICIAagA4ICIAACNIANwAKAKcAqKCAGdIAqgCrAKwArVokY2xhc3NuYW1lWCRjbGFzc2VzXk5TTXV0YWJsZUFycmF5owCsAK4Ar1dOU0FycmF5WE5TT2JqZWN00gCqAKsAsQCyXxAQWERVTUxQcm9wZXJ0eUltcKQAswC0ALUAr18QEFhEVU1MUHJvcGVydHlJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwBfAFgAWABYAC0AWACgAHEAWABYABMAWIAAgACAAIAMCAgICIAagA8ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAMcAEwBfAFgAWABYAC0AWACgAHIAWABYABMAWIAAgB2AAIAMCAgICIAagBAICIAACNIANwAKANUAqKCAGd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwBfAFgAWABYAC0AWACgAHMAWABYABMAWIAAgACAAIAMCAgICIAagBEICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAOgAEwBfAFgAWABYAC0AWACgAHQAWABYABMAWIAAgCCAAIAMCAgICIAagBIICIAACNIANwAKAPYAqKCAGd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwBfAFgAWABYAC0AWACgAHUAWABYABMAWIAAgCKAAIAMCAgICIAagBMICIAACAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEKABMAXwBYAFgAWAAtAFgAoAB2AFgAWAATAFiAAIAkgACADAgICAiAGoAUCAiAAAjTADYANwAKARgBGQA8oKCAJdIAqgCrARwBHV8QE05TTXV0YWJsZURpY3Rpb25hcnmjARwBHgCvXE5TRGljdGlvbmFyed8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASEAEwBfAFgAWABYAC0AWACgAHcAWABYABMAWIAAgCeAAIAMCAgICIAagBUICIAACNYAIQAKACQASQAdAB8BLwEwABMAWAATAC2AKIApgAAIgABfEBRYREdlbmVyaWNSZWNvcmRDbGFzc9IAqgCrATYBN11YRFVNTENsYXNzSW1wpgE4ATkBOgE7ATwAr11YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAT8AEwBfAFgAWABYAC0AWACgAHgAWABYABMAWIAAgCuAAIAMCAgICIAagBYICIAACF8QD05TTWFuYWdlZE9iamVjdNIAqgCrAU4BT18QElhEVU1MU3RlcmVvdHlwZUltcKcBUAFRAVIBUwFUAVUAr18QElhEVU1MU3RlcmVvdHlwZUltcF1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNMANgA3AAoBVwFcADykAVgBWQFaAVuALoAvgDCAMaQBXQFeAV8BYIAygF6AdoCPgCVcY3JlYXRpb25EYXRlVGRhdGFSaWRZY2hhbm5lbElk3xASAI4AjwCQAWcAHQCSAJMBaAAfAJEBaQCUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgBcQAtAFgASgBYAXUBWABYAFgBeQBYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgDQIgAkIgF2ALggIgDMIEmSVafvTADYANwAKAX0BgAA8ogF+AX+ANYA2ogGBAYKAN4BLgCVfEBJYRF9QUHJvcFN0ZXJlb3R5cGVfEBJYRF9QQXR0X1N0ZXJlb3R5cGXZAB0AIQGHAAoAJAGIAB8ASQGJAV0BfgBKAGkAEwAlAC0AWAGRXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgDKANYAJgCyAAIAECIA40wA2ADcACgGTAZwAPKgBlAGVAZYBlwGYAZkBmgGbgDmAOoA7gDyAPYA+gD+AQKgBnQGeAZ8BoAGhAaIBowGkgEGAQoBDgEWARoBIgEmASoAlXxAbWERfUFBTS19pc1N0b3JlZEluVHJ1dGhGaWxlXxAbWERfUFBTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAQWERfUFBTS191c2VySW5mb18QEVhEX1BQU0tfaXNJbmRleGVkXxASWERfUFBTS19pc09wdGlvbmFsXxAaWERfUFBTS19pc1Nwb3RsaWdodEluZGV4ZWRfEBFYRF9QUFNLX2VsZW1lbnRJRF8QE1hEX1BQU0tfaXNUcmFuc2llbnTfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMBgQBYAFgAWAAtAFgAoAGUAFgAWAATAFiAAIAigACANwgICAiAGoA5CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBgQBYAFgAWAAtAFgAoAGVAFgAWAATAFiAAIAAgACANwgICAiAGoA6CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwHOABMBgQBYAFgAWAAtAFgAoAGWAFgAWAATAFiAAIBEgACANwgICAiAGoA7CAiAAAjTADYANwAKAdwB3QA8oKCAJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwGBAFgAWABYAC0AWACgAZcAWABYABMAWIAAgCKAAIA3CAgICIAagDwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAfAAEwGBAFgAWABYAC0AWACgAZgAWABYABMAWIAAgEeAAIA3CAgICIAagD0ICIAACAnfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMBgQBYAFgAWAAtAFgAoAGZAFgAWAATAFiAAIAigACANwgICAiAGoA+CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBgQBYAFgAWAAtAFgAoAGaAFgAWAATAFiAAIAAgACANwgICAiAGoA/CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMBgQBYAFgAWAAtAFgAoAGbAFgAWAATAFiAAIAigACANwgICAiAGoBACAiAAAjZAB0AIQIsAAoAJAItAB8ASQIuAV0BfwBKAGkAEwAlAC0AWAI2XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgDKANoAJgCyAAIAECIBM0wA2ADcACgI4AkAAPKcCOQI6AjsCPAI9Aj4CP4BNgE6AT4BQgFGAUoBTpwJBAkICQwJEAkUCRgJHgFSAVoBXgFiAWoBbgFyAJV8QHVhEX1BBdHRLX2RlZmF1bHRWYWx1ZUFzU3RyaW5nXxAoWERfUEF0dEtfYWxsb3dzRXh0ZXJuYWxCaW5hcnlEYXRhU3RvcmFnZV8QF1hEX1BBdHRLX21pblZhbHVlU3RyaW5nXxAWWERfUEF0dEtfYXR0cmlidXRlVHlwZV8QF1hEX1BBdHRLX21heFZhbHVlU3RyaW5nXxAdWERfUEF0dEtfdmFsdWVUcmFuc2Zvcm1lck5hbWVfECBYRF9QQXR0S19yZWd1bGFyRXhwcmVzc2lvblN0cmluZ98QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAlIAEwGCAFgAWABYAC0AWACgAjkAWABYABMAWIAAgFWAAIBLCAgICIAagE0ICIAACFMwLjDfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMBggBYAFgAWAAtAFgAoAI6AFgAWAATAFiAAIAigACASwgICAiAGoBOCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBggBYAFgAWAAtAFgAoAI7AFgAWAATAFiAAIAAgACASwgICAiAGoBPCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwKAABMBggBYAFgAWAAtAFgAoAI8AFgAWAATAFiAAIBZgACASwgICAiAGoBQCAiAAAgRAfTfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBggBYAFgAWAAtAFgAoAI9AFgAWAATAFiAAIAAgACASwgICAiAGoBRCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBggBYAFgAWAAtAFgAoAI+AFgAWAATAFiAAIAAgACASwgICAiAGoBSCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMBggBYAFgAWAAtAFgAoAI/AFgAWAATAFiAAIAAgACASwgICAiAGoBTCAiAAAjSAKoAqwK8Ar1dWERQTUF0dHJpYnV0ZaYCvgK/AsACwQLCAK9dWERQTUF0dHJpYnV0ZVxYRFBNUHJvcGVydHlfEBBYRFVNTFByb3BlcnR5SW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDfEBIAjgCPAJACxAAdAJIAkwLFAB8AkQLGAJQACgAhAJUAlgAkAJcAEwATABMAJQA7AFgAWALOAC0AWABKAFgBdQFZAFgAWALWAFhfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAHCAiAYAiACQiAXYAvCAiAXwgSJ1mbxdMANgA3AAoC2gLdADyiAX4Bf4A1gDaiAt4C34BhgGyAJdkAHQAhAuIACgAkAuMAHwBJAuQBXgF+AEoAaQATACUALQBYAuxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAXoA1gAmALIAAgAQIgGLTADYANwAKAu4C9wA8qAGUAZUBlgGXAZgBmQGaAZuAOYA6gDuAPIA9gD6AP4BAqAL4AvkC+gL7AvwC/QL+Av+AY4BkgGWAZ4BogGmAaoBrgCXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMC3gBYAFgAWAAtAFgAoAGUAFgAWAATAFiAAIAigACAYQgICAiAGoA5CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMC3gBYAFgAWAAtAFgAoAGVAFgAWAATAFiAAIAAgACAYQgICAiAGoA6CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwMhABMC3gBYAFgAWAAtAFgAoAGWAFgAWAATAFiAAIBmgACAYQgICAiAGoA7CAiAAAjTADYANwAKAy8DMAA8oKCAJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwLeAFgAWABYAC0AWACgAZcAWABYABMAWIAAgCKAAIBhCAgICIAagDwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAfAAEwLeAFgAWABYAC0AWACgAZgAWABYABMAWIAAgEeAAIBhCAgICIAagD0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwLeAFgAWABYAC0AWACgAZkAWABYABMAWIAAgCKAAIBhCAgICIAagD4ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwLeAFgAWABYAC0AWACgAZoAWABYABMAWIAAgACAAIBhCAgICIAagD8ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwLeAFgAWABYAC0AWACgAZsAWABYABMAWIAAgCKAAIBhCAgICIAagEAICIAACNkAHQAhA34ACgAkA38AHwBJA4ABXgF/AEoAaQATACUALQBYA4hfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAXoA2gAmALIAAgAQIgG3TADYANwAKA4oDkgA8pwI5AjoCOwI8Aj0CPgI/gE2AToBPgFCAUYBSgFOnA5MDlAOVA5YDlwOYA5mAboBvgHCAcYBzgHSAdYAl3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAt8AWABYAFgALQBYAKACOQBYAFgAEwBYgACAAIAAgGwICAgIgBqATQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATAt8AWABYAFgALQBYAKACOgBYAFgAEwBYgACAIoAAgGwICAgIgBqATggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAt8AWABYAFgALQBYAKACOwBYAFgAEwBYgACAAIAAgGwICAgIgBqATwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMDygATAt8AWABYAFgALQBYAKACPABYAFgAEwBYgACAcoAAgGwICAgIgBqAUAgIgAAIEQPo3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAt8AWABYAFgALQBYAKACPQBYAFgAEwBYgACAAIAAgGwICAgIgBqAUQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAt8AWABYAFgALQBYAKACPgBYAFgAEwBYgACAAIAAgGwICAgIgBqAUggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAt8AWABYAFgALQBYAKACPwBYAFgAEwBYgACAAIAAgGwICAgIgBqAUwgIgAAI3xASAI4AjwCQBAYAHQCSAJMEBwAfAJEECACUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgEEAAtAFgASgBYAXUBWgBYAFgEGABYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgHgIgAkIgF2AMAgIgHcIErT/2e3TADYANwAKBBwEHwA8ogF+AX+ANYA2ogQgBCGAeYCEgCXZAB0AIQQkAAoAJAQlAB8ASQQmAV8BfgBKAGkAEwAlAC0AWAQuXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHaANYAJgCyAAIAECIB60wA2ADcACgQwBDkAPKgBlAGVAZYBlwGYAZkBmgGbgDmAOoA7gDyAPYA+gD+AQKgEOgQ7BDwEPQQ+BD8EQARBgHuAfIB9gH+AgICBgIKAg4Al3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBCAAWABYAFgALQBYAKABlABYAFgAEwBYgACAIoAAgHkICAgIgBqAOQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBCAAWABYAFgALQBYAKABlQBYAFgAEwBYgACAAIAAgHkICAgIgBqAOggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMEYwATBCAAWABYAFgALQBYAKABlgBYAFgAEwBYgACAfoAAgHkICAgIgBqAOwgIgAAI0wA2ADcACgRxBHIAPKCggCXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMEIABYAFgAWAAtAFgAoAGXAFgAWAATAFiAAIAigACAeQgICAiAGoA8CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwHwABMEIABYAFgAWAAtAFgAoAGYAFgAWAATAFiAAIBHgACAeQgICAiAGoA9CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMEIABYAFgAWAAtAFgAoAGZAFgAWAATAFiAAIAigACAeQgICAiAGoA+CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEIABYAFgAWAAtAFgAoAGaAFgAWAATAFiAAIAAgACAeQgICAiAGoA/CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMEIABYAFgAWAAtAFgAoAGbAFgAWAATAFiAAIAigACAeQgICAiAGoBACAiAAAjZAB0AIQTAAAoAJATBAB8ASQTCAV8BfwBKAGkAEwAlAC0AWATKXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgHaANoAJgCyAAIAECICF0wA2ADcACgTMBNQAPKcCOQI6AjsCPAI9Aj4CP4BNgE6AT4BQgFGAUoBTpwTVBNYE1wTYBNkE2gTbgIaAiICJgIqAjICNgI6AJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATBN8AEwQhAFgAWABYAC0AWACgAjkAWABYABMAWIAAgIeAAICECAgICIAagE0ICIAACFEw3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBCEAWABYAFgALQBYAKACOgBYAFgAEwBYgACAIoAAgIQICAgIgBqATggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBCEAWABYAFgALQBYAKACOwBYAFgAEwBYgACAAIAAgIQICAgIgBqATwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMFDQATBCEAWABYAFgALQBYAKACPABYAFgAEwBYgACAi4AAgIQICAgIgBqAUAgIgAAIEQEs3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBCEAWABYAFgALQBYAKACPQBYAFgAEwBYgACAAIAAgIQICAgIgBqAUQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBCEAWABYAFgALQBYAKACPgBYAFgAEwBYgACAAIAAgIQICAgIgBqAUggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBCEAWABYAFgALQBYAKACPwBYAFgAEwBYgACAAIAAgIQICAgIgBqAUwgIgAAI3xASAI4AjwCQBUkAHQCSAJMFSgAfAJEFSwCUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgFUwAtAFgASgBYAXUBWwBYAFgFWwBYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgJEIgAkIgF2AMQgIgJAIEniZwYPTADYANwAKBV8FYgA8ogF+AX+ANYA2ogVjBWSAkoCdgCXZAB0AIQVnAAoAJAVoAB8ASQVpAWABfgBKAGkAEwAlAC0AWAVxXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgI+ANYAJgCyAAIAECICT0wA2ADcACgVzBXwAPKgBlAGVAZYBlwGYAZkBmgGbgDmAOoA7gDyAPYA+gD+AQKgFfQV+BX8FgAWBBYIFgwWEgJSAlYCWgJiAmYCagJuAnIAl3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA+gATBWMAWABYAFgALQBYAKABlABYAFgAEwBYgACAIoAAgJIICAgIgBqAOQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBWMAWABYAFgALQBYAKABlQBYAFgAEwBYgACAAIAAgJIICAgIgBqAOggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMFpgATBWMAWABYAFgALQBYAKABlgBYAFgAEwBYgACAl4AAgJIICAgIgBqAOwgIgAAI0wA2ADcACgW0BbUAPKCggCXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMFYwBYAFgAWAAtAFgAoAGXAFgAWAATAFiAAIAigACAkggICAiAGoA8CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwHwABMFYwBYAFgAWAAtAFgAoAGYAFgAWAATAFiAAIBHgACAkggICAiAGoA9CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMFYwBYAFgAWAAtAFgAoAGZAFgAWAATAFiAAIAigACAkggICAiAGoA+CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMFYwBYAFgAWAAtAFgAoAGaAFgAWAATAFiAAIAAgACAkggICAiAGoA/CAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwD6ABMFYwBYAFgAWAAtAFgAoAGbAFgAWAATAFiAAIAigACAkggICAiAGoBACAiAAAjZAB0AIQYDAAoAJAYEAB8ASQYFAWABfwBKAGkAEwAlAC0AWAYNXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgI+ANoAJgCyAAIAECICe0wA2ADcACgYPBhcAPKcCOQI6AjsCPAI9Aj4CP4BNgE6AT4BQgFGAUoBTpwYYBhkGGgYbBhwGHQYegJ+AoIChgKKApIClgKaAJd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwVkAFgAWABYAC0AWACgAjkAWABYABMAWIAAgACAAICdCAgICIAagE0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAPoAEwVkAFgAWABYAC0AWACgAjoAWABYABMAWIAAgCKAAICdCAgICIAagE4ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwVkAFgAWABYAC0AWACgAjsAWABYABMAWIAAgACAAICdCAgICIAagE8ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATBk8AEwVkAFgAWABYAC0AWACgAjwAWABYABMAWIAAgKOAAICdCAgICIAagFAICIAACBECvN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwVkAFgAWABYAC0AWACgAj0AWABYABMAWIAAgACAAICdCAgICIAagFEICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwVkAFgAWABYAC0AWACgAj4AWABYABMAWIAAgACAAICdCAgICIAagFIICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwVkAFgAWABYAC0AWACgAj8AWABYABMAWIAAgACAAICdCAgICIAagFMICIAACFpkdXBsaWNhdGVz0gA3AAoGjACooIAZ0gCqAKsGjwaQWlhEUE1FbnRpdHmnBpEGkgaTBpQGlQaWAK9aWERQTUVudGl0eV1YRFVNTENsYXNzSW1wXxASWERVTUxDbGFzc2lmaWVySW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNMANgA3AAoGmAaZADygoIAl0wA2ADcACgacBp0APKCggCXTADYANwAKBqAGoQA8oKCAJdIAqgCrBqQGpV5YRE1vZGVsUGFja2FnZaYGpganBqgGqQaqAK9eWERNb2RlbFBhY2thZ2VfEA9YRFVNTFBhY2thZ2VJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0gA3AAoGrACooIAZ0wA2ADcACgavBrAAPKCggCVQ0gCqAKsGtAa1WVhEUE1Nb2RlbKMGtAa2AK9XWERNb2RlbF8QD05TS2V5ZWRBcmNoaXZlctEGuQAoVHJvb3SAAQAIABkAIgArADUAOgA/AaYBrAHJAdsB4gHvAgICGgIoAkICRAJGAkgCSgJMAk4CUAKJAqgCxQLkAvYDFgMdAzsDRwNjA2kDiwOsA78DwQPDA8UDxwPJA8sDzQPPA9ED0wPVA9cD2QPbA9wD4APtA/UEAAQDBAUECAQKBAwEFARXBHsEnwTCBOkFCQUwBVcFdwWbBb8FywXNBc8F0QXTBdUF1wXZBdsF3QXfBeEF4wXlBecF6AXtBfUGAgYFBgcGCgYMBg4GHQZCBmYGjQaxBrMGtQa3BrkGuwa9Br4GwAbNBuAG4gbkBuYG6AbqBuwG7gbwBvIHBQcHBwkHCwcNBw8HEQcTBxUHFwcZBy8HQgdeB3sHlwerB70H0wfsCCsIMQg6CEcIUwhdCGcIcgh9CIoIkgiUCJYImAiaCJsInAidCJ4IoAiiCKMIpAimCKcIsAixCLMIvAjHCNAI3wjmCO4I9wkACRMJHAkvCUYJWAmXCZkJmwmdCZ8JoAmhCaIJowmlCacJqAmpCasJrAnrCe0J7wnxCfMJ9An1CfYJ9wn5CfsJ/An9Cf8KAAoJCgoKDApLCk0KTwpRClMKVApVClYKVwpZClsKXApdCl8KYAqfCqEKowqlCqcKqAqpCqoKqwqtCq8KsAqxCrMKtAq9Cr4KwAr/CwELAwsFCwcLCAsJCwoLCwsNCw8LEAsRCxMLFAsVC1QLVgtYC1oLXAtdC14LXwtgC2ILZAtlC2YLaAtpC3YLdwt4C3oLgwuZC6ALrQvsC+4L8AvyC/QL9Qv2C/cL+Av6C/wL/Qv+DAAMAQwaDBwMHgwgDCEMIww6DEMMUQxeDGwMgQyVDKwMvgz9DP8NAQ0DDQUNBg0HDQgNCQ0LDQ0NDg0PDRENEg0kDS0NQg1RDWYNdA2JDZ0NtA3GDdMN3A3eDeAN4g3kDe0N7w3xDfMN9Q33DgQOCQ4MDhYOYQ6EDqQOxA7GDsgOyg7MDs4Ozw7QDtIO0w7VDtYO2A7aDtsO3A7eDt8O5A7xDvYO+A76Dv8PAQ8DDwUPGg8vD1QPeA+fD8MPxQ/HD8kPyw/ND88P0A/SD98P8A/yD/QP9g/4D/oP/A/+EAAQERATEBUQFxAZEBsQHRAfECEQIxBBEF8QchCGEJsQuBDMEOIRIREjESURJxEpESoRKxEsES0RLxExETIRMxE1ETYRdRF3EXkRexF9EX4RfxGAEYERgxGFEYYRhxGJEYoRyRHLEc0RzxHREdIR0xHUEdUR1xHZEdoR2xHdEd4R6xHsEe0R7xIuEjASMhI0EjYSNxI4EjkSOhI8Ej4SPxJAEkISQxKCEoQShhKIEooSixKMEo0SjhKQEpISkxKUEpYSlxKYEtcS2RLbEt0S3xLgEuES4hLjEuUS5xLoEukS6xLsEysTLRMvEzETMxM0EzUTNhM3EzkTOxM8Ez0TPxNAE38TgRODE4UThxOIE4kTihOLE40TjxOQE5ETkxOUE7kT3RQEFCgUKhQsFC4UMBQyFDQUNRQ3FEQUUxRVFFcUWRRbFF0UXxRhFHAUchR0FHYUeBR6FHwUfhSAFKAUyxTlFP4VGBU4FVsVmhWcFZ4VoBWiFaMVpBWlFaYVqBWqFasVrBWuFa8VsxXyFfQV9hX4FfoV+xX8Ff0V/hYAFgIWAxYEFgYWBxZGFkgWShZMFk4WTxZQFlEWUhZUFlYWVxZYFloWWxaaFpwWnhagFqIWoxakFqUWphaoFqoWqxasFq4WrxayFvEW8xb1FvcW+Rb6FvsW/Bb9Fv8XARcCFwMXBRcGF0UXRxdJF0sXTRdOF08XUBdRF1MXVRdWF1cXWRdaF5kXmxedF58XoReiF6MXpBelF6cXqReqF6sXrReuF7cXxRfSF+AX7RgAGBcYKRh0GJcYtxjXGNkY2xjdGN8Y4RjiGOMY5RjmGOgY6RjrGO0Y7hjvGPEY8hj3GQQZCRkLGQ0ZEhkUGRYZGBk9GWEZiBmsGa4ZsBmyGbQZthm4GbkZuxnIGdkZ2xndGd8Z4RnjGeUZ5xnpGfoZ/Bn+GgAaAhoEGgYaCBoKGgwaSxpNGk8aURpTGlQaVRpWGlcaWRpbGlwaXRpfGmAanxqhGqMapRqnGqgaqRqqGqsarRqvGrAasRqzGrQa8xr1Gvca+Rr7Gvwa/Rr+Gv8bARsDGwQbBRsHGwgbFRsWGxcbGRtYG1obXBteG2AbYRtiG2MbZBtmG2gbaRtqG2wbbRusG64bsBuyG7QbtRu2G7cbuBu6G7wbvRu+G8AbwRwAHAIcBBwGHAgcCRwKHAscDBwOHBAcERwSHBQcFRxUHFYcWBxaHFwcXRxeHF8cYBxiHGQcZRxmHGgcaRyoHKocrByuHLAcsRyyHLMctBy2HLgcuRy6HLwcvRziHQYdLR1RHVMdVR1XHVkdWx1dHV4dYB1tHXwdfh2AHYIdhB2GHYgdih2ZHZsdnR2fHaEdox2lHacdqR3oHeod7B3uHfAd8R3yHfMd9B32Hfgd+R36Hfwd/R48Hj4eQB5CHkQeRR5GHkceSB5KHkweTR5OHlAeUR6QHpIelB6WHpgemR6aHpsenB6eHqAeoR6iHqQepR7kHuYe6B7qHuwe7R7uHu8e8B7yHvQe9R72Hvge+R78HzsfPR8/H0EfQx9EH0UfRh9HH0kfSx9MH00fTx9QH48fkR+TH5Uflx+YH5kfmh+bH50fnx+gH6Efox+kH+Mf5R/nH+kf6x/sH+0f7h/vH/Ef8x/0H/Uf9x/4IEMgZiCGIKYgqCCqIKwgriCwILEgsiC0ILUgtyC4ILogvCC9IL4gwCDBIMYg0yDYINog3CDhIOMg5SDnIQwhMCFXIXshfSF/IYEhgyGFIYchiCGKIZchqCGqIawhriGwIbIhtCG2IbghySHLIc0hzyHRIdMh1SHXIdkh2yIaIhwiHiIgIiIiIyIkIiUiJiIoIioiKyIsIi4iLyJuInAiciJ0InYidyJ4InkieiJ8In4ifyKAIoIigyLCIsQixiLIIsoiyyLMIs0iziLQItIi0yLUItYi1yLkIuUi5iLoIycjKSMrIy0jLyMwIzEjMiMzIzUjNyM4IzkjOyM8I3sjfSN/I4EjgyOEI4UjhiOHI4kjiyOMI40jjyOQI88j0SPTI9Uj1yPYI9kj2iPbI90j3yPgI+Ej4yPkJCMkJSQnJCkkKyQsJC0kLiQvJDEkMyQ0JDUkNyQ4JHckeSR7JH0kfySAJIEkgiSDJIUkhySIJIkkiySMJLEk1ST8JSAlIiUkJSYlKCUqJSwlLSUvJTwlSyVNJU8lUSVTJVUlVyVZJWglaiVsJW4lcCVyJXQldiV4JbcluSW7Jb0lvyXAJcElwiXDJcUlxyXIJcklyyXMJc4mDSYPJhEmEyYVJhYmFyYYJhkmGyYdJh4mHyYhJiImYSZjJmUmZyZpJmomayZsJm0mbyZxJnImcyZ1JnYmtSa3Jrkmuya9Jr4mvybAJsEmwybFJsYmxybJJsomzScMJw4nECcSJxQnFScWJxcnGCcaJxwnHSceJyAnISdgJ2InZCdmJ2gnaSdqJ2snbCduJ3AncSdyJ3QndSe0J7YnuCe6J7wnvSe+J78nwCfCJ8QnxSfGJ8gnySgUKDcoVyh3KHkoeyh9KH8ogSiCKIMohSiGKIgoiSiLKI0ojiiPKJEokiiXKKQoqSirKK0osii0KLYouCjdKQEpKClMKU4pUClSKVQpVilYKVkpWyloKXkpeyl9KX8pgSmDKYUphymJKZopnCmeKaApoimkKaYpqCmqKawp6yntKe8p8SnzKfQp9Sn2Kfcp+Sn7Kfwp/Sn/KgAqPypBKkMqRSpHKkgqSSpKKksqTSpPKlAqUSpTKlQqkyqVKpcqmSqbKpwqnSqeKp8qoSqjKqQqpSqnKqgqtSq2KrcquSr4Kvoq/Cr+KwArASsCKwMrBCsGKwgrCSsKKwwrDStMK04rUCtSK1QrVStWK1crWCtaK1wrXSteK2ArYSugK6IrpCumK6grqSuqK6srrCuuK7ArsSuyK7QrtSv0K/Yr+Cv6K/wr/Sv+K/8sACwCLAQsBSwGLAgsCSxILEosTCxOLFAsUSxSLFMsVCxWLFgsWSxaLFwsXSyCLKYszSzxLPMs9Sz3LPks+yz9LP4tAC0NLRwtHi0gLSItJC0mLSgtKi05LTstPS0/LUEtQy1FLUctSS2ILYotjC2OLZAtkS2SLZMtlC2WLZgtmS2aLZwtnS3cLd4t4C3iLeQt5S3mLect6C3qLewt7S3uLfAt8S4wLjIuNC42LjguOS46LjsuPC4+LkAuQS5CLkQuRS6ELoYuiC6KLowujS6OLo8ukC6SLpQulS6WLpgumS6cLtsu3S7fLuEu4y7kLuUu5i7nLuku6y7sLu0u7y7wLy8vMS8zLzUvNy84LzkvOi87Lz0vPy9AL0EvQy9EL4MvhS+HL4kviy+ML40vji+PL5Evky+UL5Uvly+YL6MvrC+tL68vuC/DL9Iv3S/rMAAwFDArMD0wSjBLMEwwTjBbMFwwXTBfMGwwbTBuMHAweTCIMJUwpDC2MMow4TDzMPww/TD/MQwxDTEOMRAxETEaMSQxKzEzMUUxSjFPAAAAAAAAAgIAAAAAAAAGuwAAAAAAAAAAAAAAAAAAMVE=\n</attribute>\n        <attribute name=\"destinationmodelpath\" type=\"string\">Resources/Data Models/HistoricLogFileStorageModel.xcdatamodeld/LogControllerStorageModel (model 3).xcdatamodel</attribute>\n        <attribute name=\"destinationmodeldata\" type=\"binary\">YnBsaXN0MDDUAAEAAgADAAQABQAGCWkJalgkdmVyc2lvblgkb2JqZWN0c1kkYXJjaGl2ZXJUJHRv\ncBIAAYagrxDuAAcACAAXADMANAA1AD0APgBZAFoAWwBhAGIAbgCEAIUAhgCHAIgAiQCKAIsAjACNAKYAqQCwALYAxQDUANcA5gD1APwBBQEGAQoBEAERARIBGAEZARoBIAEhASIAWAEyAUEBRQFJAVgBXgFfAWcBdgF3AYABkAGRAZIBkwGUAZUBlgGrAawBtAG1AbYBwgHWAdcB2AHZAdoB2wHcAd0B3gHtAfwCCwIPAh4CLQIuAj0CTAJbAmcCeQJ6AnsCfAJ9An4CfwKAAo8CngKtArwCvQLMAtsC6gLyAwcDCAMQAxwDMAM/A04DXQNhA3ADfwOOA50DrAO4A8oD2QPaA+kD+AQHBAgEFwQmBDUESgRLBFMEXwRzBIIEkQSgBKQEswTCBNEE4ATvBPsFDQUcBR0FLAU7BUoFSwVaBWkFeAWNBY4FlgWiBbYFxQXUBeMF5wX2BgUGFAYjBjIGPgZQBl8GbgZ9BowGmwaqBrkGzgbPBtcG4wb3BwYHFQckBygHNwdGB1UHZAdzB38HkQegB68HvgfNB84H3QfsB/sIEAgRCBkIJQg5CEgIVwhmCGoIeQiICJcIpgi1CMEI0wjiCPEJAAkPCR4JLQk8CT0JQAlJCU0JUQlVCV0JYAlkCWVVJG51bGzXAAkACgALAAwADQAOAA8AEAARABIAEwAUABMAFl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoDtgOqAAIDrgACA7N4AGAAZABoAGwAcAB0AHgAKAB8AIAAhACIAIwAkACUAJgAnACgAJQATACsALAAtAC4ALwAlACUAE18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIDogOaAAYAEgACA54DpEACABYADgASABIAAUFNZRVPTADYANwAKADgAOgA8V05TLmtleXNaTlMub2JqZWN0c6EAOYAGoQA7gAeAMVhMb2dMaW5lMt8QEAA/AEAAQQBCAB0AQwBEAB8ARQBGAAoAIQBHAEgAJABJAEoASwAlACUAEABPAFAALQAlAEoAUwA5AEoAVgBXAFhfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SACYA5gASABIACgAqA44AEgAmA5YAGgAmA5IAICBMAAAABHk5WSVdvcmRlcmVk0wA2ADcACgBcAF4APKEAXYALoQBfgAyAMV5YRF9QU3RlcmVvdHlwZdkAHQAhAGMACgAkAGQAHwBJAGUAOwBdAEoAaQATACUALQBYAG1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmAOIAAgAQIgA3TADYANwAKAG8AeQA8qQBwAHEAcgBzAHQAdQB2AHcAeIAOgA+AEIARgBKAE4AUgBWAFqkAegB7AHwAfQB+AH8AgACBAIKAF4AbgByAHoAfgC2AL4AygDaAMV8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZWERfUFNLX2ZldGNoUmVxdWVzdHNBcnJheV8QEVhEX1BTS19pc0Fic3RyYWN0XxAPWERfUFNLX3VzZXJJbmZvXxATWERfUFNLX2NsYXNzTWFwcGluZ18QFlhEX1BTS19lbnRpdHlDbGFzc05hbWXfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwCZABMAXwBYAFgAWAAtAFgAoABwAFgAWAATAFhVX3R5cGVYX2RlZmF1bHRcX2Fzc29jaWF0aW9uW19pc1JlYWRPbmx5WV9pc1N0YXRpY1lfaXNVbmlxdWVaX2lzRGVyaXZlZFpfaXNPcmRlcmVkXF9pc0NvbXBvc2l0ZVdfaXNMZWFmgACAGIAAgAwICAgIgBqADggIgAAI0gA3AAoApwCooIAZ0gCqAKsArACtWiRjbGFzc25hbWVYJGNsYXNzZXNeTlNNdXRhYmxlQXJyYXmjAKwArgCvV05TQXJyYXlYTlNPYmplY3TSAKoAqwCxALJfEBBYRFVNTFByb3BlcnR5SW1wpACzALQAtQCvXxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAF8AWABYAFgALQBYAKAAcQBYAFgAEwBYgACAAIAAgAwICAgIgBqADwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAxwATAF8AWABYAFgALQBYAKAAcgBYAFgAEwBYgACAHYAAgAwICAgIgBqAEAgIgAAI0gA3AAoA1QCooIAZ3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAF8AWABYAFgALQBYAKAAcwBYAFgAEwBYgACAAIAAgAwICAgIgBqAEQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMA6AATAF8AWABYAFgALQBYAKAAdABYAFgAEwBYgACAIIAAgAwICAgIgBqAEggIgAAI0gA3AAoA9gCopAD3APgA+QD6gCGAJIAngCqAGdUAIQD9AP4A/wAKAQAAEwATADsBBF8QEF9mZXRjaGVkUHJvcGVydHlfEBBfcHJlZGljYXRlU3RyaW5nV19lbnRpdHmAIoAAgACAB4AjWkdlbmVyaWNBbGzSAKoAqwEHAQhfEBBYRFBNRmV0Y2hSZXF1ZXN0ogEJAK9fEBBYRFBNRmV0Y2hSZXF1ZXN01QAhAP0A/gD/AAoBCwATAQ0AOwEEgCWAAIAmgAeAI18QEkdlbmVyaWNDb25kaXRpb25hbF8QmWxvZ0xpbmVWaWV3SWRlbnRpZmllciA9PSAkdmlld19pZCBBTkQgZW50cnlJZGVudGlmaWVyID49ICRlbnRyeV9pZF9sb3dlc3QgQU5EIGVudHJ5SWRlbnRpZmllciA8PSAkZW50cnlfaWRfaGlnaGVzdCBBTkQgZW50cnlDcmVhdGlvbkRhdGUgPCAkY3JlYXRpb25fZGF0ZdUAIQD9AP4A/wAKARMAEwEVADsBBIAogACAKYAHgCNYVHJ1bmNhdGVfEElsb2dMaW5lVmlld0lkZW50aWZpZXIgPT0gJHZpZXdfaWQgQU5EIGVudHJ5SWRlbnRpZmllciA8PSAkZW50cnlfaWRfbG93ZXN01QAhAP0A/gD/AAoBGwATAR0AOwEEgCuAAIAsgAeAI18QEVVuaXF1ZUlkVG9FbnRyeUlkXxBLbG9nTGluZVZpZXdJZGVudGlmaWVyID09ICR2aWV3X2lkIEFORCBsb2dMaW5lVW5pcXVlSWRlbnRpZmllciA9PSAkdW5pcXVlX2lk3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATAF8AWABYAFgALQBYAKAAdQBYAFgAEwBYgACALoAAgAwICAgIgBqAEwgIgAAICN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATATQAEwBfAFgAWABYAC0AWACgAHYAWABYABMAWIAAgDCAAIAMCAgICIAagBQICIAACNMANgA3AAoBQgFDADygoIAx0gCqAKsBRgFHXxATTlNNdXRhYmxlRGljdGlvbmFyeaMBRgFIAK9cTlNEaWN0aW9uYXJ53xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBSwATAF8AWABYAFgALQBYAKAAdwBYAFgAEwBYgACAM4AAgAwICAgIgBqAFQgIgAAI1gAhAAoAJABJAB0AHwFZAVoAEwBYABMALYA0gDWAAAiAAF8QFFhER2VuZXJpY1JlY29yZENsYXNz0gCqAKsBYAFhXVhEVU1MQ2xhc3NJbXCmAWIBYwFkAWUBZgCvXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBaQATAF8AWABYAFgALQBYAKAAeABYAFgAEwBYgACAN4AAgAwICAgIgBqAFggIgAAIXxAPTlNNYW5hZ2VkT2JqZWN00gCqAKsBeAF5XxASWERVTUxTdGVyZW90eXBlSW1wpwF6AXsBfAF9AX4BfwCvXxASWERVTUxTdGVyZW90eXBlSW1wXVhEVU1MQ2xhc3NJbXBfEBJYRFVNTENsYXNzaWZpZXJJbXBfEBFYRFVNTE5hbWVzcGFjZUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w0wA2ADcACgGBAYgAPKYBggGDAYQBhQGGAYeAOoA7gDyAPYA+gD+mAYkBigGLAYwBjQGOgECAa4CEgJ2AtIDMgDFfEBVsb2dMaW5lVmlld0lkZW50aWZpZXJfEBFlbnRyeUNyZWF0aW9uRGF0ZV8QD2VudHJ5SWRlbnRpZmllcl8QF2xvZ0xpbmVVbmlxdWVJZGVudGlmaWVyW2xvZ0xpbmVEYXRhXxARc2Vzc2lvbklkZW50aWZpZXLfEBIAjgCPAJABlwAdAJIAkwGYAB8AkQGZAJQACgAhAJUAlgAkAJcAEwATABMAJQA7AFgAWAGhAC0AWABKAFgBpQGCAFgAWAGpAFhfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAHCAiAQgiACQiAaoA6CAiAQQgS489V8NMANgA3AAoBrQGwADyiAa4Br4BDgESiAbEBsoBFgFmAMV8QElhEX1BQcm9wU3RlcmVvdHlwZV8QElhEX1BBdHRfU3RlcmVvdHlwZdkAHQAhAbcACgAkAbgAHwBJAbkBiQGuAEoAaQATACUALQBYAcFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAQIBDgAmAOIAAgAQIgEbTADYANwAKAcMBzAA8qAHEAcUBxgHHAcgByQHKAcuAR4BIgEmASoBLgEyATYBOqAHNAc4BzwHQAdEB0gHTAdSAT4BQgFGAU4BUgFaAV4BYgDFfEBtYRF9QUFNLX2lzU3RvcmVkSW5UcnV0aEZpbGVfEBtYRF9QUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBBYRF9QUFNLX3VzZXJJbmZvXxARWERfUFBTS19pc0luZGV4ZWRfEBJYRF9QUFNLX2lzT3B0aW9uYWxfEBpYRF9QUFNLX2lzU3BvdGxpZ2h0SW5kZXhlZF8QEVhEX1BQU0tfZWxlbWVudElEXxATWERfUFBTS19pc1RyYW5zaWVudN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwGxAFgAWABYAC0AWACgAcQAWABYABMAWIAAgC6AAIBFCAgICIAagEcICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwGxAFgAWABYAC0AWACgAcUAWABYABMAWIAAgACAAIBFCAgICIAagEgICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAf4AEwGxAFgAWABYAC0AWACgAcYAWABYABMAWIAAgFKAAIBFCAgICIAagEkICIAACNMANgA3AAoCDAINADygoIAx3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATAbEAWABYAFgALQBYAKABxwBYAFgAEwBYgACALoAAgEUICAgIgBqASggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMCIAATAbEAWABYAFgALQBYAKAByABYAFgAEwBYgACAVYAAgEUICAgIgBqASwgIgAAICd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwGxAFgAWABYAC0AWACgAckAWABYABMAWIAAgC6AAIBFCAgICIAagEwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwGxAFgAWABYAC0AWACgAcoAWABYABMAWIAAgACAAIBFCAgICIAagE0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwGxAFgAWABYAC0AWACgAcsAWABYABMAWIAAgC6AAIBFCAgICIAagE4ICIAACNkAHQAhAlwACgAkAl0AHwBJAl4BiQGvAEoAaQATACUALQBYAmZfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAQIBEgAmAOIAAgAQIgFrTADYANwAKAmgCcAA8pwJpAmoCawJsAm0CbgJvgFuAXIBdgF6AX4BggGGnAnECcgJzAnQCdQJ2AneAYoBjgGSAZYBngGiAaYAxXxAdWERfUEF0dEtfZGVmYXVsdFZhbHVlQXNTdHJpbmdfEChYRF9QQXR0S19hbGxvd3NFeHRlcm5hbEJpbmFyeURhdGFTdG9yYWdlXxAXWERfUEF0dEtfbWluVmFsdWVTdHJpbmdfEBZYRF9QQXR0S19hdHRyaWJ1dGVUeXBlXxAXWERfUEF0dEtfbWF4VmFsdWVTdHJpbmdfEB1YRF9QQXR0S192YWx1ZVRyYW5zZm9ybWVyTmFtZV8QIFhEX1BBdHRLX3JlZ3VsYXJFeHByZXNzaW9uU3RyaW5n3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAbIAWABYAFgALQBYAKACaQBYAFgAEwBYgACAAIAAgFkICAgIgBqAWwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATAbIAWABYAFgALQBYAKACagBYAFgAEwBYgACALoAAgFkICAgIgBqAXAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAbIAWABYAFgALQBYAKACawBYAFgAEwBYgACAAIAAgFkICAgIgBqAXQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMCrwATAbIAWABYAFgALQBYAKACbABYAFgAEwBYgACAZoAAgFkICAgIgBqAXggIgAAIEQK83xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAbIAWABYAFgALQBYAKACbQBYAFgAEwBYgACAAIAAgFkICAgIgBqAXwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAbIAWABYAFgALQBYAKACbgBYAFgAEwBYgACAAIAAgFkICAgIgBqAYAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAbIAWABYAFgALQBYAKACbwBYAFgAEwBYgACAAIAAgFkICAgIgBqAYQgIgAAI0gCqAKsC6wLsXVhEUE1BdHRyaWJ1dGWmAu0C7gLvAvAC8QCvXVhEUE1BdHRyaWJ1dGVcWERQTVByb3BlcnR5XxAQWERVTUxQcm9wZXJ0eUltcF8QFFhEVU1MTmFtZWRFbGVtZW50SW1wXxAPWERVTUxFbGVtZW50SW1w3xASAI4AjwCQAvMAHQCSAJMC9AAfAJEC9QCUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgC/QAtAFgASgBYAaUBgwBYAFgDBQBYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgG0IgAkIgGqAOwgIgGwIEjigAOrTADYANwAKAwkDDAA8ogGuAa+AQ4BEogMNAw6AboB5gDHZAB0AIQMRAAoAJAMSAB8ASQMTAYoBrgBKAGkAEwAlAC0AWAMbXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgGuAQ4AJgDiAAIAECIBv0wA2ADcACgMdAyYAPKgBxAHFAcYBxwHIAckBygHLgEeASIBJgEqAS4BMgE2ATqgDJwMoAykDKgMrAywDLQMugHCAcYBygHSAdYB2gHeAeIAx3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATAw0AWABYAFgALQBYAKABxABYAFgAEwBYgACALoAAgG4ICAgIgBqARwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATAw0AWABYAFgALQBYAKABxQBYAFgAEwBYgACAAIAAgG4ICAgIgBqASAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMDUAATAw0AWABYAFgALQBYAKABxgBYAFgAEwBYgACAc4AAgG4ICAgIgBqASQgIgAAI0wA2ADcACgNeA18APKCggDHfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMDDQBYAFgAWAAtAFgAoAHHAFgAWAATAFiAAIAugACAbggICAiAGoBKCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwIgABMDDQBYAFgAWAAtAFgAoAHIAFgAWAATAFiAAIBVgACAbggICAiAGoBLCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMDDQBYAFgAWAAtAFgAoAHJAFgAWAATAFiAAIAugACAbggICAiAGoBMCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMDDQBYAFgAWAAtAFgAoAHKAFgAWAATAFiAAIAAgACAbggICAiAGoBNCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMDDQBYAFgAWAAtAFgAoAHLAFgAWAATAFiAAIAugACAbggICAiAGoBOCAiAAAjZAB0AIQOtAAoAJAOuAB8ASQOvAYoBrwBKAGkAEwAlAC0AWAO3XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgGuARIAJgDiAAIAECIB60wA2ADcACgO5A8EAPKcCaQJqAmsCbAJtAm4Cb4BbgFyAXYBegF+AYIBhpwPCA8MDxAPFA8YDxwPIgHuAfYB+gH+AgYCCgIOAMd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATA8wAEwMOAFgAWABYAC0AWACgAmkAWABYABMAWIAAgHyAAIB5CAgICIAagFsICIAACFMwLjDfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMDDgBYAFgAWAAtAFgAoAJqAFgAWAATAFiAAIAugACAeQgICAiAGoBcCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMDDgBYAFgAWAAtAFgAoAJrAFgAWAATAFiAAIAAgACAeQgICAiAGoBdCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwP6ABMDDgBYAFgAWAAtAFgAoAJsAFgAWAATAFiAAICAgACAeQgICAiAGoBeCAiAAAgRAfTfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMDDgBYAFgAWAAtAFgAoAJtAFgAWAATAFiAAIAAgACAeQgICAiAGoBfCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMDDgBYAFgAWAAtAFgAoAJuAFgAWAATAFiAAIAAgACAeQgICAiAGoBgCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMDDgBYAFgAWAAtAFgAoAJvAFgAWAATAFiAAIAAgACAeQgICAiAGoBhCAiAAAjfEBIAjgCPAJAENgAdAJIAkwQ3AB8AkQQ4AJQACgAhAJUAlgAkAJcAEwATABMAJQA7AFgAWARAAC0AWABKAFgBpQGEAFgAWARIAFhfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAHCAiAhgiACQiAaoA8CAiAhQgS9yHsndMANgA3AAoETARPADyiAa4Br4BDgESiBFAEUYCHgJKAMdkAHQAhBFQACgAkBFUAHwBJBFYBiwGuAEoAaQATACUALQBYBF5fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAhIBDgAmAOIAAgAQIgIjTADYANwAKBGAEaQA8qAHEAcUBxgHHAcgByQHKAcuAR4BIgEmASoBLgEyATYBOqARqBGsEbARtBG4EbwRwBHGAiYCKgIuAjYCOgI+AkICRgDHfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMEUABYAFgAWAAtAFgAoAHEAFgAWAATAFiAAIAugACAhwgICAiAGoBHCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEUABYAFgAWAAtAFgAoAHFAFgAWAATAFiAAIAAgACAhwgICAiAGoBICAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwSTABMEUABYAFgAWAAtAFgAoAHGAFgAWAATAFiAAICMgACAhwgICAiAGoBJCAiAAAjTADYANwAKBKEEogA8oKCAMd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwRQAFgAWABYAC0AWACgAccAWABYABMAWIAAgC6AAICHCAgICIAagEoICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAiAAEwRQAFgAWABYAC0AWACgAcgAWABYABMAWIAAgFWAAICHCAgICIAagEsICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwRQAFgAWABYAC0AWACgAckAWABYABMAWIAAgC6AAICHCAgICIAagEwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwRQAFgAWABYAC0AWACgAcoAWABYABMAWIAAgACAAICHCAgICIAagE0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwRQAFgAWABYAC0AWACgAcsAWABYABMAWIAAgC6AAICHCAgICIAagE4ICIAACNkAHQAhBPAACgAkBPEAHwBJBPIBiwGvAEoAaQATACUALQBYBPpfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAhIBEgAmAOIAAgAQIgJPTADYANwAKBPwFBAA8pwJpAmoCawJsAm0CbgJvgFuAXIBdgF6AX4BggGGnBQUFBgUHBQgFCQUKBQuAlICWgJeAmICagJuAnIAx3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMFDwATBFEAWABYAFgALQBYAKACaQBYAFgAEwBYgACAlYAAgJIICAgIgBqAWwgIgAAIUTDfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMEUQBYAFgAWAAtAFgAoAJqAFgAWAATAFiAAIAugACAkggICAiAGoBcCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEUQBYAFgAWAAtAFgAoAJrAFgAWAATAFiAAIAAgACAkggICAiAGoBdCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwU9ABMEUQBYAFgAWAAtAFgAoAJsAFgAWAATAFiAAICZgACAkggICAiAGoBeCAiAAAgRASzfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEUQBYAFgAWAAtAFgAoAJtAFgAWAATAFiAAIAAgACAkggICAiAGoBfCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEUQBYAFgAWAAtAFgAoAJuAFgAWAATAFiAAIAAgACAkggICAiAGoBgCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMEUQBYAFgAWAAtAFgAoAJvAFgAWAATAFiAAIAAgACAkggICAiAGoBhCAiAAAjfEBIAjgCPAJAFeQAdAJIAkwV6AB8AkQV7AJQACgAhAJUAlgAkAJcAEwATABMAJQA7AFgAWAWDAC0AWABKAFgBpQGFAFgAWAWLAFhfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWSAAIAAgACABIAHCAiAnwiACQiAaoA9CAiAnggSKZL7qdMANgA3AAoFjwWSADyiAa4Br4BDgESiBZMFlICggKuAMdkAHQAhBZcACgAkBZgAHwBJBZkBjAGuAEoAaQATACUALQBYBaFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAnYBDgAmAOIAAgAQIgKHTADYANwAKBaMFrAA8qAHEAcUBxgHHAcgByQHKAcuAR4BIgEmASoBLgEyATYBOqAWtBa4FrwWwBbEFsgWzBbSAooCjgKSApoCngKiAqYCqgDHfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMFkwBYAFgAWAAtAFgAoAHEAFgAWAATAFiAAIAugACAoAgICAiAGoBHCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMFkwBYAFgAWAAtAFgAoAHFAFgAWAATAFiAAIAAgACAoAgICAiAGoBICAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwXWABMFkwBYAFgAWAAtAFgAoAHGAFgAWAATAFiAAIClgACAoAgICAiAGoBJCAiAAAjTADYANwAKBeQF5QA8oKCAMd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwWTAFgAWABYAC0AWACgAccAWABYABMAWIAAgC6AAICgCAgICIAagEoICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATAiAAEwWTAFgAWABYAC0AWACgAcgAWABYABMAWIAAgFWAAICgCAgICIAagEsICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwWTAFgAWABYAC0AWACgAckAWABYABMAWIAAgC6AAICgCAgICIAagEwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwWTAFgAWABYAC0AWACgAcoAWABYABMAWIAAgACAAICgCAgICIAagE0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwWTAFgAWABYAC0AWACgAcsAWABYABMAWIAAgC6AAICgCAgICIAagE4ICIAACNkAHQAhBjMACgAkBjQAHwBJBjUBjAGvAEoAaQATACUALQBYBj1fECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAnYBEgAmAOIAAgAQIgKzTADYANwAKBj8GRwA8pwJpAmoCawJsAm0CbgJvgFuAXIBdgF6AX4BggGGnBkgGSQZKBksGTAZNBk6ArYCugK+AsICxgLKAs4Ax3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBZQAWABYAFgALQBYAKACaQBYAFgAEwBYgACAAIAAgKsICAgIgBqAWwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATBZQAWABYAFgALQBYAKACagBYAFgAEwBYgACALoAAgKsICAgIgBqAXAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBZQAWABYAFgALQBYAKACawBYAFgAEwBYgACAAIAAgKsICAgIgBqAXQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMCrwATBZQAWABYAFgALQBYAKACbABYAFgAEwBYgACAZoAAgKsICAgIgBqAXggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBZQAWABYAFgALQBYAKACbQBYAFgAEwBYgACAAIAAgKsICAgIgBqAXwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBZQAWABYAFgALQBYAKACbgBYAFgAEwBYgACAAIAAgKsICAgIgBqAYAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBZQAWABYAFgALQBYAKACbwBYAFgAEwBYgACAAIAAgKsICAgIgBqAYQgIgAAI3xASAI4AjwCQBroAHQCSAJMGuwAfAJEGvACUAAoAIQCVAJYAJACXABMAEwATACUAOwBYAFgGxAAtAFgASgBYAaUBhgBYAFgGzABYXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgLYIgAkIgGqAPggIgLUIEqf4upDTADYANwAKBtAG0wA8ogGuAa+AQ4BEogbUBtWAt4DCgDHZAB0AIQbYAAoAJAbZAB8ASQbaAY0BrgBKAGkAEwAlAC0AWAbiXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgLSAQ4AJgDiAAIAECIC40wA2ADcACgbkBu0APKgBxAHFAcYBxwHIAckBygHLgEeASIBJgEqAS4BMgE2ATqgG7gbvBvAG8QbyBvMG9Ab1gLmAuoC7gL2AvoC/gMCAwYAx3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATBtQAWABYAFgALQBYAKABxABYAFgAEwBYgACALoAAgLcICAgIgBqARwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATBtQAWABYAFgALQBYAKABxQBYAFgAEwBYgACAAIAAgLcICAgIgBqASAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMHFwATBtQAWABYAFgALQBYAKABxgBYAFgAEwBYgACAvIAAgLcICAgIgBqASQgIgAAI0wA2ADcACgclByYAPKCggDHfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMG1ABYAFgAWAAtAFgAoAHHAFgAWAATAFiAAIAugACAtwgICAiAGoBKCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwIgABMG1ABYAFgAWAAtAFgAoAHIAFgAWAATAFiAAIBVgACAtwgICAiAGoBLCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMG1ABYAFgAWAAtAFgAoAHJAFgAWAATAFiAAIAugACAtwgICAiAGoBMCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMG1ABYAFgAWAAtAFgAoAHKAFgAWAATAFiAAIAAgACAtwgICAiAGoBNCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMG1ABYAFgAWAAtAFgAoAHLAFgAWAATAFiAAIAugACAtwgICAiAGoBOCAiAAAjZAB0AIQd0AAoAJAd1AB8ASQd2AY0BrwBKAGkAEwAlAC0AWAd+XxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgLSARIAJgDiAAIAECIDD0wA2ADcACgeAB4gAPKcCaQJqAmsCbAJtAm4Cb4BbgFyAXYBegF+AYIBhpweJB4oHiweMB40HjgePgMSAxYDGgMeAyYDKgMuAMd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwbVAFgAWABYAC0AWACgAmkAWABYABMAWIAAgACAAIDCCAgICIAagFsICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwbVAFgAWABYAC0AWACgAmoAWABYABMAWIAAgC6AAIDCCAgICIAagFwICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwbVAFgAWABYAC0AWACgAmsAWABYABMAWIAAgACAAIDCCAgICIAagF0ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATB8AAEwbVAFgAWABYAC0AWACgAmwAWABYABMAWIAAgMiAAIDCCAgICIAagF4ICIAACBED6N8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwbVAFgAWABYAC0AWACgAm0AWABYABMAWIAAgACAAIDCCAgICIAagF8ICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwbVAFgAWABYAC0AWACgAm4AWABYABMAWIAAgACAAIDCCAgICIAagGAICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwbVAFgAWABYAC0AWACgAm8AWABYABMAWIAAgACAAIDCCAgICIAagGEICIAACN8QEgCOAI8AkAf8AB0AkgCTB/0AHwCRB/4AlAAKACEAlQCWACQAlwATABMAEwAlADsAWABYCAYALQBYAEoAWAGlAYcAWABYCA4AWF8QIFhEQnVja2V0Rm9yU3RlcmVvdHlwZXN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc3N0b3JhZ2VfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzb3JkZXJlZIAAgACAAIAEgAcICIDOCIAJCIBqgD8ICIDNCBK09YDQ0wA2ADcACggSCBUAPKIBrgGvgEOARKIIFggXgM+A2oAx2QAdACEIGgAKACQIGwAfAEkIHAGOAa4ASgBpABMAJQAtAFgIJF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDMgEOACYA4gACABAiA0NMANgA3AAoIJggvADyoAcQBxQHGAccByAHJAcoBy4BHgEiASYBKgEuATIBNgE6oCDAIMQgyCDMINAg1CDYIN4DRgNKA04DVgNaA14DYgNmAMd8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATASQAEwgWAFgAWABYAC0AWACgAcQAWABYABMAWIAAgC6AAIDPCAgICIAagEcICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATABMAEwgWAFgAWABYAC0AWACgAcUAWABYABMAWIAAgACAAIDPCAgICIAagEgICIAACN8QDwCOAI8AkAAdAJEAkgCTAB8AlAAKACEAlQCWACQAlwATCFkAEwgWAFgAWABYAC0AWACgAcYAWABYABMAWIAAgNSAAIDPCAgICIAagEkICIAACNMANgA3AAoIZwhoADygoIAx3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATCBYAWABYAFgALQBYAKABxwBYAFgAEwBYgACALoAAgM8ICAgIgBqASggIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATCBYAWABYAFgALQBYAKAByABYAFgAEwBYgACALoAAgM8ICAgIgBqASwgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATCBYAWABYAFgALQBYAKAByQBYAFgAEwBYgACALoAAgM8ICAgIgBqATAgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMAEwATCBYAWABYAFgALQBYAKABygBYAFgAEwBYgACAAIAAgM8ICAgIgBqATQgIgAAI3xAPAI4AjwCQAB0AkQCSAJMAHwCUAAoAIQCVAJYAJACXABMBJAATCBYAWABYAFgALQBYAKABywBYAFgAEwBYgACALoAAgM8ICAgIgBqATggIgAAI2QAdACEItgAKACQItwAfAEkIuAGOAa8ASgBpABMAJQAtAFgIwF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYDMgESACYA4gACABAiA29MANgA3AAoIwgjKADynAmkCagJrAmwCbQJuAm+AW4BcgF2AXoBfgGCAYacIywjMCM0IzgjPCNAI0YDcgN2A3oDfgOCA4YDigDHfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwUPABMIFwBYAFgAWAAtAFgAoAJpAFgAWAATAFiAAICVgACA2ggICAiAGoBbCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwEkABMIFwBYAFgAWAAtAFgAoAJqAFgAWAATAFiAAIAugACA2ggICAiAGoBcCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMIFwBYAFgAWAAtAFgAoAJrAFgAWAATAFiAAIAAgACA2ggICAiAGoBdCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwU9ABMIFwBYAFgAWAAtAFgAoAJsAFgAWAATAFiAAICZgACA2ggICAiAGoBeCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMIFwBYAFgAWAAtAFgAoAJtAFgAWAATAFiAAIAAgACA2ggICAiAGoBfCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMIFwBYAFgAWAAtAFgAoAJuAFgAWAATAFiAAIAAgACA2ggICAiAGoBgCAiAAAjfEA8AjgCPAJAAHQCRAJIAkwAfAJQACgAhAJUAlgAkAJcAEwATABMIFwBYAFgAWAAtAFgAoAJvAFgAWAATAFiAAIAAgACA2ggICAiAGoBhCAiAAAhaZHVwbGljYXRlc9IANwAKCT4AqKCAGdIAqgCrCUEJQlpYRFBNRW50aXR5pwlDCUQJRQlGCUcJSACvWlhEUE1FbnRpdHldWERVTUxDbGFzc0ltcF8QElhEVU1MQ2xhc3NpZmllckltcF8QEVhEVU1MTmFtZXNwYWNlSW1wXxAUWERVTUxOYW1lZEVsZW1lbnRJbXBfEA9YRFVNTEVsZW1lbnRJbXDTADYANwAKCUoJSwA8oKCAMdMANgA3AAoJTglPADygoIAx0wA2ADcACglSCVMAPKCggDHSAKoAqwlWCVdeWERNb2RlbFBhY2thZ2WmCVgJWQlaCVsJXACvXlhETW9kZWxQYWNrYWdlXxAPWERVTUxQYWNrYWdlSW1wXxARWERVTUxOYW1lc3BhY2VJbXBfEBRYRFVNTE5hbWVkRWxlbWVudEltcF8QD1hEVU1MRWxlbWVudEltcNIANwAKCV4AqKCAGdMANgA3AAoJYQliADygoIAxUNIAqgCrCWYJZ1lYRFBNTW9kZWyjCWYJaACvV1hETW9kZWxfEA9OU0tleWVkQXJjaGl2ZXLRCWsAKFRyb290gAEACAAZACIAKwA1ADoAPwIeAiQCQQJTAloCZwJ6ApICoAK6ArwCvgLAAsICxALGAsgDAQMgAz0DXANuA44DlQOzA78D2wPhBAMEJAQ3BDkEOwQ9BD8EQQRDBEUERwRJBEsETQRPBFEEUwRUBFgEZQRtBHgEewR9BIAEggSEBI0E0AT0BRgFOwViBYIFqQXQBfAGFAY4BkQGRgZIBkoGTAZOBlAGUgZUBlYGWAZaBlwGXgZgBmEGagZyBn8GggaEBocGiQaLBpoGvwbjBwoHLgcwBzIHNAc2BzgHOgc7Bz0HSgddB18HYQdjB2UHZwdpB2sHbQdvB4IHhAeGB4gHigeMB44HkAeSB5QHlgesB78H2wf4CBQIKAg6CFAIaQioCK4ItwjECNAI2gjkCO8I+gkHCQ8JEQkTCRUJFwkYCRkJGgkbCR0JHwkgCSEJIwkkCS0JLgkwCTkJRAlNCVwJYwlrCXQJfQmQCZkJrAnDCdUKFAoWChgKGgocCh0KHgofCiAKIgokCiUKJgooCikKaApqCmwKbgpwCnEKcgpzCnQKdgp4CnkKegp8Cn0KhgqHCokKyArKCswKzgrQCtEK0grTCtQK1grYCtkK2grcCt0LHAseCyALIgskCyULJgsnCygLKgssCy0LLgswCzELOgtDC0ULRwtJC0sLTQtiC3ULiAuQC5ILlAuWC5gLmgulC64LwQvGC9kL7gvwC/IL9Av2C/gMDQypDL4MwAzCDMQMxgzIDNENHQ0yDTQNNg04DToNPA1QDZ4N3Q3fDeEN4w3lDeYN5w3oDekN6w3tDe4N7w3xDfIN8w4yDjQONg44DjoOOw48Dj0OPg5ADkIOQw5EDkYORw5UDlUOVg5YDmEOdw5+DosOyg7MDs4O0A7SDtMO1A7VDtYO2A7aDtsO3A7eDt8O+A76DvwO/g7/DwEPGA8hDy8PPA9KD18Pcw+KD5wP2w/dD98P4Q/jD+QP5Q/mD+cP6Q/rD+wP7Q/vD/AQAhALECAQLxBEEFIQZxB7EJIQpBCxEL4QwBDCEMQQxhDIEMoQ1xDZENsQ3RDfEOEQ4xDlEP0REREjET0RSRFdEagRyxHrEgsSDRIPEhESExIVEhYSFxIZEhoSHBIdEh8SIRIiEiMSJRImEisSOBI9Ej8SQRJGEkgSShJMEmESdhKbEr8S5hMKEwwTDhMQExITFBMWExcTGRMmEzcTORM7Ez0TPxNBE0MTRRNHE1gTWhNcE14TYBNiE2QTZhNoE2oTiBOmE7kTzRPiE/8UExQpFGgUahRsFG4UcBRxFHIUcxR0FHYUeBR5FHoUfBR9FLwUvhTAFMIUxBTFFMYUxxTIFMoUzBTNFM4U0BTRFRAVEhUUFRYVGBUZFRoVGxUcFR4VIBUhFSIVJBUlFTIVMxU0FTYVdRV3FXkVexV9FX4VfxWAFYEVgxWFFYYVhxWJFYoVyRXLFc0VzxXRFdIV0xXUFdUV1xXZFdoV2xXdFd4V3xYeFiAWIhYkFiYWJxYoFikWKhYsFi4WLxYwFjIWMxZyFnQWdhZ4FnoWexZ8Fn0WfhaAFoIWgxaEFoYWhxbGFsgWyhbMFs4WzxbQFtEW0hbUFtYW1xbYFtoW2xcAFyQXSxdvF3EXcxd1F3cXeRd7F3wXfheLF5oXnBeeF6AXohekF6YXqBe3F7kXuxe9F78XwRfDF8UXxxfnGBIYLBhFGF8YfxiiGOEY4xjlGOcY6RjqGOsY7BjtGO8Y8RjyGPMY9Rj2GTUZNxk5GTsZPRk+GT8ZQBlBGUMZRRlGGUcZSRlKGYkZixmNGY8ZkRmSGZMZlBmVGZcZmRmaGZsZnRmeGd0Z3xnhGeMZ5RnmGecZ6BnpGesZ7RnuGe8Z8RnyGfUaNBo2GjgaOho8Gj0aPho/GkAaQhpEGkUaRhpIGkkaiBqKGowajhqQGpEakhqTGpQalhqYGpkamhqcGp0a3BreGuAa4hrkGuUa5hrnGuga6hrsGu0a7hrwGvEa+hsIGxUbIxswG0MbWhtsG7cb2hv6HBocHBweHCAcIhwkHCUcJhwoHCkcKxwsHC4cMBwxHDIcNBw1HDocRxxMHE4cUBxVHFccWRxbHIAcpBzLHO8c8RzzHPUc9xz5HPsc/Bz+HQsdHB0eHSAdIh0kHSYdKB0qHSwdPR0/HUEdQx1FHUcdSR1LHU0dTx2OHZAdkh2UHZYdlx2YHZkdmh2cHZ4dnx2gHaIdox3iHeQd5h3oHeod6x3sHe0d7h3wHfId8x30HfYd9x42HjgeOh48Hj4ePx5AHkEeQh5EHkYeRx5IHkoeSx5YHlkeWh5cHpsenR6fHqEeox6kHqUeph6nHqkeqx6sHq0erx6wHu8e8R7zHvUe9x74Hvke+h77Hv0e/x8AHwEfAx8EH0MfRR9HH0kfSx9MH00fTh9PH1EfUx9UH1UfVx9YH5cfmR+bH50fnx+gH6Efoh+jH6Ufpx+oH6kfqx+sH+sf7R/vH/Ef8x/0H/Uf9h/3H/kf+x/8H/0f/yAAICUgSSBwIJQgliCYIJognCCeIKAgoSCjILAgvyDBIMMgxSDHIMkgyyDNINwg3iDgIOIg5CDmIOgg6iDsISshLSEvITEhMyE0ITUhNiE3ITkhOyE8IT0hPyFAIUQhgyGFIYchiSGLIYwhjSGOIY8hkSGTIZQhlSGXIZgh1yHZIdsh3SHfIeAh4SHiIeMh5SHnIegh6SHrIewiKyItIi8iMSIzIjQiNSI2IjciOSI7IjwiPSI/IkAiQyKCIoQihiKIIooiiyKMIo0ijiKQIpIikyKUIpYilyLWItgi2iLcIt4i3yLgIuEi4iLkIuYi5yLoIuoi6yMqIywjLiMwIzIjMyM0IzUjNiM4IzojOyM8Iz4jPyOKI60jzSPtI+8j8SPzI/Uj9yP4I/kj+yP8I/4j/yQBJAMkBCQFJAckCCQNJBokHyQhJCMkKCQqJCwkLiRTJHckniTCJMQkxiTIJMokzCTOJM8k0STeJO8k8STzJPUk9yT5JPsk/ST/JRAlEiUUJRYlGCUaJRwlHiUgJSIlYSVjJWUlZyVpJWolayVsJW0lbyVxJXIlcyV1JXYltSW3JbkluyW9Jb4lvyXAJcElwyXFJcYlxyXJJcomCSYLJg0mDyYRJhImEyYUJhUmFyYZJhomGyYdJh4mKyYsJi0mLyZuJnAmciZ0JnYmdyZ4JnkmeiZ8Jn4mfyaAJoImgybCJsQmxibIJsomyybMJs0mzibQJtIm0ybUJtYm1ycWJxgnGiccJx4nHycgJyEnIickJyYnJycoJyonKydqJ2wnbidwJ3Incyd0J3Undid4J3oneyd8J34nfye+J8AnwifEJ8YnxyfIJ8knyifMJ84nzyfQJ9In0yf4KBwoQyhnKGkoayhtKG8ocShzKHQodiiDKJIolCiWKJgomiicKJ4ooCivKLEosyi1KLcouSi7KL0ovyj+KQApAikEKQYpBykIKQkpCikMKQ4pDykQKRIpEykVKVQpVilYKVopXCldKV4pXylgKWIpZCllKWYpaClpKagpqimsKa4psCmxKbIpsym0KbYpuCm5KbopvCm9Kfwp/ioAKgIqBCoFKgYqByoIKgoqDCoNKg4qECoRKhQqUypVKlcqWSpbKlwqXSpeKl8qYSpjKmQqZSpnKmgqpyqpKqsqrSqvKrAqsSqyKrMqtSq3KrgquSq7Krwq+yr9Kv8rASsDKwQrBSsGKwcrCSsLKwwrDSsPKxArWyt+K54rvivAK8IrxCvGK8grySvKK8wrzSvPK9Ar0ivUK9Ur1ivYK9kr3ivrK/Ar8iv0K/kr+yv9K/8sJCxILG8skyyVLJcsmSybLJ0snyygLKIsryzALMIsxCzGLMgsyizMLM4s0CzhLOMs5SznLOks6yztLO8s8SzzLTItNC02LTgtOi07LTwtPS0+LUAtQi1DLUQtRi1HLYYtiC2KLYwtji2PLZAtkS2SLZQtli2XLZgtmi2bLdot3C3eLeAt4i3jLeQt5S3mLegt6i3rLewt7i3vLfwt/S3+LgAuPy5BLkMuRS5HLkguSS5KLksuTS5PLlAuUS5TLlQuky6VLpcumS6bLpwunS6eLp8uoS6jLqQupS6nLqgu5y7pLusu7S7vLvAu8S7yLvMu9S73Lvgu+S77LvwvOy89Lz8vQS9DL0QvRS9GL0cvSS9LL0wvTS9PL1Avjy+RL5MvlS+XL5gvmS+aL5svnS+fL6AvoS+jL6QvyS/tMBQwODA6MDwwPjBAMEIwRDBFMEcwVDBjMGUwZzBpMGswbTBvMHEwgDCCMIQwhjCIMIowjDCOMJAwzzDRMNMw1TDXMNgw2TDaMNsw3TDfMOAw4TDjMOQxIzElMScxKTErMSwxLTEuMS8xMTEzMTQxNTE3MTgxdzF5MXsxfTF/MYAxgTGCMYMxhTGHMYgxiTGLMYwxyzHNMc8x0THTMdQx1THWMdcx2THbMdwx3THfMeAyHzIhMiMyJTInMigyKTIqMisyLTIvMjAyMTIzMjQyczJ1MncyeTJ7MnwyfTJ+Mn8ygTKDMoQyhTKHMogyxzLJMssyzTLPMtAy0TLSMtMy1TLXMtgy2TLbMtwzJzNKM2ozijOMM44zkDOSM5QzlTOWM5gzmTObM5wznjOgM6EzojOkM6UzqjO3M7wzvjPAM8UzxzPJM8sz8DQUNDs0XzRhNGM0ZTRnNGk0azRsNG40ezSMNI40kDSSNJQ0ljSYNJo0nDStNK80sTSzNLU0tzS5NLs0vTS/NP41ADUCNQQ1BjUHNQg1CTUKNQw1DjUPNRA1EjUTNVI1VDVWNVg1WjVbNVw1XTVeNWA1YjVjNWQ1ZjVnNaY1qDWqNaw1rjWvNbA1sTWyNbQ1tjW3Nbg1ujW7Ncg1yTXKNcw2CzYNNg82ETYTNhQ2FTYWNhc2GTYbNhw2HTYfNiA2XzZhNmM2ZTZnNmg2aTZqNms2bTZvNnA2cTZzNnQ2sza1Nrc2uTa7Nrw2vTa+Nr82wTbDNsQ2xTbHNsg3BzcJNws3DTcPNxA3ETcSNxM3FTcXNxg3GTcbNxw3WzddN183YTdjN2Q3ZTdmN2c3aTdrN2w3bTdvN3A3lTe5N+A4BDgGOAg4CjgMOA44EDgROBM4IDgvODE4Mzg1ODc4OTg7OD04TDhOOFA4UjhUOFY4WDhaOFw4mzidOJ84oTijOKQ4pTimOKc4qTirOKw4rTivOLA47zjxOPM49Tj3OPg4+Tj6OPs4/Tj/OQA5ATkDOQQ5QzlFOUc5STlLOUw5TTlOOU85UTlTOVQ5VTlXOVg5lzmZOZs5nTmfOaA5oTmiOaM5pTmnOag5qTmrOaw5rznuOfA58jn0OfY59zn4Ofk5+jn8Of45/zoAOgI6AzpCOkQ6RjpIOko6SzpMOk06TjpQOlI6UzpUOlY6VzqWOpg6mjqcOp46nzqgOqE6ojqkOqY6pzqoOqo6qzr2Oxk7OTtZO1s7XTtfO2E7YztkO2U7ZztoO2o7azttO287cDtxO3M7dDt5O4Y7izuNO487lDuWO5g7mju/O+M8CjwuPDA8Mjw0PDY8ODw6PDs8PTxKPFs8XTxfPGE8YzxlPGc8aTxrPHw8fjyAPII8hDyGPIg8ijyMPI48zTzPPNE80zzVPNY81zzYPNk82zzdPN483zzhPOI9IT0jPSU9Jz0pPSo9Kz0sPS09Lz0xPTI9Mz01PTY9dT13PXk9ez19PX49fz2APYE9gz2FPYY9hz2JPYo9lz2YPZk9mz3aPdw93j3gPeI94z3kPeU95j3oPeo96z3sPe497z4uPjA+Mj40PjY+Nz44Pjk+Oj48Pj4+Pz5APkI+Qz6CPoQ+hj6IPoo+iz6MPo0+jj6QPpI+kz6UPpY+lz7WPtg+2j7cPt4+3z7gPuE+4j7kPuY+5z7oPuo+6z8qPyw/Lj8wPzI/Mz80PzU/Nj84Pzo/Oz88Pz4/Pz9kP4g/rz/TP9U/1z/ZP9s/3T/fP+A/4j/vP/5AAEACQARABkAIQApADEAbQB1AH0AhQCNAJUAnQClAK0BqQGxAbkBwQHJAc0B0QHVAdkB4QHpAe0B8QH5Af0C+QMBAwkDEQMZAx0DIQMlAykDMQM5Az0DQQNJA00ESQRRBFkEYQRpBG0EcQR1BHkEgQSJBI0EkQSZBJ0FmQWhBakFsQW5Bb0FwQXFBckF0QXZBd0F4QXpBe0G6QbxBvkHAQcJBw0HEQcVBxkHIQcpBy0HMQc5Bz0IOQhBCEkIUQhZCF0IYQhlCGkIcQh5CH0IgQiJCI0JiQmRCZkJoQmpCa0JsQm1CbkJwQnJCc0J0QnZCd0KCQotCjEKOQpdCokKxQrxCykLfQvNDCkMcQylDKkMrQy1DOkM7QzxDPkNLQ0xDTUNPQ1hDZ0N0Q4NDlUOpQ8BD0kPbQ9xD3kPrQ+xD7UPvQ/BD+UQDRApEEkQkRClELgAAAAAAAAICAAAAAAAACW0AAAAAAAAAAAAAAAAAAEQw\n</attribute>\n        <relationship name=\"entitymappings\" type=\"0/0\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z104\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGODlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKwH\nCBMUGRoiJywtMDRVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAtfEBB2YWx1ZUZvcktleVBhdGg60xULDRYXGFpOU1ZhcmlhYmxlgAQQAoAFVnNvdXJjZdIbHB0eWiRjbGFzc25hbWVYJGNsYXNzZXNfEBROU1ZhcmlhYmxlRXhwcmVzc2lvbqMfICFfEBROU1ZhcmlhYmxlRXhwcmVzc2lvblxOU0V4cHJlc3Npb25YTlNPYmplY3TSIw0kJlpOUy5vYmplY3RzoSWAB4AK0w0LKCkqK1lOU0tleVBhdGiACRAKgAhcY3JlYXRpb25EYXRl0hscLi9fEBxOU0tleVBhdGhTcGVjaWZpZXJFeHByZXNzaW9uoy4gIdIbHDEyXk5TTXV0YWJsZUFycmF5ozEzIVdOU0FycmF50hscNTZfEBNOU0tleVBhdGhFeHByZXNzaW9upDU3ICFfEBROU0Z1bmN0aW9uRXhwcmVzc2lvbl8QD05TS2V5ZWRBcmNoaXZlctE6O1Ryb290gAEACAARABoAIwAtADIANwBEAEoAVQBfAG4AgQCNAJQAlgCYAJoAnACeALEAuADDAMUAxwDJANAA1QDgAOkBAAEEARsBKAExATYBQQFDAUUBRwFOAVgBWgFcAV4BawFwAY8BkwGYAacBqwGzAbgBzgHTAeoB/AH/AgQAAAAAAAACAQAAAAAAAAA8AAAAAAAAAAAAAAAAAAACBg==\n</attribute>\n        <attribute name=\"name\" type=\"string\">entryCreationDate</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z105\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGODlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKwH\nCBMUGRoiJywtMDRVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAtfEBB2YWx1ZUZvcktleVBhdGg60xULDRYXGFpOU1ZhcmlhYmxlgAQQAoAFVnNvdXJjZdIbHB0eWiRjbGFzc25hbWVYJGNsYXNzZXNfEBROU1ZhcmlhYmxlRXhwcmVzc2lvbqMfICFfEBROU1ZhcmlhYmxlRXhwcmVzc2lvblxOU0V4cHJlc3Npb25YTlNPYmplY3TSIw0kJlpOUy5vYmplY3RzoSWAB4AK0w0LKCkqK1lOU0tleVBhdGiACRAKgAhUZGF0YdIbHC4vXxAcTlNLZXlQYXRoU3BlY2lmaWVyRXhwcmVzc2lvbqMuICHSGxwxMl5OU011dGFibGVBcnJheaMxMyFXTlNBcnJhedIbHDU2XxATTlNLZXlQYXRoRXhwcmVzc2lvbqQ1NyAhXxAUTlNGdW5jdGlvbkV4cHJlc3Npb25fEA9OU0tleWVkQXJjaGl2ZXLROjtUcm9vdIABAAgAEQAaACMALQAyADcARABKAFUAXwBuAIEAjQCUAJYAmACaAJwAngCxALgAwwDFAMcAyQDQANUA4ADpAQABBAEbASgBMQE2AUEBQwFFAUcBTgFYAVoBXAFeAWMBaAGHAYsBkAGfAaMBqwGwAcYBywHiAfQB9wH8AAAAAAAAAgEAAAAAAAAAPAAAAAAAAAAAAAAAAAAAAf4=\n</attribute>\n        <attribute name=\"name\" type=\"string\">logLineData</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z106\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGODlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKwH\nCBMUGRoiJywtMDRVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAtfEBB2YWx1ZUZvcktleVBhdGg60xULDRYXGFpOU1ZhcmlhYmxlgAQQAoAFVnNvdXJjZdIbHB0eWiRjbGFzc25hbWVYJGNsYXNzZXNfEBROU1ZhcmlhYmxlRXhwcmVzc2lvbqMfICFfEBROU1ZhcmlhYmxlRXhwcmVzc2lvblxOU0V4cHJlc3Npb25YTlNPYmplY3TSIw0kJlpOUy5vYmplY3RzoSWAB4AK0w0LKCkqK1lOU0tleVBhdGiACRAKgAhZY2hhbm5lbElk0hscLi9fEBxOU0tleVBhdGhTcGVjaWZpZXJFeHByZXNzaW9uoy4gIdIbHDEyXk5TTXV0YWJsZUFycmF5ozEzIVdOU0FycmF50hscNTZfEBNOU0tleVBhdGhFeHByZXNzaW9upDU3ICFfEBROU0Z1bmN0aW9uRXhwcmVzc2lvbl8QD05TS2V5ZWRBcmNoaXZlctE6O1Ryb290gAEACAARABoAIwAtADIANwBEAEoAVQBfAG4AgQCNAJQAlgCYAJoAnACeALEAuADDAMUAxwDJANAA1QDgAOkBAAEEARsBKAExATYBQQFDAUUBRwFOAVgBWgFcAV4BaAFtAYwBkAGVAaQBqAGwAbUBywHQAecB+QH8AgEAAAAAAAACAQAAAAAAAAA8AAAAAAAAAAAAAAAAAAACAw==\n</attribute>\n        <attribute name=\"name\" type=\"string\">logLineViewIdentifier</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z107\">\n        <attribute name=\"migrationpolicyclassname\" type=\"string\">HLSHistoricLogLineEntityMigration</attribute>\n        <attribute name=\"sourcename\" type=\"string\">LogLine</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">1</attribute>\n        <attribute name=\"destinationname\" type=\"string\">LogLine2</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\" idrefs=\"z103\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\" idrefs=\"z104 z120 z108 z102 z106 z105\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z108\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGODlYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKwH\nCBMUGRoiJywtMDRVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAtfEBB2YWx1ZUZvcktleVBhdGg60xULDRYXGFpOU1ZhcmlhYmxlgAQQAoAFVnNvdXJjZdIbHB0eWiRjbGFzc25hbWVYJGNsYXNzZXNfEBROU1ZhcmlhYmxlRXhwcmVzc2lvbqMfICFfEBROU1ZhcmlhYmxlRXhwcmVzc2lvblxOU0V4cHJlc3Npb25YTlNPYmplY3TSIw0kJlpOUy5vYmplY3RzoSWAB4AK0w0LKCkqK1lOU0tleVBhdGiACRAKgAhSaWTSGxwuL18QHE5TS2V5UGF0aFNwZWNpZmllckV4cHJlc3Npb26jLiAh0hscMTJeTlNNdXRhYmxlQXJyYXmjMTMhV05TQXJyYXnSGxw1Nl8QE05TS2V5UGF0aEV4cHJlc3Npb26kNTcgIV8QFE5TRnVuY3Rpb25FeHByZXNzaW9uXxAPTlNLZXllZEFyY2hpdmVy0To7VHJvb3SAAQAIABEAGgAjAC0AMgA3AEQASgBVAF8AbgCBAI0AlACWAJgAmgCcAJ4AsQC4AMMAxQDHAMkA0ADVAOAA6QEAAQQBGwEoATEBNgFBAUMBRQFHAU4BWAFaAVwBXgFhAWYBhQGJAY4BnQGhAakBrgHEAckB4AHyAfUB+gAAAAAAAAIBAAAAAAAAADwAAAAAAAAAAAAAAAAAAAH8\n</attribute>\n        <attribute name=\"name\" type=\"string\">entryIdentifier</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z109\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z110\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z111\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z112\">\n        <attribute name=\"sourcename\" type=\"string\">LogLine</attribute>\n        <attribute name=\"name\" type=\"string\">Mapping</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">2</attribute>\n        <attribute name=\"destinationname\" type=\"string\">LogLine2</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\" idrefs=\"z114\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z113\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z114\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z112\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z115\">\n        <attribute name=\"sourcename\" type=\"string\">LogLine</attribute>\n        <attribute name=\"name\" type=\"string\">Mapping</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">3</attribute>\n        <attribute name=\"destinationname\" type=\"string\">LogLine2</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z116\">\n        <attribute name=\"name\" type=\"string\">Mapping1</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">2</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z117\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z118\">\n        <attribute name=\"name\" type=\"string\">Mapping</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">3</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\" idrefs=\"z122\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z119\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z120\">\n        <attribute name=\"valueexpressiondata\" type=\"binary\">YnBsaXN0MDDUAQIDBAUGLC1YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoKkH\nCBMUGRoiJilVJG51bGzVCQoLDA0ODxAREllOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzViRjbGFzc4ADgAIQBIAGgAhfEBRuZXdTZXNzaW9uSWRlbnRpZmllctMVCw0WFxhaTlNWYXJpYWJsZYAEEAKABVxlbnRpdHlQb2xpY3nSGxwdHlokY2xhc3NuYW1lWCRjbGFzc2VzXxAUTlNWYXJpYWJsZUV4cHJlc3Npb26jHyAhXxAUTlNWYXJpYWJsZUV4cHJlc3Npb25cTlNFeHByZXNzaW9uWE5TT2JqZWN00iMNJCVaTlMub2JqZWN0c6CAB9IbHCcoV05TQXJyYXmiJyHSGxwqK18QFE5TRnVuY3Rpb25FeHByZXNzaW9uoyogIV8QD05TS2V5ZWRBcmNoaXZlctEuL1Ryb290gAEACAARABoAIwAtADIANwBBAEcAUgBcAGsAfgCKAJEAkwCVAJcAmQCbALIAuQDEAMYAyADKANcA3ADnAPABBwELASIBLwE4AT0BSAFJAUsBUAFYAVsBYAF3AXsBjQGQAZUAAAAAAAACAQAAAAAAAAAwAAAAAAAAAAAAAAAAAAABlw==\n</attribute>\n        <attribute name=\"name\" type=\"string\">sessionIdentifier</attribute>\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z107\"></relationship>\n    </object>\n    <object type=\"XDDEVENTITYMAPPING\" id=\"z121\">\n        <attribute name=\"name\" type=\"string\">Mapping1</attribute>\n        <attribute name=\"mappingtypename\" type=\"string\">Undefined</attribute>\n        <attribute name=\"mappingnumber\" type=\"int16\">2</attribute>\n        <attribute name=\"autogenerateexpression\" type=\"bool\">1</attribute>\n        <relationship name=\"mappingmodel\" type=\"1/1\" destination=\"XDDEVMAPPINGMODEL\"></relationship>\n        <relationship name=\"attributemappings\" type=\"0/0\" destination=\"XDDEVATTRIBUTEMAPPING\"></relationship>\n        <relationship name=\"relationshipmappings\" type=\"0/0\" destination=\"XDDEVRELATIONSHIPMAPPING\"></relationship>\n    </object>\n    <object type=\"XDDEVATTRIBUTEMAPPING\" id=\"z122\">\n        <relationship name=\"entitymapping\" type=\"1/1\" destination=\"XDDEVENTITYMAPPING\" idrefs=\"z118\"></relationship>\n    </object>\n</database>"
  },
  {
    "path": "XPC Services/Historic Log File Manager/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>Historic Log File Manager</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>XPC!</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2016 - 2018 Codeux Software, LLC. All rights reserved.</string>\n\t<key>XPCService</key>\n\t<dict>\n\t\t<key>ServiceType</key>\n\t\t<string>Application</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/IRCConnectionPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"RCMConnectionManagerProtocol.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface IRCConnection : NSObject\n- (instancetype)initWithConfig:(IRCConnectionConfig *)config onConnection:(NSXPCConnection *)connection NS_DESIGNATED_INITIALIZER;\n\n- (void)open;\n- (void)close;\n\n- (void)sendData:(NSData *)data bypassQueue:(BOOL)bypassQueue;\n\n- (void)enforceFloodControl;\n\n- (void)clearSendQueue;\n\n- (BOOL)exportSecureConnectionInformation:(RCMSecureConnectionInformationCompletionBlock)completionBlock error:(NSError * _Nullable * _Nullable)error;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/RCMConnectionManagerProtocol.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* *** XPC PROTOCOL HEADERS ARE PRIVATE *** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class IRCConnectionConfig;\n\ntypedef void (^RCMSecureConnectionInformationCompletionBlock)(\n\t\t\t\t\t\t\t\t\t\tNSString * _Nullable policyName,\n\t\t\t\t\t\t\t\t\t\ttls_protocol_version_t ptocoolType,\n\t\t\t\t\t\t\t\t\t\ttls_ciphersuite_t cipherSuites,\n\t\t\t\t\t\t\t\t\t\tNSArray<NSData *> *certificateChain);\n\n#pragma mark -\n#pragma mark Server Protocol\n\n/* The server protocol is what the daemon responds to. */\n@protocol RCMConnectionManagerServerProtocol\n@required\n\n- (void)openWithConfig:(IRCConnectionConfig *)config;\n- (void)close;\n\n/* -sendData: does not append \\r\\n. It is assumed client does that. */\n- (void)sendData:(NSData *)data;\n- (void)sendData:(NSData *)data bypassQueue:(BOOL)bypassQueue;\n\n- (void)exportSecureConnectionInformation:(NS_NOESCAPE RCMSecureConnectionInformationCompletionBlock)completionBlock;\n\n- (void)enforceFloodControl;\n\n- (void)clearSendQueue;\n\n#pragma mark -\n#pragma mark Resource Usage\n\n- (void)enableAppNap;\n- (void)disableAppNap;\n\n- (void)enableSuddenTermination;\n- (void)disableSuddenTermination;\n@end\n\n#pragma mark -\n#pragma mark Client Protocol\n\n/* The client protocol is what Textual (the client) implements\n so that the daemon can communicate state with it. */\n@protocol RCMConnectionManagerClientProtocol\n@required\n\n- (void)ircConnectionWillConnectToProxy:(NSString *)proxyHost port:(uint16_t)proxyPort;\n\n/* host is nil if we are connected to a proxy because we do not have enough context\n at the point this delegate method is called to know where the proxy itself connected. */\n- (void)ircConnectionDidConnectToHost:(nullable NSString *)host;\n- (void)ircConnectionDidSecureConnectionWithProtocolType:(tls_protocol_version_t)protocolType\n\t\t\t\t\t\t\t\t\t\t\t cipherSuite:(tls_ciphersuite_t)cipherSuite;\n- (void)ircConnectionDidCloseReadStream;\n- (void)ircConnectionDidDisconnectWithError:(nullable NSError *)disconnectError;\n- (void)ircConnectionDidReceiveData:(NSData *)data;\n- (void)ircConnectionRequestInsecureCertificateTrust:(RCMTrustResponse)trustBlock;\n- (void)ircConnectionWillSendData:(NSData *)data;\n- (void)ircConnectionDidSendData;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/RCMProcessDelegatePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface RCMProcessDelegate : NSObject <NSXPCListenerDelegate>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/RCMProcessMainPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface RCMProcessMain : NSObject <RCMConnectionManagerServerProtocol>\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithXPCConnection:(NSXPCConnection *)connection NS_DESIGNATED_INITIALIZER;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/RCMProcessPCHPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CocoaExtensions/CocoaExtensions.h>\n\n#import <Security/Security.h>\n\n#import <SystemConfiguration/SystemConfiguration.h>\n\n#import \"StaticDefinitions.h\"\n#import \"GCDAsyncSocket.h\"\n#import \"GCDAsyncSocketExtensions.h\"\n#import \"NSObjectHelperPrivate.h\"\n#import \"TLOLocalization.h\"\n#import \"TLOTimer.h\"\n#import \"IRCConnectionConfig.h\"\n#import \"IRCConnectionErrors.h\"\n#import \"IRCConnectionPrivate.h\"\n#import \"RCMConnectionManagerProtocol.h\"\n#import \"RCMProcessDelegatePrivate.h\"\n#import \"RCMProcessMainPrivate.h\"\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"RCMProcessPCHPrivate.h\"\n\n#import <os/log.h>\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/IRC/IRCConnection.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n* Copyright (c) 2018 - 2020 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n@objc(IRCConnection)\nfinal class Connection: NSObject, ConnectionSocketDelegate\n{\n\tfileprivate let config: IRCConnectionConfig\n\n\tfileprivate let socket: ConnectionSocket & ConnectionSocketProtocol\n\n\tfileprivate let serviceConnection: NSXPCConnection\n\n\tfileprivate var sendQueue: [Data] = []\n\n\tfileprivate lazy var floodControlTimer: TLOTimer =\n\t{\n\t\treturn TLOTimer(actionBlock: { [weak self] _ in\n\t\t\tself?.onFloodControlTimer()\n\t\t}, on: DispatchQueue.global(qos: .default))\n\t}()\n\n\tfileprivate var floodControlCurrentMessageCount = 0\n\tfileprivate var floodControlEnforced = false\n\n\tfileprivate var workerQueue: DispatchQueue?\n\n\tfileprivate var disconnectingManually = false\n\n\tenum ConnectionError : Error\n\t{\n\t\t/// socketError are errors returned by the connection library.\n\t\t/// For example: GCDAsyncSocket, Network.framework, etc.\n\t\tcase socket(error: Error)\n\n\t\t// otherError are errors returned by ConnectionSocket instances.\n\t\tcase other(message: String)\n\n\t\t/// invalidCertificate are errors returned when the connection\n\t\t/// cannot be secured because of problem with certificate.\n\t\tcase badCertificate(failureReason: String)\n\n\t\t/// unableToSecure are errors returned when the connection\n\t\t/// cannot be secured for some reason. e.g. handshake failure\n\t\tcase unableToSecure(failureReason: String)\n\t} // ConnectionError\n\n\t// MARK: - Initialization\n\n\t@objc(initWithConfig:onConnection:)\n\tinit (with config: IRCConnectionConfig, on connection: NSXPCConnection)\n\t{\n\t\tself.config = config\n\n\t\tsocket = ConnectionSocket.socket(with: config)\n\n\t\tserviceConnection = connection\n\n\t\tsuper.init()\n\n\t\tsocket.delegate = self\n\t}\n\n\t// MARK: - Grand Central Dispatch\n\n\tfileprivate func destroyWorkerDispatchQueue()\n\t{\n\t\tworkerQueue = nil\n\t}\n\n\tfileprivate func createWorkerDispatchQueue()\n\t{\n\t\tlet workerQueueName = \"Textual.IRCConnection.workerQueue.\\(socket.uniqueIdentifier)\"\n\n\t\tworkerQueue = DispatchQueue(label: workerQueueName)\n\t}\n\n\t// MARK: - Open/Close\n\n\t@objc\n\tfinal func open()\n\t{\n\t\tLogging.defaultSubsystem?.debug(\"Opening connection \\(self.socket.uniqueIdentifier, privacy: .public)...\")\n\n\t\tif (socket.disconnected == false) {\n\t\t\tLogging.defaultSubsystem?.error(\"Already connected\")\n\n\t\t\treturn\n\t\t}\n\n\t\tcreateWorkerDispatchQueue()\n\n\t\tstartFloodControlTimer()\n\n\t\tdisconnectingManually = true\n\n\t\tsocket.open()\n\t}\n\n\t@objc\n\tfinal func close()\n\t{\n\t\tLogging.defaultSubsystem?.debug(\"Closing connection \\(self.socket.uniqueIdentifier, privacy: .public)...\")\n\n\t\tif (socket.disconnected) {\n\t\t\tLogging.defaultSubsystem?.error(\"Not connected\")\n\n\t\t\treturn\n\t\t}\n\n\t\tfloodControlEnforced = false\n\n\t\tclearSendQueue()\n\n\t\tstopFloodControlTimer()\n\n\t\tdisconnectingManually = true\n\n\t\tsocket.close()\n\t}\n\n\tfinal func resetState()\n\t{\n\t\t/* Method invoked when a disconnect occurs. */\n\t\t/* disconnectingManually prevents us doing redundant work. */\n\t\tif (disconnectingManually) {\n\t\t\tdisconnectingManually = false\n\t\t} else {\n\t\t\tfloodControlEnforced = false\n\n\t\t\tclearSendQueue()\n\n\t\t\tstopFloodControlTimer()\n\t\t}\n\n\t\tdestroyWorkerDispatchQueue()\n\t}\n\n\t// MARK: - Send Queue\n\n\tfileprivate var sendQueueCount: Int\n\t{\n\t\tvar sendQueueCount = 0\n\n\t\tworkerQueue?.sync {\n\t\t\tsendQueueCount = sendQueue.count\n\t\t}\n\n\t\treturn sendQueueCount\n\t}\n\n\tfileprivate func nextEntryInSendQueue() -> Data?\n\t{\n\t\tvar nextEntry: Data?\n\n\t\tworkerQueue?.sync {\n\t\t\tnextEntry = sendQueue.first\n\t\t}\n\n\t\treturn nextEntry\n\t}\n\n\tfileprivate func sendQueue(add data: Data)\n\t{\n\t\tworkerQueue?.sync {\n\t\t\tsendQueue.append(data)\n\t\t}\n\t}\n\n\tfileprivate func sendQueue(remove data: Data)\n\t{\n\t\tworkerQueue?.sync {\n\t\t\tif let index = sendQueue.firstIndex(of: data) {\n\t\t\t\tsendQueue.remove(at: index)\n\t\t\t}\n\t\t}\n\t}\n\n\t@objc\n\tfinal func clearSendQueue()\n\t{\n\t\tworkerQueue?.sync {\n\t\t\tsendQueue.removeAll()\n\t\t}\n\t}\n\n\t@discardableResult\n\tfileprivate func tryToSend() -> Bool\n\t{\n\t\tif (socket.sending) {\n\t\t\treturn false\n\t\t}\n\n\t\tif (sendQueueCount == 0) {\n\t\t\treturn false\n\t\t}\n\n\t\tif (floodControlEnforced) {\n\t\t\tif (floodControlCurrentMessageCount >= config.floodControlMaximumMessages) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\n\t\tfloodControlCurrentMessageCount += 1\n\n\t\tsendNextLine()\n\n\t\treturn true\n\t}\n\n\tfileprivate func sendNextLine()\n\t{\n\t\tguard let line = nextEntryInSendQueue() else {\n\t\t\treturn\n\t\t}\n\n\t\tsend(line, removeFromQueue: true)\n\t}\n\n\t@objc(sendData:bypassQueue:)\n\tfinal func send(_ data: Data, bypassQueue: Bool = false)\n\t{\n\t\tif (socket.disconnected) {\n\t\t\tLogging.defaultSubsystem?.error(\"Cannot send data while disconnected\")\n\n\t\t\treturn\n\t\t}\n\n\t\tif (bypassQueue) {\n\t\t\tsend(data, removeFromQueue: false)\n\n\t\t\treturn\n\t\t}\n\n\t\tsendQueue(add: data)\n\n\t\ttryToSend()\n\t}\n\n\tfileprivate func send(_ data: Data, removeFromQueue: Bool = false)\n\t{\n\t\tif (removeFromQueue) {\n\t\t\tsendQueue(remove: data)\n\t\t}\n\n\t\tsocket.write(data)\n\t}\n\n\t// MARK: - Flood Control\n\n\t@objc\n\tfinal func enforceFloodControl()\n\t{\n\t\tfloodControlEnforced = true\n\t}\n\n\tfileprivate func startFloodControlTimer()\n\t{\n\t\tif (floodControlTimer.timerIsActive) {\n\t\t\treturn\n\t\t}\n\n\t\tlet timerInterval = Double(config.floodControlDelayInterval)\n\n\t\tfloodControlTimer.start(timerInterval, onRepeat: true)\n\t}\n\n\tfileprivate func stopFloodControlTimer()\n\t{\n\t\tif (floodControlTimer.timerIsActive == false) {\n\t\t\treturn\n\t\t}\n\n\t\tfloodControlTimer.stop()\n\t}\n\n\tfileprivate func onFloodControlTimer()\n\t{\n\t\tfloodControlCurrentMessageCount = 0\n\n\t\twhile (tryToSend()) {\n\n\t\t}\n\t}\n\n\t// MARK: - Socket Proxy\n\n\t@objc(exportSecureConnectionInformation:error:)\n\tfinal func exportSecureConnectionInformation(to receiver: RCMSecureConnectionInformationCompletionBlock) throws\n\t{\n\t\ttry socket.exportSecureConnectionInformation(to: receiver)\n\t}\n\n\t// MARK: - Socket Delegate\n\n\tfinal var remoteObjectProxy: RCMConnectionManagerClientProtocol\n\t{\n\t\treturn serviceConnection.remoteObjectProxy as! RCMConnectionManagerClientProtocol\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, willConnectToProxy address: String, on port: UInt16)\n\t{\n\t\tremoteObjectProxy.ircConnectionWillConnect(toProxy: address, port: port)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, willConnectTo address: String, on port: UInt16)\n\t{\n\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, didConnectTo address: String?)\n\t{\n\t\tremoteObjectProxy.ircConnectionDidConnect(toHost: address)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, securedWith protocol: tls_protocol_version_t, cipherSuite: tls_ciphersuite_t)\n\t{\n\t\tremoteObjectProxy.ircConnectionDidSecureConnection(withProtocolType: `protocol`, cipherSuite: cipherSuite)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, requiresTrust response: @escaping (Bool) -> Void)\n\t{\n\t\tremoteObjectProxy.ircConnectionRequestInsecureCertificateTrust(response)\n\t}\n\n\tfinal func connectionClosedReadStream(_ connection: ConnectionSocket)\n\t{\n\t\tremoteObjectProxy.ircConnectionDidCloseReadStream()\n\t}\n\n\tfinal func connectionDisconnected(_ connection: ConnectionSocket)\n\t{\n\t\tresetState()\n\n\t\tremoteObjectProxy.ircConnectionDidDisconnectWithError(nil)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, disconnectedWith error: ConnectionError)\n\t{\n\t\tresetState()\n\n\t\tremoteObjectProxy.ircConnectionDidDisconnectWithError(error as NSError)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, received data: Data)\n\t{\n\t\tremoteObjectProxy.ircConnectionDidReceive(data)\n\t}\n\n\tfinal func connection(_ connection: ConnectionSocket, willSend data: Data)\n\t{\n\t\tremoteObjectProxy.ircConnectionWillSend(data)\n\t}\n\n\tfinal func connectionDidSend(_ connection: ConnectionSocket)\n\t{\n\t\tremoteObjectProxy.ircConnectionDidSendData()\n\n\t\ttryToSend()\n\t}\n}\n\n// MARK: - Extensions\n\ntypealias ConnectionError = Connection.ConnectionError\n\nextension ConnectionError: CustomNSError\n{\n\t/* Error domain and codes are defined in IRCConnectionErrors.h/m */\n\tstatic let errorDomain = ConnectionErrorDomain\n\n\tvar errorCode: Int\n\t{\n\t\tlet errorCode: ConnectionErrorCode\n\n\t\tswitch self {\n\t\t\tcase .socket(_):\n\t\t\t\terrorCode = .socket\n\t\t\tcase .other(_):\n\t\t\t\terrorCode = .other\n\t\t\tcase .badCertificate(_):\n\t\t\t\terrorCode = .badCertificate\n\t\t\tcase .unableToSecure(_):\n\t\t\t\terrorCode = .unableToSecure\n\t\t}\n\n\t\treturn Int(errorCode.rawValue)\n\t}\n\n\tvar errorUserInfo: [String : Any]\n\t{\n\t\tvar userInfo: [String : Any] = [:]\n\n\t\tif let errorDescription = errorDescription {\n\t\t\tuserInfo[NSLocalizedDescriptionKey] = errorDescription\n\t\t}\n\n\t\t// While we don't make use of it right now, pass the original\n\t\t// error object inside the user info dictionary because at\n\t\t// a later time, we may be interested in its contents.\n\t\tif case let .socket(error) = self {\n\t\t\tuserInfo[\"UnderlyingSocketError\"] = error\n\t\t}\n\n\t\treturn userInfo\n\t}\n}\n\nextension ConnectionError: LocalizedError\n{\n\tvar errorDescription: String?\n\t{\n\t\tswitch self {\n\t\t\tcase .socket(let error):\n\t\t\t\t/* The underlying socket error is almost always an NSError\n\t\t\t\t which means we can just ask for its localized description. */\n\t\t\t\treturn error.localizedDescription\n\t\t\tcase .other(let message),\n\t\t\t\t .badCertificate(let message),\n\t\t\t\t .unableToSecure(let message):\n\t\t\t\treturn message\n\t\t}\n\t}\n}\n\nfileprivate extension ConnectionSocket\n{\n\tstatic func socket(with config: IRCConnectionConfig) -> ConnectionSocket & ConnectionSocketProtocol\n\t{\n#if canImport(Network)\n\t\tif #available(macOS 10.14, *) {\n\t\t\tif (config.connectionPrefersModernSockets) {\n\t\t\t\treturn ConnectionSocketNWF(with: config)\n\t\t\t}\n\t\t}\n#endif\n\n\t\treturn ConnectionSocketClassic(with: config)\n\t}\n}\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/IRC/IRCConnectionSocket.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n*    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n/* ConnectionSocket is subclassed to implement the connection logic.\n One subclass uses GCDAsyncSocket which isn't designed for Swift.\n To accommodate some of its features, we must have our base class\n inherit from NSObject or all hell will break loose. */\nclass ConnectionSocket: NSObject\n{\n\tweak var delegate: ConnectionSocketDelegate?\n\n\tfinal private(set) var config: IRCConnectionConfig\n\n\tfinal let uniqueIdentifier: String\n\n\tvar connecting = false\n\tvar connected = false\n\tvar connectedWithClientSideCertificate = false\n\tvar disconnecting = false\n\tvar disconnected: Bool\n\t{\n\t\treturn (connecting == false && connected == false)\n\t}\n\tvar secured = false\n\tvar sending = false\n\tvar EOFReceived = false\n\n\tvar alternateDisconnectError: ConnectionError?\n\n\tfinal let torProxyTypeAddress = \"127.0.0.1\"\n\tfinal let torProxyTypePort: UInt16 = 9150\n\n\tfinal let maximumDataLength = (1000 * 1000 * 100) // 100 megabytes\n\n\tinit (with config: IRCConnectionConfig)\n\t{\n\t\tself.config = config\n\n\t\tuniqueIdentifier = UUID().uuidString\n\n\t\tsuper.init()\n\t}\n\n\tfunc resetState()\n\t{\n\t\tconnecting = false\n\t\tconnected = false\n\t\tconnectedWithClientSideCertificate = false\n\t\tdisconnecting = false\n\t\tsecured = false\n\n\t\tsending = false\n\n\t\tEOFReceived = false\n\n\t\talternateDisconnectError = nil\n\t}\n\n\tfunc tlsVerify(_ trust: SecTrust, response: @escaping RCMTrustResponse)\n\t{\n\t\tif (config.connectionShouldValidateCertificateChain == false) {\n\t\t\tresponse(true)\n\n\t\t\treturn\n\t\t}\n\n\t\tvar evaluationResult: SecTrustResultType = .invalid\n\n\t\tlet evaluationStatus = SecTrustEvaluate(trust, &evaluationResult)\n\n\t\tif (evaluationStatus == errSecSuccess) {\n\t\t\tif (evaluationResult == .unspecified || evaluationResult == .proceed) {\n\t\t\t\tresponse(true)\n\n\t\t\t\treturn\n\t\t\t} else if (evaluationResult == .recoverableTrustFailure) {\n\t\t\t\tdelegate?.connection(self, requiresTrust: response)\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tresponse(false)\n\t}\n\n\tfinal var clientSideCertificate: (identity: SecIdentity, certificate: SecCertificate)?\n\t{\n\t\tguard let certificateDataIn = config.identityClientSideCertificate else {\n\t\t\treturn nil\n\t\t}\n\n\t\t/* ====================================== */\n\n\t\tvar keychainRef: SecKeychainItem?\n\n\t\tlet certificateDataInRef = certificateDataIn as CFData\n\n\t\tvar status = SecKeychainItemCopyFromPersistentReference(certificateDataInRef, &keychainRef)\n\n\t\tif (status != noErr) {\n\t\t\tLogging.defaultSubsystem?.error(\"Operation Failed (1): \\(status, privacy: .public)\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\t/* \"A SecKeychainItem object for a certificate that is stored\n\t\t in a keychain can be safely cast to a SecCertificate for use\n\t\t with Certificate, Key, and Trust Services.\" */\n\t\t/* Contrary to the statement above, as stated in documentation,\n\t\t casting was crashing. This is a workaround until that's fixed. */\n\t\tlet certificateRef = unsafeBitCast(keychainRef, to: SecCertificate.self)\n\n\t\t/* ====================================== */\n\n\t\tvar identityRef: SecIdentity?\n\n\t\tstatus = SecIdentityCreateWithCertificate(nil, certificateRef, &identityRef)\n\n\t\tif (status != noErr) {\n\t\t\tLogging.defaultSubsystem?.error(\"Operation Failed (2): \\(status, privacy: .public)\")\n\n\t\t\treturn nil\n\t\t}\n\n\t\t/* ====================================== */\n\n\t\treturn (identity: identityRef!, certificate: certificateRef)\n\t}\n\n\tfinal func changeProxy(to type: IRCConnectionProxyType = .none, at host: String? = nil, on port: UInt16 = 0, username: String? = nil, password: String? = nil)\n\t{\n\t\tlet mutableConfig: IRCConnectionConfigMutable = config.mutableCopy() as! IRCConnectionConfigMutable\n\n\t\tmutableConfig.proxyAddress = host\n\t\tmutableConfig.proxyPort = port\n\n\t\tmutableConfig.proxyType = type\n\n\t\tmutableConfig.proxyUsername = username\n\t\tmutableConfig.proxyPassword = password\n\n\t\tconfig = mutableConfig\n\t}\n\n\tfinal func changeProxyToTor()\n\t{\n\t\tchangeProxy(to: .socks5, at: torProxyTypeAddress, on: torProxyTypePort)\n\t}\n\n\tfinal func changeProxyToNone()\n\t{\n\t\tchangeProxy()\n\t}\n}\n\nextension ConnectionError\n{\n\tinit (socketError: Error)\n\t{\n\t\tself = .socket(error: socketError)\n\t}\n\n\tinit (otherError message: String)\n\t{\n\t\tself = .other(message: message)\n\t}\n\n\tinit? (tlsError error: Error)\n\t{\n\t\tif (RCMSecureTransport.isTLSError(error) == false) {\n\t\t\treturn nil\n\t\t}\n\n\t\tself.init(tlsError: error.code)\n\t}\n\n\t/// init(tlsError:) returns .unableToSecure(\"Unknown\") for out of range error codes\n\tinit (tlsError errorCode: Int)\n\t{\n\t\tif let certError = RCMSecureTransport.description(forBadCertificateErrorCode: errorCode) {\n\t\t\tself = .badCertificate(failureReason: certError)\n\n\t\t\treturn\n\t\t}\n\n\t\tlet tlsError = RCMSecureTransport.description(forErrorCode: errorCode)\n\n\t\tself = .unableToSecure(failureReason: tlsError)\n\t}\n}\n\nprotocol ConnectionSocketDelegate: AnyObject\n{\n\tfunc connection(_ connection: ConnectionSocket, willConnectToProxy address: String, on port: UInt16)\n\tfunc connection(_ connection: ConnectionSocket, willConnectTo address: String, on port: UInt16)\n\tfunc connection(_ connection: ConnectionSocket, didConnectTo address: String?) // address is nil when connecting to proxy\n\tfunc connection(_ connection: ConnectionSocket, securedWith protocol: tls_protocol_version_t, cipherSuite: tls_ciphersuite_t)\n\tfunc connection(_ connection: ConnectionSocket, requiresTrust response: @escaping (Bool) -> Void)\n\tfunc connectionClosedReadStream(_ connection: ConnectionSocket)\n\tfunc connectionDisconnected(_ connection: ConnectionSocket)\n\tfunc connection(_ connection: ConnectionSocket, disconnectedWith error: ConnectionError)\n\tfunc connection(_ connection: ConnectionSocket, received data: Data)\n\tfunc connection(_ connection: ConnectionSocket, willSend data: Data)\n\tfunc connectionDidSend(_ connection: ConnectionSocket)\n}\n\nprotocol ConnectionSocketProtocol\n{\n\t/// Logic for opening socket\n\tfunc open()\n\n\t/// Logic for closing socket\n\tfunc close()\n\tfunc close(with error: String)\n\tfunc close(with error: ConnectionError)\n\n\t/// Logic for writing data (sending)\n\tfunc write(_ data: Data)\n\n\t/// Logic for waiting for data (receiving)\n\tfunc read()\n\n\t/// Logic for reading data from socket (receiving)\n\tfunc readIn(_ data: Data)\n\n\t/// Logic for providing upstream with information\n\t/// about the secured connection including policy name,\n\t/// protocol version, cipher suite, and certificates.\n\tfunc exportSecureConnectionInformation(to receiver: RCMSecureConnectionInformationCompletionBlock) throws\n\n\t/// TLS Information\n\tvar tlsNegotiatedProtocol: tls_protocol_version_t? { get }\n\tvar tlsNegotiatedCipherSuite: tls_ciphersuite_t? { get }\n\tvar tlsCertificateChainData: [Data]? { get }\n\tvar tlsPolicyName: String? { get }\n}\n\nextension ConnectionSocketProtocol where Self: ConnectionSocket\n{\n\tfunc close(with error: String)\n\t{\n\t\tlet errorEnum = ConnectionError.other(message: error)\n\n\t\tclose(with: errorEnum)\n\t}\n\n\tfunc close(with error: ConnectionError)\n\t{\n\t\tif (disconnected || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\talternateDisconnectError = error\n\n\t\tclose()\n\t}\n\n\tfunc exportSecureConnectionInformation(to receiver: RCMSecureConnectionInformationCompletionBlock) throws\n\t{\n\t\tlet policyName = tlsPolicyName\n\n\t\tlet protocolType = tlsNegotiatedProtocol ?? tls_protocol_version_unknown\n\n\t\tlet cipherSuite = tlsNegotiatedCipherSuite ?? tls_ciphersuite_unknown\n\n\t\tlet certificateChain = tlsCertificateChainData ?? []\n\n\t\treceiver(policyName, protocolType, cipherSuite, certificateChain)\n\t}\n}\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/IRC/IRCConnectionSocketClassic.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n* Copyright (c) 2018, 2019 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\nfinal class ConnectionSocketClassic: ConnectionSocket, ConnectionSocketProtocol, GCDAsyncSocketDelegate\n{\n\tfileprivate enum Tag : Int\n\t{\n\t\tcase none = 0\n\n\t\tcase socksProxyOpen = 10100\n\t\tcase socksProxyConnect = 10200\n\t\tcase socksProxyConnectReplyOne = 10300\n\t\tcase socksProxyAuthenticateUser = 10500\n\t}\n\n\tfileprivate enum Timeout : Double\n\t{\n\t\tcase normal = 30.0\n\t\tcase none = -1.0\n\t}\n\n\tfileprivate let httpHeaderResponseStatusRegularExpression = \"^HTTP\\\\/([1-2]{1})(\\\\.([0-2]{1}))?\\\\s([0-9]{3,4})\\\\s(.*)$\"\n\n\tfileprivate var socketDelegateQueue: DispatchQueue?\n\tfileprivate var socketReadWriteQueue: DispatchQueue?\n\tfileprivate var workerQueue: DispatchQueue?\n\n\tfileprivate var connection: GCDAsyncSocket?\n\n\tfileprivate let readDelimiter = Data([0x0a]) // \\n\n\n\t// MARK: - Grand Central Dispatch\n\n\tfileprivate func destroyDispatchQueues()\n\t{\n\t\tsocketDelegateQueue = nil\n\n\t\tsocketReadWriteQueue = nil\n\t}\n\n\tfileprivate func createDispatchQueues()\n\t{\n\t\tlet socketDelegateQueueName = \"Textual.ConnectionSocket.socketDelegateQueue.\\(uniqueIdentifier)\"\n\n\t\tsocketDelegateQueue = DispatchQueue(label: socketDelegateQueueName)\n\n\t\tlet socketReadWriteQueueName = \"Textual.ConnectionSocket.socketReadWriteQueue.\\(uniqueIdentifier)\"\n\n\t\tsocketReadWriteQueue = DispatchQueue(label: socketReadWriteQueueName)\n\t}\n\n\t// MARK: - Open/Close Socket\n\n\tfunc open()\n\t{\n\t\tif (disconnected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tcreateDispatchQueues()\n\n\t\tlet connection = GCDAsyncSocket(delegate: self,\n\t\t\t\t\t\t\t\t\t\tdelegateQueue: socketDelegateQueue,\n\t\t\t\t\t\t\t\t\t\tsocketQueue: socketReadWriteQueue)\n\n\t\tconnection.useStrictTimers = true\n\n\t\tswitch config.addressType {\n\t\t\tcase .v4:\n\t\t\t\tconnection.isIPv6Enabled = false\n\t\t\tcase .v6:\n\t\t\t\tconnection.isIPv4Enabled = false\n\t\t\tdefault:\n\t\t\t\tconnection.isIPv4PreferredOverIPv6 = false\n\t\t}\n\n\t\tself.connection = connection\n\n\t\tif (proxyConfigured) {\n\t\t\t/* populateSystemSocksProxy() does not assign an error for non-fatal\n\t\t\t failures which means this value should be treated as optional. */\n\t\t\tvar proxyPopulateError: String?\n\n\t\t\tif (populateSystemSocksProxy(failureReason: &proxyPopulateError) == false) {\n\t\t\t\tif let error = proxyPopulateError {\n\t\t\t\t\tLogging.defaultSubsystem?.error(\"\\(error, privacy: .public)\")\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet proxyAddress = config.proxyAddress!\n\t\t\t\tlet proxyPort = config.proxyPort\n\n\t\t\t\tdelegate?.connection(self, willConnectToProxy: proxyAddress, on: proxyPort)\n\n\t\t\t\tconnect(to: proxyAddress, on: proxyPort)\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tlet serverAddress = config.serverAddress\n\t\tlet serverPort = config.serverPort\n\n\t\tdelegate?.connection(self, willConnectTo: serverAddress, on: serverPort)\n\n\t\tconnect(to: serverAddress, on: serverPort)\n\t}\n\n\tfileprivate func connect(to host: String, on port: UInt16)\n\t{\n\t\tconnecting = true\n\n\t\tdo {\n\t\t\ttry connection?.connect(toHost: host, onPort: port, withTimeout: Timeout.normal.rawValue)\n\t\t} catch {\n\t\t\tlet socketError = ConnectionError(socketError: error)\n\n\t\t\tclose(with: socketError)\n\t\t}\n\t}\n\n\tfunc close()\n\t{\n\t\tif (disconnected || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tdisconnecting = true\n\n\t\tconnection?.disconnect()\n\t}\n\n\toverride func resetState()\n\t{\n\t\tsuper.resetState()\n\n\t\tconnection = nil\n\n\t\tdestroyDispatchQueues()\n\t}\n\n\t// MARK: - Socket Read & Write\n\n\tfunc write(_ data: Data)\n\t{\n\t\tif (connected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\t/* We only allow one write a time */\n\t\tif (sending) {\n\t\t\treturn\n\t\t}\n\n\t\tsending = true\n\n\t\tdelegate?.connection(self, willSend: data)\n\n\t\tconnection?.write(data, withTimeout: Timeout.none.rawValue, tag: Tag.none.rawValue)\n\t}\n\n\tfunc read()\n\t{\n\t\tif (connected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tconnection?.readData(to: readDelimiter,\n\t\t\t\t\t\t\t withTimeout: Timeout.none.rawValue,\n\t\t\t\t\t\t\t maxLength: UInt(maximumDataLength),\n\t\t\t\t\t\t\t tag: Tag.none.rawValue)\n\t}\n\n\tfunc readIn(_ data: Data)\n\t{\n\t\tif (disconnected || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\t/* We read until \\n appears.\n\t\t Data returned by socket will include the \\n\n\t\t and \\r if it's present. We therefore trim the\n\t\t data of \\r and \\n when we read it in. */\n\t\tlet trimmedData = data.withoutNewlinesAtEnd\n\n\t\tdelegate?.connection(self, received: trimmedData)\n\t}\n\n\t// MARK: - Properties\n\n\tfinal var connectedHost: String?\n\t{\n\t\tif (proxyInUse) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn connection?.connectedHost\n\t}\n\n\tfileprivate func beginTLSNegotiation()\n\t{\n\t\tif (config.connectionPrefersSecuredConnection == false) {\n\t\t\treturn\n\t\t}\n\n\t\t/* This makes me cry */\n\t\tvar settings:[String : NSObject] = [\n\t\t\tGCDAsyncSocketManuallyEvaluateTrust : NSNumber(value: true),\n\t\t\tGCDAsyncSocketSSLProtocolVersionMin : NSNumber(value: RCMSecureTransport.minimumDeprecatedProtocol.rawValue),\n\t\t\tkCFStreamSSLIsServer as String : NSNumber(value: false),\n\t\t\tkCFStreamSSLPeerName as String : config.serverAddress as NSString\n\t\t]\n\n\t\tif (config.cipherSuites != .none) {\n\t\t\tsettings[GCDAsyncSocketSSLCipherSuites] =\n\t\t\t\tRCMSecureTransport.cipherSuites(in: config.cipherSuites, includeDeprecated:\n\t\t\t\t\t\t\t\t\t\t\t\t\t(config.connectionPrefersModernCiphersOnly == false)) as NSArray\n\t\t}\n\n\t\tif let certificate = clientSideCertificate {\n\t\t\tsettings[kCFStreamSSLCertificates as String] = NSArray(objects: certificate.identity, certificate.certificate)\n\n\t\t\tconnectedWithClientSideCertificate = true\n\t\t}\n\n\t\tconnection?.startTLS(settings)\n\t}\n\n\tfileprivate func onConnect()\n\t{\n\t\tbeginTLSNegotiation()\n\n\t\tconnecting = false\n\t\tconnected = true\n\n\t\tread()\n\n\t\tdelegate?.connection(self, didConnectTo: connectedHost)\n\t}\n\n\tfileprivate func onSecured()\n\t{\n\t\tsecured = true\n\n\t\tlet protocolType = tlsNegotiatedProtocol ?? tls_protocol_version_unknown\n\n\t\tlet cipherSuite = tlsNegotiatedCipherSuite ?? tls_ciphersuite_unknown\n\n\t\tdelegate?.connection(self, securedWith: protocolType, cipherSuite: cipherSuite)\n\t}\n\n\tfileprivate func onDisconnect(with error: Error?)\n\t{\n\t\tdefer {\n\t\t\tresetState()\n\t\t}\n\n\t\tvar errorPayload: ConnectionError?\n\n\t\tif let alternateError = alternateDisconnectError {\n\t\t\terrorPayload = alternateError\n\t\t} else if let err = error {\n\t\t\tif let tlsError = ConnectionError(tlsError: err) {\n\t\t\t\terrorPayload = tlsError\n\t\t\t} else if (err.code != errSSLClosedGraceful) {\n\t\t\t\terrorPayload = ConnectionError(socketError: err)\n\t\t\t}\n\t\t}\n\n\t\tif (errorPayload == nil) {\n\t\t\tdelegate?.connectionDisconnected(self)\n\t\t} else {\n\t\t\tdelegate?.connection(self, disconnectedWith: errorPayload!)\n\t\t}\n\t}\n\n\t// MARK: - GCDAsyncSocketDelegate\n\n\tfinal func socket(_ sock: GCDAsyncSocket, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void)\n\t{\n\t\ttlsVerify(trust) { (underlyingResponse) in\n\t\t\tcompletionHandler(underlyingResponse)\n\t\t}\n\t}\n\n\tfinal func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16)\n\t{\n\t\tif (proxyInUse) {\n\t\t\tdo {\n\t\t\t\ttry openProxy()\n\t\t\t} catch let error as ConnectionError {\n\t\t\t\tclose(with: error)\n\t\t\t} catch {\n\t\t\t\tfatalError(\"Unexpected error: \\(error)\")\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\n\t\tonConnect()\n\t}\n\n\tfinal func socketDidCloseReadStream(_ sock: GCDAsyncSocket)\n\t{\n\t\tEOFReceived = true\n\n\t\tdelegate?.connectionClosedReadStream(self)\n\t}\n\n\tfinal func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?)\n\t{\n\t\tonDisconnect(with: err)\n\t}\n\n\tfinal func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int)\n\t{\n\t\tif (proxyInUse) {\n\t\t\tdo {\n\t\t\t\t/* proxyRead() returns true if it swallows the data such as\n\t\t\t\t when it is talking directly to the proxy during negotiations. */\n\t\t\t\tif (try proxyRead(data, with: Tag(rawValue: tag) ?? .none)) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} catch let error as ConnectionError {\n\t\t\t\tclose(with: error)\n\n\t\t\t\treturn\n\t\t\t} catch {\n\t\t\t\tfatalError(\"Unexpected error: \\(error)\")\n\t\t\t}\n\t\t}\n\n\t\treadIn(data)\n\n\t\tread()\n\t}\n\n\tfinal func socket(_ sock: GCDAsyncSocket, didWriteDataWithTag tag: Int)\n\t{\n\t\tsending = false\n\n\t\tdelegate?.connectionDidSend(self)\n\t}\n\n\tfinal func socketDidSecure(_ sock: GCDAsyncSocket)\n\t{\n\t\tonSecured()\n\t}\n\n\t// MARK: - Security\n\n\tvar tlsNegotiatedProtocol: tls_protocol_version_t?\n\t{\n\t\treturn connection?.tlsNegotiatedProtocol\n\t}\n\n\tvar tlsNegotiatedCipherSuite: tls_ciphersuite_t?\n\t{\n\t\treturn connection?.tlsNegotiatedCipherSuite\n\t}\n\n\tvar tlsCertificateChainData: [Data]?\n\t{\n\t\treturn connection?.tlsCertificateChainData\n\t}\n\n\tvar tlsPolicyName: String?\n\t{\n\t\treturn connection?.tlsPolicyName\n\t}\n\n\t// MARK: - SOCKS Proxy Support\n\n\tfileprivate var proxyConfigured: Bool\n\t{\n\t\tlet proxyType = config.proxyType\n\n\t\treturn (proxyType == .automatic\t\t||\n\t\t\t\tproxyType == .socks4\t\t||\n\t\t\t\tproxyType == .socks5\t\t||\n\t\t\t\tproxyType == .tor\t\t\t||\n\t\t\t\tproxyType == .HTTP)\n\t}\n\n\tfileprivate var proxyInUse: Bool\n\t{\n\t\tlet proxyType = config.proxyType\n\n\t\treturn (proxyType == .socks4\t\t||\n\t\t\t\tproxyType == .socks5\t\t||\n\t\t\t\tproxyType == .HTTP)\n\t}\n\n\tfileprivate var proxyCanAuthenticate: Bool\n\t{\n\t\treturn (config.proxyUsername?.isEmpty == false &&\n\t\t\t\tconfig.proxyPassword?.isEmpty == false)\n\t}\n\n\tfileprivate func populateSystemSocksProxy(failureReason: inout String?) -> Bool\n\t{\n\t\tlet proxyType = config.proxyType\n\n\t\tif (proxyType == .automatic)\n\t\t{\n\t\t\t/* Being unable to read proxy values is considered non-fatal\n\t\t\t error which why an failure reason is never assigned. */\n\t\t\tguard let proxySettings = SCDynamicStoreCopyProxies(nil) as? [String : AnyObject] else {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (proxySettings.bool(for: \"SOCKSEnable\") == false) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tguard let proxyHost = proxySettings.string(for: \"SOCKSProxy\") else {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tif (proxyHost.isEmpty) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tlet proxyPort = proxySettings.integer(for: \"SOCKSPort\")\n\n\t\t\tif (proxyPort.isValidInternetPort == false) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tvar proxyPassword: String?\n\n\t\t\tlet proxyUsername = proxySettings.string(for: \"SOCKSUser\")\n\n\t\t\tif proxyUsername?.isEmpty == false {\n\t\t\t\tlet queryParameters:[CFString : CFTypeRef] = [\n\t\t\t\t\tkSecClass : kSecClassInternetPassword,\n\t\t\t\t\tkSecAttrServer : proxyHost as CFString,\n\t\t\t\t\tkSecAttrProtocol : kSecAttrProtocolSOCKS,\n\t\t\t\t\tkSecReturnData : kCFBooleanTrue,\n\t\t\t\t\tkSecMatchLimit : kSecMatchLimitOne\n\t\t\t\t]\n\n\t\t\t\tvar queryResultRef: CFTypeRef?\n\n\t\t\t\tlet queryStatus = SecItemCopyMatching(queryParameters as CFDictionary, &queryResultRef)\n\n\t\t\t\tif (queryStatus != noErr) {\n\t\t\t\t\tfailureReason = \"SOCKS Error: Textual encountered a problem trying to retrieve the SOCKS proxy password from System Settings\"\n\n\t\t\t\t\treturn false\n\t\t\t\t}\n\n\t\t\t\tlet proxyPasswordData = queryResultRef as! Data\n\n\t\t\t\tproxyPassword = String(data: proxyPasswordData, encoding: .utf8)\n\t\t\t} // proxyUsername\n\n\t\t\tchangeProxy(to: .socks5,\n\t\t\t\t\t\tat: proxyHost,\n\t\t\t\t\t\ton: UInt16(proxyPort),\n\t\t\t\t\t\tusername: proxyUsername,\n\t\t\t\t\t\tpassword: proxyPassword)\n\t\t}\n\t\telse if (proxyType == .tor)\n\t\t{\n\t\t\tchangeProxyToTor()\n\t\t}\n\n\t\treturn true\n\t}\n\n\tfileprivate func openProxy() throws\n\t{\n\t\tlet proxyType = config.proxyType\n\n\t\tswitch proxyType {\n\t\t\tcase .socks4:\n\t\t\t\ttry socks4ProxyOpen()\n\t\t\tcase .socks5:\n\t\t\t\tsocks5ProxyOpen()\n\t\t\tcase .HTTP:\n\t\t\t\thttpProxyOpen()\n\t\t\tdefault:\n\t\t\t\treturn\n\t\t} // switch()\n\t}\n\n\t/* Boolean return value indicates whether the data was successfully\n\t read as data related to the proxy. When false is returned, the data\n\t is passed upstream as normal data to read. */\n\tfileprivate func proxyRead(_ data: Data, with tag: Tag = .none) throws -> Bool\n\t{\n\t\tlet proxyType = config.proxyType\n\n\t\tswitch proxyType {\n\t\t\tcase .socks4:\n\t\t\t\treturn try socks4ProxyRead(data, with: tag)\n\t\t\tcase .socks5:\n\t\t\t\treturn try socks5ProxyRead(data, with: tag)\n\t\t\tcase .HTTP:\n\t\t\t\treturn try httpProxyRead(data, with: tag)\n\t\t\tdefault:\n\t\t\t\treturn false\n\t\t} // switch()\n\t}\n\n\t// MARK: - SOCKS4 and SOCKS5\n\n\tfileprivate func socksProxyConnect() throws\n\t{\n\t\t//\n\t\t// Packet layout for SOCKS4 connect:\n\t\t//\n\t\t// \t    +----+----+---------+-------------------+---------+....+----+\n\t\t// NAME | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|\n\t\t//      +----+----+---------+-------------------+---------+....+----+\n\t\t// SIZE\t   1    1      2              4           variable       1\n\t\t//\n\t\t// ---------------------------------------------------------------------------\n\t\t//\n\t\t// Packet layout for SOCKS5 connect:\n\t\t//\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t// NAME | VER | CMD | RSV | ATYP | ADDR | PORT |\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t// SIZE |  1  |  1  |  1  |  1   | var  |  2   |\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t//\n\n\t\tvar destination = \"\"\n\n\t\tlet socksVersion = config.proxyType\n\n\t\tif (socksVersion == .socks4) {\n\t\t\tguard let resolvedAddress = socks4ConnectAddress else {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Unable to resolve an IPv4 address to connect to\")\n\t\t\t}\n\n\t\t\tdestination = resolvedAddress\n\t\t} else {\n\t\t\tdestination = config.serverAddress\n\t\t}\n\n\t\t/* \"...big-endian byte order is also referred to as network byte order... */\n\t\tlet destinationPortBytes = config.serverPort.bigEndian.data\n\n\t\t/* Assemble the packet of data that will be sent */\n\t\tvar packetData = Data()\n\n\t\t/* SOCKS version to use */\n\t\tif (socksVersion == .socks5) {\n\t\t\tpacketData.append([0x05], count: 1)\n\t\t} else {\n\t\t\tpacketData.append([0x04], count: 1)\n\t\t}\n\n\t\t/* Type of connection (the command) */\n\t\tpacketData.append([0x01], count: 1)\n\n\t\tif (socksVersion == .socks5)\n\t\t{\n\t\t\t/* Reserved value that must be 0 for SOCKS5 */\n\t\t\tpacketData.append([0x00], count: 1)\n\n\t\t\t/* The address */\n\t\t\tif let IPv4Bytes = destination.IPv6AddressBytes\n\t\t\t{\n\t\t\t\tpacketData.append([0x04], count: 1)\n\n\t\t\t\tpacketData.append(IPv4Bytes)\n\t\t\t}\n\t\t\telse if let IPv6Bytes = destination.IPv4AddressBytes\n\t\t\t{\n\t\t\t\tpacketData.append([0x01], count: 1)\n\n\t\t\t\tpacketData.append(IPv6Bytes)\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tpacketData.append([0x03], count: 1)\n\n\t\t\t\tguard let addressBytes = destination.data(using: .ascii) else {\n\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Unable to convert address into a ASCII fragment\")\n\t\t\t\t}\n\n\t\t\t\tlet addressBytesLength = addressBytes.count\n\n\t\t\t\tif (addressBytesLength > UINT8_MAX) {\n\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Connection address length cannot exceed \\(UINT8_MAX) characters\")\n\t\t\t\t}\n\n\t\t\t\tpacketData.append([UInt8(addressBytesLength)], count: 1)\n\n\t\t\t\tpacketData.append(addressBytes)\n\t\t\t} // Address\n\n\t\t\tpacketData.append(destinationPortBytes)\n\t\t}\n\t\telse // .socks5\n\t\t{\n\t\t\tpacketData.append(destinationPortBytes)\n\n\t\t\tguard let addressBytes = destination.IPv4AddressBytes else {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Unable to convert address into network bytes\")\n\t\t\t}\n\n\t\t\tpacketData.append(addressBytes)\n\n\t\t\tpacketData.append([0x00], count: 1)\n\t\t}\n\n\t\t/* Write the packet to the socket */\n\t\tconnection?.write(packetData, withTimeout: Timeout.none.rawValue, tag: Tag.socksProxyConnect.rawValue)\n\n\t\t//\n\t\t// Packet layout for SOCKS4 connect response:\n\t\t//\n\t\t//\t    +----+----+----+----+----+----+----+----+\n\t\t// NAME | VN | CD | DSTPORT |      DSTIP        |\n\t\t//      +----+----+----+----+----+----+----+----+\n\t\t// SIZE    1    1      2              4\n\t\t//\n\t\t// Packet layout for SOCKS5 connect response:\n\t\t//\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t// NAME | VER | REP | RSV | ATYP | ADDR | PORT |\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t// SIZE |  1  |  1  |  1  |  1   | var  |  2   |\n\t\t//      +-----+-----+-----+------+------+------+\n\t\t//\n\n\t\t/* Wait for a response from the SOCKS server */\n\t\tconnection?.readData(withTimeout: Timeout.normal.rawValue, tag: Tag.socksProxyConnectReplyOne.rawValue)\n\t}\n\n\t// MARK: - SOCKS5\n\n\tfileprivate func socks5ProxyOpen()\n\t{\n\t\tsocks5ProxySendGreeting()\n\t}\n\n\tfileprivate func socks5ProxyRead(_ data: Data, with tag: Tag = .none) throws -> Bool\n\t{\n\t\tif (tag == .socksProxyOpen)\n\t\t{\n\t\t\tif (data.count != 2) {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server responded with a malformed packet\")\n\t\t\t}\n\n\t\t\tlet version = data[0]\n\t\t\tlet method = data[1]\n\n\t\t\tif (version != 5) {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server greeting reply contained incorrect version number\")\n\t\t\t}\n\n\t\t\tswitch method {\n\t\t\t\tcase 0:\n\t\t\t\t\ttry socksProxyConnect()\n\t\t\t\tcase 2:\n\t\t\t\t\tif (proxyCanAuthenticate) {\n\t\t\t\t\t\ttry socks5ProxyUserAuthentication()\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server requested that we authenticate but a username and/or password is not configured\")\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server requested authentication method that is not supported\")\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t\telse if (tag == .socksProxyConnectReplyOne)\n\t\t{\n\t\t\tif (data.count <= 8) { // first 4 bytes + 2 for port\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server responded with a malformed packet\")\n\t\t\t}\n\n\t\t\tlet version = data[0]\n\t\t\tlet reply = data[1]\n\n\t\t\tif (version == 5 && reply == 0)\n\t\t\t{\n\t\t\t\tonConnect()\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch reply {\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: General SOCKS server failure\")\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Connection not allowed by ruleset\")\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Network unreachable\")\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Host unreachable\")\n\t\t\t\t\tcase 5:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Connection refused\")\n\t\t\t\t\tcase 6:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Time to live (TTL) expired\")\n\t\t\t\t\tcase 7:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Command not supported\")\n\t\t\t\t\tcase 8:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Address type not supported\")\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Unknown SOCKS error\")\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t\telse if (tag == .socksProxyAuthenticateUser)\n\t\t{\n\t\t\t//\n\t\t\t// Server response for username/password authentication:\n\t\t\t//\n\t\t\t// field 1: version, 1 byte\n\t\t\t// field 2: status code, 1 byte.\n\t\t\t// 0x00 = success\n\t\t\t// any other value = failure, connection must be closed\n\t\t\t//\n\n\t\t\tif (data.count != 2) {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Server responded with a malformed packet\")\n\t\t\t}\n\n\t\t\tlet status = data[1]\n\n\t\t\tif (status == 0x00) {\n\t\t\t\ttry socksProxyConnect()\n\t\t\t} else {\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Authentication failed for unknown reason\")\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\n\t\treturn false /* Read not handled here */\n\t}\n\n\tfileprivate func socks5ProxySendGreeting()\n\t{\n\t\t//\n\t\t// Packet layout for SOCKS5 greeting:\n\t\t//\n\t\t//      +-----+-----------+---------+\n\t\t// NAME | VER | NMETHODS  | METHODS |\n\t\t//      +-----+-----------+---------+\n\t\t// SIZE |  1  |    1      | 1 - 255 |\n\t\t//      +-----+-----------+---------+\n\t\t//\n\n\t\t/* Assemble the packet of data that will be sent */\n\t\tvar packetData = Data()\n\n\t\tif (proxyCanAuthenticate == false) {\n\t\t\t/* Send instructions that we are asking for version 5 of the SOCKS protocol\n\t\t\t with one authentication method: anonymous access */\n\n\t\t\tpacketData.append([0x05, 0x01, 0x00], count: 3)\n\t\t} else {\n\t\t\t/* Send instructions that we are asking for version 5 of the SOCKS protocol\n\t\t\t with two authentication methods: anonymous access and password based. */\n\n\t\t\tpacketData.append([0x05, 0x02, 0x00, 0x02], count: 4)\n\t\t}\n\n\t\t/* Write the packet to the socket */\n\t\tconnection?.write(packetData, withTimeout: Timeout.none.rawValue, tag: Tag.socksProxyOpen.rawValue)\n\n\t\t//\n\t\t// Packet layout for SOCKS5 greeting response:\n\t\t//\n\t\t//      +-----+--------+\n\t\t// NAME | VER | METHOD |\n\t\t//      +-----+--------+\n\t\t// SIZE |  1  |   1    |\n\t\t//      +-----+--------+\n\t\t//\n\n\t\t/* Wait for a response from the SOCKS server */\n\t\tconnection?.readData(withTimeout: Timeout.normal.rawValue, tag: Tag.socksProxyOpen.rawValue)\n\t}\n\n\t//\n\t// For username/password authentication the client's authentication request is\n\t//\n\t// field 1: version number, 1 byte (must be 0x01)\n\t// field 2: username length, 1 byte\n\t// field 3: username\n\t// field 4: password length, 1 byte\n\t// field 5: password\n\t//\n\n\tfileprivate func socks5ProxyUserAuthentication() throws\n\t{\n\t\t/* Assemble the packet of data that will be sent */\n\t\tguard let usernameData = config.proxyUsername!.data(using: .utf8) else {\n\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Unable to convert username into a UTF-8 fragment\")\n\t\t}\n\n\t\tlet usernameLength = usernameData.count\n\n\t\tif (usernameLength > UINT8_MAX) {\n\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Username length cannot exceed \\(UINT8_MAX) characters\")\n\t\t}\n\n\t\tguard let passwordData = config.proxyPassword!.data(using: .utf8) else {\n\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Unable to convert password into a UTF-8 fragment\")\n\t\t}\n\n\t\tlet passwordLength = passwordData.count\n\n\t\tif (passwordLength > UINT8_MAX) {\n\t\t\tthrow ConnectionError(otherError: \"SOCKS5 Error: Password length cannot exceed \\(UINT8_MAX) characters\")\n\t\t}\n\n\t\tvar authData = Data(capacity: 1 + 1 + usernameLength + 1 + passwordLength)\n\n\t\tauthData.append([0x01], count: 1)\n\t\tauthData.append([UInt8(usernameLength)], count: 1)\n\t\tauthData.append(usernameData)\n\t\tauthData.append([UInt8(passwordLength)], count: 1)\n\t\tauthData.append(passwordData)\n\n\t\t/* Write the packet to the socket */\n\t\tconnection?.write(authData, withTimeout: Timeout.none.rawValue, tag: Tag.socksProxyAuthenticateUser.rawValue)\n\n\t\t/* Wait for a response from the SOCKS server */\n\t\tconnection?.readData(withTimeout: Timeout.none.rawValue, tag: Tag.socksProxyAuthenticateUser.rawValue)\n\t}\n\n\t// MARK: - SOCKS4\n\n\tfileprivate func socks4ProxyOpen() throws\n\t{\n\t\ttry socksProxyConnect()\n\t}\n\n\tfileprivate func socks4ProxyRead(_ data: Data, with tag: Tag = .none) throws -> Bool\n\t{\n\t\tif (tag != .socksProxyConnectReplyOne) {\n\t\t\treturn false /* Read not handled here */\n\t\t}\n\n\t\tif (data.count != 8) {\n\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Server responded with a malformed packet\")\n\t\t}\n\n\t\tlet reply = data[1]\n\n\t\tswitch reply {\n\t\t\tcase 0x5a:\n\t\t\t\tonConnect()\n\t\t\tcase 0x5b:\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Request rejected or failed\")\n\t\t\tcase 0x5c:\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Request failed because client is not running an identd (or not reachable from server)\")\n\t\t\tcase 0x5d:\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Request failed because client's identd could not confirm the user ID string in the request\")\n\t\t\tdefault:\n\t\t\t\tthrow ConnectionError(otherError: \"SOCKS4 Error: Server replied with unknown status code\")\n\t\t}\n\n\t\treturn true\n\t}\n\n\tfileprivate var socks4ConnectAddress: String?\n\t{\n\t\t/* SOCKS4 proxies do not support anything other than IPv4 addresses\n\t\t (unless you support SOCKS4a, which Textual does not) which means we\n\t\t perform manual DNS lookup for SOCKS4 and rely on end-point proxy to\n\t\t perform lookup when using other proxy types. */\n\t\tlet serverAddress = config.serverAddress\n\n\t\tif (serverAddress.isIPv4Address) {\n\t\t\treturn serverAddress\n\t\t} else if (serverAddress.isIPv6Address) {\n\t\t\treturn nil\n\t\t}\n\n\t\tguard let resolvedAddresses = try? GCDAsyncSocket.lookupHost(serverAddress, port: config.serverPort) as? [Data] else {\n\t\t\treturn nil\n\t\t}\n\n\t\tlet resolvedAddress4 = resolvedAddresses.first {\n\t\t\tGCDAsyncSocket.isIPv4Address($0)\n\t\t}\n\n\t\tif (resolvedAddress4 == nil) {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn GCDAsyncSocket.host(fromAddress: resolvedAddress4!)\n\t}\n\n\t// MARK: - HTTP Proxy\n\n\tfileprivate func httpProxyOpen()\n\t{\n\t\tlet connectionAddress = config.serverAddress\n\n\t\tlet connectionPort = config.serverPort\n\n\t\tvar connectionAddressCombined = \"\"\n\n\t\tif (connectionAddress.isIPv6Address) {\n\t\t\tconnectionAddressCombined = \"[\\(connectionAddress)]:\\(connectionPort)\" // IPv6 requires brackets\n\t\t} else {\n\t\t\tconnectionAddressCombined = \"\\(connectionAddress):\\(connectionPort)\"\n\t\t}\n\n\t\tlet connectCommand = \"CONNECT \\(connectionAddressCombined) HTTP/1.1\\r\\n\\r\\n\"\n\n\t\t/* Pass the data along to the HTTP server */\n\t\tlet connectCommandData = connectCommand.data(using: .ascii)\n\n\t\tconnection?.write(connectCommandData!, withTimeout: Timeout.none.rawValue, tag: Tag.socksProxyOpen.rawValue)\n\n\t\t/* Read until the end of the HTTP header response */\n\t\tlet responseTerminatorData = \"\\r\\n\\r\\n\".data(using: .ascii)\n\n\t\tconnection?.readData(to: responseTerminatorData!, withTimeout: Timeout.normal.rawValue, tag: Tag.socksProxyOpen.rawValue)\n\t}\n\n\tfileprivate func httpProxyRead(_ data: Data, with tag: Tag = .none) throws -> Bool\n\t{\n\t\tif (tag != .socksProxyOpen) {\n\t\t\treturn false /* Read not handled here */\n\t\t}\n\n\t\t/* Given data, turn it into string and perform basic validation */\n\t\tguard let dataAsString = String(data: data, encoding: .utf8) else {\n\t\t\tthrow ConnectionError(otherError: \"HTTP Error: Unable to read data\")\n\t\t}\n\n\t\tlet headerComponents = dataAsString.components(separatedBy: \"\\r\\n\")\n\n\t\tif (headerComponents.count <= 2) {\n\t\t\tthrow ConnectionError(otherError: \"HTTP Error: Server responded with a malformed packet\")\n\t\t}\n\n\t\t/* Try our best to extract the status code from the response */\n\t\tlet statusResponse = headerComponents[0]\n\n\t\t// It is possible to split the response into its components using\n\t\t// the space character but by using regular expression we are not\n\t\t// only getting the components, we are also validating its format.\n\t\tlet statusResponseRegexRange = NSMakeRange(0, statusResponse.count)\n\n\t\tlet statusResponseRegex = try! NSRegularExpression(pattern: httpHeaderResponseStatusRegularExpression, options: [])\n\n\t\tlet statusResponseRegexResult = statusResponseRegex.firstMatch(in: statusResponse, options: [], range: statusResponseRegexRange)\n\n\t\tif (statusResponseRegexResult?.numberOfRanges != 6) {\n\t\t\tthrow ConnectionError(otherError: \"HTTP Error: Server responded with a malformed packet\")\n\t\t}\n\n\t\t//\n\t\t// Index values:\n\t\t//\n\t\t// Complete Line\t\t(0): HTTP/1.1 200 Connection established\n\t\t// Major Version\t\t(1): 1\n\t\t// Minor Version\t\t(2): .1\n\t\t// Minor Version\t\t(3): 1\n\t\t// Status Code\t\t\t(4): 200\n\t\t// Status Message\t\t(5): Connection established\n\t\t//\n\n\t\tlet statusCodeRange = statusResponseRegexResult?.range(at: 4)\n\t\tlet statusCode = statusResponse.substring(with: statusCodeRange!)!\n\n\t\tif (Int(statusCode) == 200) {\n\t\t\tonConnect()\n\t\t} else {\n\t\t\tlet statusMessageRange = statusResponseRegexResult?.range(at: 5)\n\t\t\tlet statusMessage = statusResponse.substring(with: statusMessageRange!)!\n\n\t\t\tthrow ConnectionError(otherError: \"HTTP Error: HTTP proxy server returned status code \\(statusCode) with the message “\\(statusMessage)”\")\n\t\t}\n\n\t\treturn true\n\t}\n}\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/IRC/IRCConnectionSocketNWF.swift",
    "content": "/* *********************************************************************\n*                  _____         _               _\n*                 |_   _|____  _| |_ _   _  __ _| |\n*                   | |/ _ \\ \\/ / __| | | |/ _` | |\n*                   | |  __/>  <| |_| |_| | (_| | |\n*                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n*\n* Copyright (c) 2018, 2019 Codeux Software, LLC & respective contributors.\n*       Please see Acknowledgements.pdf for additional information.\n*\n* Redistribution and use in source and binary forms, with or without\n* modification, are permitted provided that the following conditions\n* are met:\n*\n*  * Redistributions of source code must retain the above copyright\n*    notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above copyright\n*    notice, this list of conditions and the following disclaimer in the\n*    documentation and/or other materials provided with the distribution.\n*  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n*    names of its contributors may be used to endorse or promote products\n*    derived from this software without specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n* SUCH DAMAGE.\n*\n*********************************************************************** */\n\n#if canImport(Network)\nimport Network\n\n@available(macOS 10.14, *)\nfinal class ConnectionSocketNWF: ConnectionSocket, ConnectionSocketProtocol\n{\n\tfileprivate var readInBuffer: Data?\n\n\tfileprivate var connection: NWConnection?\n\n\tfileprivate var socketDelegateQueue: DispatchQueue?\n\n\tfileprivate var trustRef: SecTrust?\n\n\t// MARK: - Grand Central Dispatch\n\n\tfileprivate func destroyDispatchQueues()\n\t{\n\t\tsocketDelegateQueue = nil\n\t}\n\n\tfileprivate func createDispatchQueues()\n\t{\n\t\tlet socketDelegateQueueName = \"Textual.ConnectionSocket.socketDelegateQueue.\\(uniqueIdentifier)\"\n\n\t\tsocketDelegateQueue = DispatchQueue(label: socketDelegateQueueName)\n\t}\n\n\t// MARK: - Open/Close Socket\n\n\tfileprivate var constructedParameters: NWParameters\n\t{\n\t\tvar parameters: NWParameters\n\n\t\tif (config.connectionPrefersSecuredConnection) {\n\t\t\tparameters = NWParameters(tls: constructedTLSOptions)\n\t\t} else {\n\t\t\tparameters = .tcp\n\t\t}\n\n\t\tparameters.preferNoProxies = (config.proxyType == .none)\n\n\t\tif let internetProtocol = parameters.defaultProtocolStack.internetProtocol as? NWProtocolIP.Options {\n\t\t\tswitch config.addressType {\n\t\t\t\tcase .v4:\n\t\t\t\t\tinternetProtocol.version = .v4\n\t\t\t\tcase .v6:\n\t\t\t\t\tinternetProtocol.version = .v6\n\t\t\t\tdefault:\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn parameters\n\t}\n\n\tfileprivate var constructedTLSOptions: NWProtocolTLS.Options\n\t{\n\t\tlet tlsOptions = NWProtocolTLS.Options()\n\n\t\tlet secOptions = tlsOptions.securityProtocolOptions\n\n\t\tif let localIdentity = tlsLocalIdentity {\n\t\t\tsec_protocol_options_set_local_identity(secOptions, localIdentity)\n\t\t}\n\n\t\tif (config.cipherSuites == .none) {\n\t\t\tsec_protocol_options_append_tls_ciphersuite_group(secOptions, .default)\n\t\t} else {\n\t\t\tRCMSecureTransport.appendCipherSuites(in: config.cipherSuites,\n\t\t\t\t\t\t\t\t\t\t\t\t  includeDeprecated: (config.connectionPrefersModernCiphersOnly == false),\n\t\t\t\t\t\t\t\t\t\t\t\t  to: secOptions)\n\t\t}\n\n\t\tsec_protocol_options_set_min_tls_protocol_version(secOptions, RCMSecureTransport.minimumProtocolType)\n\n\t\tsec_protocol_options_set_verify_block(secOptions, { [weak self] (_, trust, completionBlock) in\n\t\t\tself?.tlsVerifySecProtocol(trust, response: completionBlock)\n\t\t}, socketDelegateQueue!)\n\n\t\treturn tlsOptions\n\t}\n\n\tfunc open()\n\t{\n\t\tif (disconnected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tcreateDispatchQueues()\n\n\t\tlet serverAddress = config.serverAddress\n\t\tlet serverPort = config.serverPort\n\n\t\tlet connection = NWConnection(host: NWEndpoint.Host(stringLiteral: serverAddress),\n\t\t\t\t\t\t\t\t\t  port: NWEndpoint.Port(integerLiteral: serverPort),\n\t\t\t\t\t\t\t\t\t  using: constructedParameters)\n\n\t\tconnection.stateUpdateHandler = statusUpdateHandler\n\n\t\tself.connection = connection\n\n\t\tdelegate?.connection(self, willConnectTo: serverAddress, on: serverPort)\n\n\t\tconnect()\n\t}\n\n\tfileprivate func connect()\n\t{\n\t\tconnecting = true\n\n\t\tconnection?.start(queue: socketDelegateQueue!)\n\t}\n\n\tfunc close()\n\t{\n\t\tif (disconnected || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tdisconnecting = true\n\n\t\tconnection?.cancel()\n\t}\n\n\tfileprivate func close(with error: NWError)\n\t{\n\t\tclose(with: translateError(error))\n\t}\n\n\toverride func resetState()\n\t{\n\t\tsuper.resetState()\n\n\t\tconnection = nil\n\n\t\tdestroyDispatchQueues()\n\t}\n\n\t// MARK: - Socket Read & Write\n\n\tfunc read()\n\t{\n\t\tif (connected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tconnection?.receive(minimumIncompleteLength: 0,\n\t\t\t\t\t\t\tmaximumLength: maximumDataLength,\n\t\t\t\t\t\t\tcompletion: readCompletionHandler)\n\t}\n\n\tfunc readIn(_ data: Data)\n\t{\n\t\tif (disconnected || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\t/* First combine the existing read buffer with the\n\t\t new data so we can process it in mass. */\n\t\t/* Note: June 29, 2018 on Swift 4.2 on Xcode 10 beta 2\n\t\t When I first wrote this code, I wrote the logic in the\n\t\t form \"newBuffer = (oldBuffer + data)\" When writing it\n\t\t using this syntax, Foundation would throw at random\n\t\t an out of range exception similar to the following:\n\n\t\t *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSConcreteMutableData subdataWithRange:]: range {12945, 87} exceeds data length 7282'\n\n\t\t TODO: Maybe this should be revisited at a later time. */\n\t\tvar newBuffer: Data\n\n\t\tif let oldBuffer = readInBuffer {\n\t\t\tnewBuffer = oldBuffer\n\t\t} else {\n\t\t\tnewBuffer = Data()\n\t\t}\n\n\t\tnewBuffer.append(data)\n\n\t\t/* Regardless of the result, we need to update the\n\t\t saved buffer with the updated buffer, but we prefer\n\t\t to wait until then end to do that. */\n\t\tdefer {\n\t\t\treadInBuffer = newBuffer\n\t\t}\n\n\t\t/* Split the data */\n\t\tguard let (lines, remainingData) = newBuffer.splitNetworkLines() else {\n\t\t\treturn\n\t\t}\n\n\t\tfor line in lines {\n\t\t\tdelegate?.connection(self, received: line)\n\t\t}\n\n\t\tif let remainder = remainingData {\n\t\t\tnewBuffer = remainder\n\t\t} else {\n\t\t\t/* \"Pass true to request that the collection avoid releasing its\n\t\t\t storage. Retaining the collection’s storage can be a useful\n\t\t\t optimization when you’re planning to grow the collection again.\" */\n\n\t\t\tnewBuffer.removeAll(keepingCapacity: true)\n\t\t}\n\t}\n\n\tfunc write(_ data: Data)\n\t{\n\t\tif (connected == false || disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\t/* We only allow one write a time */\n\t\tif (sending) {\n\t\t\treturn\n\t\t}\n\n\t\tsending = true\n\n\t\tdelegate?.connection(self, willSend: data)\n\n\t\tconnection?.send(content: data, completion: .contentProcessed(writeCompletionHandler))\n\t}\n\n\t// MARK: - Properties\n\n\tfileprivate var connectedHost: String?\n\t{\n\t\tguard let endpoint = connection?.currentPath?.remoteEndpoint else {\n\t\t\treturn nil\n\t\t}\n\n\t\tif case let .hostPort(host, _) = endpoint {\n\t\t\tswitch host {\n\t\t\t\tcase .name(let address, _):\n\t\t\t\t\treturn address\n\t\t\t\tcase .ipv4(let address):\n\t\t\t\t\treturn address.rawValue.IPv4Address\n\t\t\t\tcase .ipv6(let address):\n\t\t\t\t\treturn address.rawValue.IPv6Address\n\t\t\t\t@unknown default:\n\t\t\t\t\tfatalError(\"Unexpected switch case\")\n\t\t\t}\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfileprivate func onConnect()\n\t{\n\t\tconnecting = false\n\t\tconnected = true\n\n\t\tread()\n\n\t\tdelegate?.connection(self, didConnectTo: connectedHost)\n\n\t\tonSecured()\n\t}\n\n\tfileprivate func onSecured()\n\t{\n\t\t/* We call onSecured() regardless of other preconditions then\n\t\t only mark ourselves as secured if we have protocol information. */\n\t\tguard  let protocolType = tlsNegotiatedProtocol,\n\t\t\t   let cipherSuite \t= tlsNegotiatedCipherSuite else\n\t\t{\n\t\t\treturn\n\t\t}\n\n\t\tsecured = true\n\n\t\tdelegate?.connection(self, securedWith: protocolType, cipherSuite: cipherSuite)\n\t}\n\n\tfileprivate func onDisconnect(with error: Error?)\n\t{\n\t\tdefer {\n\t\t\tresetState()\n\t\t}\n\n\t\tvar errorPayload: ConnectionError?\n\n\t\tif let alternateError = alternateDisconnectError {\n\t\t\terrorPayload = alternateError\n\t\t} else if let nwError = error as? NWError {\n\t\t\terrorPayload = translateError(nwError)\n\t\t}\n\n\t\tif (errorPayload == nil) {\n\t\t\tdelegate?.connectionDisconnected(self)\n\t\t} else {\n\t\t\tdelegate?.connection(self, disconnectedWith: errorPayload!)\n\t\t}\n\t}\n\n\t// NWConnection Delegate\n\n\tfinal func readCompletionHandler(_ content: Data?, _ contentContext: NWConnection.ContentContext?, _ isComplete: Bool, _ error: NWError?)\n\t{\n\t\tif (disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tif let error = error {\n\t\t\tclose(with: error)\n\n\t\t\treturn\n\t\t}\n\n\t\tif (contentContext?.isFinal == true && isComplete) {\n\t\t\tEOFReceived = true\n\n\t\t\tdelegate?.connectionClosedReadStream(self)\n\n\t\t\treturn\n\t\t}\n\n\t\tif (content == nil) {\n\t\t\tclose(with: \"Unexpected condition: There is no data when there is no error\")\n\n\t\t\treturn\n\t\t}\n\n\t\treadIn(content!)\n\n\t\tread()\n\t}\n\n\tfinal func writeCompletionHandler(_ error: NWError?)\n\t{\n\t\tif (disconnecting) {\n\t\t\treturn\n\t\t}\n\n\t\tsending = false\n\n\t\tif let error = error {\n\t\t\tclose(with: error)\n\n\t\t\treturn\n\t\t}\n\n\t\tdelegate?.connectionDidSend(self)\n\t}\n\n\tfinal func statusUpdateHandler(_ status: NWConnection.State)\n\t{\n\t\tswitch status {\n\t\t\tcase .waiting(let error):\n\t\t\t\tclose(with: error)\n\t\t\tcase .ready:\n\t\t\t\tonConnect()\n\t\t\tcase .cancelled:\n\t\t\t\tonDisconnect(with: nil)\n\t\t\tcase .failed(let error):\n\t\t\t\tonDisconnect(with: error)\n\t\t\tdefault:\n\t\t\t\tbreak\n\t\t}\n\t}\n\n\t// MARK: - Security\n\n\tfinal func tlsVerifySecProtocol(_ trust: sec_trust_t, response: @escaping sec_protocol_verify_complete_t)\n\t{\n\t\tlet trustRef = sec_trust_copy_ref(trust).takeUnretainedValue()\n\n\t\tself.trustRef = trustRef\n\n\t\ttlsVerify(trustRef) { (underlyingResponse) in\n\t\t\tresponse(underlyingResponse)\n\t\t}\n\t}\n\n\tvar tlsNegotiatedProtocol: tls_protocol_version_t?\n\t{\n\t\tvar protocolType: tls_protocol_version_t?\n\n\t\taccessTLSMetadata { (metadata) in\n\t\t\tprotocolType = sec_protocol_metadata_get_negotiated_tls_protocol_version(metadata)\n\t\t}\n\n\t\treturn protocolType\n\t}\n\n\tvar tlsNegotiatedCipherSuite: tls_ciphersuite_t?\n\t{\n\t\tvar cipherSuite: tls_ciphersuite_t?\n\n\t\taccessTLSMetadata { (metadata) in\n\t\t\tcipherSuite = sec_protocol_metadata_get_negotiated_tls_ciphersuite(metadata)\n\t\t}\n\n\t\treturn cipherSuite\n\t}\n\n\tvar tlsCertificateChainData: [Data]?\n\t{\n\t\tvar certificateChain: [Data]?\n\n\t\taccessTLSTrustRef { (trustRef) in\n\t\t\tcertificateChain = RCMSecureTransport.certificates(in: trustRef)\n\t\t}\n\n\t\treturn certificateChain\n\t}\n\n\tvar tlsPolicyName: String?\n\t{\n\t\tvar policyName: String?\n\n\t\taccessTLSTrustRef { (trustRef) in\n\t\t\tpolicyName = RCMSecureTransport.policyName(in: trustRef)\n\n\t\t\tif policyName == nil {\n\t\t\t\t/*\n\t\t\t\tJune 09, 2019 with 10.15 Beta (19A471t):\n\n\t\t\t\tDespite us having a trustRef, we do not have a policy name\n\t\t\t\twhen connecting with modern sockets to an IP address.\n\t\t\t\tThe IP address itself is what is being matched against the\n\t\t\t\tcertificate name anyways so let's just return it from config.\n\n\t\t\t\tTODO: Revisit this in a later beta or GM.\n\t\t\t\t*/\n\n\t\t\t\tlet serverAddress = config.serverAddress\n\n\t\t\t\tif serverAddress.isIPAddress {\n\t\t\t\t\tpolicyName = serverAddress\n\t\t\t\t}\n\t\t\t} // policyName\n\t\t}\n\n\t\treturn policyName\n\t}\n\n\tfileprivate func accessTLSMetadata(with closure: (sec_protocol_metadata_t) -> Void)\n\t{\n\t\tguard let genericMetadata = connection?.metadata(definition: NWProtocolTLS.definition) else {\n\t\t\treturn\n\t\t}\n\n\t\tguard let tlsMetadata = genericMetadata as? NWProtocolTLS.Metadata else {\n\t\t\treturn\n\t\t}\n\n\t\tclosure(tlsMetadata.securityProtocolMetadata)\n\t}\n\n\tfileprivate func accessTLSTrustRef(with closure: (SecTrust) -> Void)\n\t{\n\t\tif let trustRef = trustRef {\n\t\t\tclosure(trustRef)\n\t\t}\n\t}\n\n\tvar tlsLocalIdentity: sec_identity_t?\n\t{\n\t\tguard let clientCertificate = clientSideCertificate else {\n\t\t\treturn nil\n\t\t}\n\n\t\t/* And I thought I wrote verbose names... */\n\t\treturn sec_identity_create_with_certificates(clientCertificate.identity,\n\t\t\t\t\t\t\t\t\t\t\t\t\t([clientCertificate.certificate] as CFArray))\n\t}\n\n\t// MARK: - Error Handling\n\n\tfileprivate func translateError(_ error: NWError) -> ConnectionError\n\t{\n\t\tswitch error {\n\t\t\tcase .dns(let errorCode):\n\t\t\t\treturn ConnectionError(nwDNSError: errorCode)\n\t\t\tcase .posix(let errorCode):\n\t\t\t\treturn ConnectionError(nwPOSIXError: errorCode.rawValue)\n\t\t\tcase .tls(let errorCode):\n\t\t\t\treturn ConnectionError(nwTLSError: errorCode)\n\t\t\t@unknown default:\n\t\t\t\tfatalError(\"Unexpected switch case\")\n\t\t}\n\t}\n}\n\nfileprivate extension ConnectionError\n{\n\tinit (nwDNSError: DNSServiceErrorType)\n\t{\n\t\tlet errorCode = Int(nwDNSError)\n\n\t\tlet errorReason: String\n\n\t\tswitch errorCode {\n\t\t\tcase kDNSServiceErr_NoError:\n\t\t\t\terrorReason = \"No error\"\n\t\t\tcase kDNSServiceErr_NoSuchName:\n\t\t\t\terrorReason = \"No such name\"\n\t\t\tcase kDNSServiceErr_NoMemory:\n\t\t\t\terrorReason = \"No memory\"\n\t\t\tcase kDNSServiceErr_BadParam:\n\t\t\t\terrorReason = \"Bad parameter\"\n\t\t\tcase kDNSServiceErr_BadReference:\n\t\t\t\terrorReason = \"Bad reference\"\n\t\t\tcase kDNSServiceErr_BadState:\n\t\t\t\terrorReason = \"Bad state\"\n\t\t\tcase kDNSServiceErr_BadFlags:\n\t\t\t\terrorReason = \"Bad flags\"\n\t\t\tcase kDNSServiceErr_Unsupported:\n\t\t\t\terrorReason = \"Unsupported\"\n\t\t\tcase kDNSServiceErr_NotInitialized:\n\t\t\t\terrorReason = \"Not initialized\"\n\t\t\tcase kDNSServiceErr_AlreadyRegistered:\n\t\t\t\terrorReason = \"Already registered\"\n\t\t\tcase kDNSServiceErr_NameConflict:\n\t\t\t\terrorReason = \"Name conflict\"\n\t\t\tcase kDNSServiceErr_Invalid:\n\t\t\t\terrorReason = \"Invalid\"\n\t\t\tcase kDNSServiceErr_Firewall:\n\t\t\t\terrorReason = \"Firewall\"\n\t\t\tcase kDNSServiceErr_Incompatible: /* client library incompatible with daemon */\n\t\t\t\terrorReason = \"Incompatible\"\n\t\t\tcase kDNSServiceErr_BadInterfaceIndex:\n\t\t\t\terrorReason = \"Bad interface index\"\n\t\t\tcase kDNSServiceErr_Refused:\n\t\t\t\terrorReason = \"Refused\"\n\t\t\tcase kDNSServiceErr_NoSuchRecord:\n\t\t\t\terrorReason = \"No such record\"\n\t\t\tcase kDNSServiceErr_NoAuth:\n\t\t\t\terrorReason = \"No authentication\"\n\t\t\tcase kDNSServiceErr_NoSuchKey:\n\t\t\t\terrorReason = \"No such key\"\n\t\t\tcase kDNSServiceErr_NATTraversal:\n\t\t\t\terrorReason = \"NAT traversal\"\n\t\t\tcase kDNSServiceErr_DoubleNAT:\n\t\t\t\terrorReason = \"Double NAT\"\n\t\t\tcase kDNSServiceErr_BadTime: /* Codes up to here existed in Tiger */\n\t\t\t\terrorReason = \"Bad time\"\n\t\t\tcase kDNSServiceErr_BadSig:\n\t\t\t\terrorReason = \"Bad signature\"\n\t\t\tcase kDNSServiceErr_BadKey:\n\t\t\t\terrorReason = \"Bad key\"\n\t\t\tcase kDNSServiceErr_Transient:\n\t\t\t\terrorReason = \"Transient\"\n\t\t\tcase kDNSServiceErr_ServiceNotRunning: /* Background daemon not running */\n\t\t\t\terrorReason = \"Service not running\"\n\t\t\tcase kDNSServiceErr_NATPortMappingUnsupported: /* NAT doesn't support PCP, NAT-PMP or UPnP */\n\t\t\t\terrorReason = \"NAT port mapping unsupported\"\n\t\t\tcase kDNSServiceErr_NATPortMappingDisabled: /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */\n\t\t\t\terrorReason = \"NAT port mapping disabled\"\n\t\t\tcase kDNSServiceErr_NoRouter: /* No router currently configured (probably no network connectivity) */\n\t\t\t\terrorReason = \"No router\"\n\t\t\tcase kDNSServiceErr_PollingMode:\n\t\t\t\terrorReason = \"Polling mode\"\n\t\t\tcase kDNSServiceErr_Timeout:\n\t\t\t\terrorReason = \"Timeout\"\n\t\t\tdefault:\n\t\t\t\terrorReason = \"Unknown\"\n\t\t}\n\n\t\tlet errorMessage = LocalizedString(\"DNS Error: %@ (%ld)\", errorReason, errorCode, table: \"ConnectionErrors\")\n\n\t\tlet nsError = NSError(domain: \"NWErrorDomainDNS\",\n\t\t\t\t\t\t\t  code: errorCode,\n\t\t\t\t\t\t\t  userInfo: [ NSLocalizedDescriptionKey : errorMessage ])\n\n\t\tself.init(socketError: nsError)\n\t}\n\n\tinit (nwPOSIXError: Int32)\n\t{\n\t\tlet errorCode = Int(nwPOSIXError)\n\n\t\tlet errorReason: String\n\n\t\tif let errorReasonC = strerror(nwPOSIXError) {\n\t\t\terrorReason = String(cString: errorReasonC)\n\t\t} else {\n\t\t\terrorReason = \"Unknown\"\n\t\t}\n\n\t\tlet errorMessage = LocalizedString(\"POSIX Error: %@ (%ld)\", errorReason, errorCode, table: \"ConnectionErrors\")\n\n\t\tlet nsError = NSError(domain: \"NWErrorDomainPOSIX\",\n\t\t\t\t\t\t\t  code: errorCode,\n\t\t\t\t\t\t\t  userInfo: [ NSLocalizedDescriptionKey : errorMessage ])\n\n\t\tself.init(socketError: nsError)\n\t}\n\n\tinit (nwTLSError: OSStatus)\n\t{\n\t\tlet errorCode = Int(nwTLSError)\n\n\t\tself.init(tlsError: errorCode)\n\t}\n}\n\n#endif\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Service/RCMProcessDelegate.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation RCMProcessDelegate\n\n#pragma mark -\n#pragma mark XPC Delegate\n\n- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection\n{\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(RCMConnectionManagerServerProtocol)];\n\n\tnewConnection.exportedInterface = exportedInterface;\n\n\tRCMProcessMain *exportedObject = [[RCMProcessMain alloc] initWithXPCConnection:newConnection];\n\n\tnewConnection.exportedObject = exportedObject;\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(RCMConnectionManagerClientProtocol)];\n\n\tnewConnection.remoteObjectInterface = remoteObjectInterface;\n\n\t[newConnection resume];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Service/RCMProcessMain.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface RCMProcessMain ()\n@property (nonatomic, strong) IRCConnection *connection;\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@end\n\n@implementation RCMProcessMain\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithXPCConnection:(NSXPCConnection *)connection\n{\n\tNSParameterAssert(connection != nil);\n\n\tif ((self = [super init])) {\n\t\tself.serviceConnection = connection;\n\n\t\tLogToConsoleSetDefaultSubsystemToMainBundle(@\"General\");\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark XPC Interface\n\n- (void)openWithConfig:(IRCConnectionConfig *)config\n{\n\tNSAssert((self.connection == nil),\n\t\t @\"Method invoked with connection already open\");\n\n\tIRCConnection *connection = [[IRCConnection alloc] initWithConfig:config onConnection:self.serviceConnection];\n\n\t[connection open];\n\n\tself.connection = connection;\n}\n\n- (void)close\n{\n\tNSAssert((self.connection != nil),\n\t\t @\"Method invoked without performing setup first\");\n\n\t[self.connection close];\n}\n\n- (void)sendData:(NSData *)data\n{\n\t[self sendData:data bypassQueue:NO];\n}\n\n- (void)sendData:(NSData *)data bypassQueue:(BOOL)bypassQueue\n{\n\tNSAssert((self.connection != nil),\n\t\t @\"Method invoked without performing setup first\");\n\n\t[self.connection sendData:data bypassQueue:bypassQueue];\n}\n\n- (void)exportSecureConnectionInformation:(NS_NOESCAPE RCMSecureConnectionInformationCompletionBlock)completionBlock\n{\n\tNSAssert((self.connection != nil),\n\t\t @\"Method invoked without performing setup first\");\n\n\t[self.connection exportSecureConnectionInformation:completionBlock error:NULL];\n}\n\n- (void)enforceFloodControl\n{\n\tNSAssert((self.connection != nil),\n\t\t @\"Method invoked without performing setup first\");\n\n\t[self.connection enforceFloodControl];\n}\n\n- (void)clearSendQueue\n{\n\tNSAssert((self.connection != nil),\n\t\t @\"Method invoked without performing setup first\");\n\n\t[self.connection clearSendQueue];\n}\n\n- (void)enableAppNap\n{\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:@{@\"NSAppSleepDisabled\" : @(NO)}];\n}\n\n- (void)disableAppNap\n{\n\t[[NSUserDefaults standardUserDefaults] registerDefaults:@{@\"NSAppSleepDisabled\" : @(YES)}];\n}\n\n- (void)enableSuddenTermination\n{\n\t[[NSProcessInfo processInfo] enableSuddenTermination];\n}\n\n- (void)disableSuddenTermination\n{\n\t[[NSProcessInfo processInfo] disableSuddenTermination];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Classes/Service/main.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wnullability-inferred-on-nested-type\"\n\nint main(int argc, const char *argv[])\n{\n\tRCMProcessDelegate *delegate = [RCMProcessDelegate new];\n\n\tNSXPCListener *listener = [NSXPCListener serviceListener];\n\n\tlistener.delegate = delegate;\n\n\t[listener resume];\n\n\treturn 0;\n}\n\n#pragma clang diagnostic pop\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Configurations/Sandbox/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/IRC Remote Connection Manager.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C06DE7E20EC48560055D09A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CAC2A071F12AFFB00D06046 /* Security.framework */; };\n\t\t4C06DE7F20EC48560055D09A /* SecurityInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CAC2A081F12AFFB00D06046 /* SecurityInterface.framework */; };\n\t\t4C06DE8020EC48570055D09A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CAC2A0B1F12B01700D06046 /* SystemConfiguration.framework */; };\n\t\t4C46A06920EC68B800094EA4 /* NSObjectHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A05720EC67E300094EA4 /* NSObjectHelper.m */; };\n\t\t4C46A06A20EC68B800094EA4 /* IRCConnectionConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A02B20EC67E300094EA4 /* IRCConnectionConfig.m */; };\n\t\t4C46A06B20EC68B800094EA4 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A02F20EC67E300094EA4 /* GCDAsyncSocket.m */; settings = {COMPILER_FLAGS = \"-Wno-implicit-retain-self\"; }; };\n\t\t4C46A06C20EC68B800094EA4 /* GCDAsyncSocketExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A03120EC67E300094EA4 /* GCDAsyncSocketExtensions.m */; };\n\t\t4C46A06D20EC68B800094EA4 /* TLOTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A03220EC67E300094EA4 /* TLOTimer.m */; };\n\t\t4C46A07020EC68B800094EA4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A00C20EC626E00094EA4 /* main.m */; };\n\t\t4C46A07120EC68B800094EA4 /* RCMProcessDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A00A20EC626E00094EA4 /* RCMProcessDelegate.m */; };\n\t\t4C46A07220EC68B800094EA4 /* RCMProcessMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A00B20EC626E00094EA4 /* RCMProcessMain.m */; };\n\t\t4C46A07320EC68C000094EA4 /* IRCConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C469FFF20EC626E00094EA4 /* IRCConnection.swift */; };\n\t\t4C46A07420EC68C000094EA4 /* IRCConnectionSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C46A00020EC626E00094EA4 /* IRCConnectionSocket.swift */; };\n\t\t4C46A07520EC68C000094EA4 /* IRCConnectionSocketClassic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C469FFE20EC626E00094EA4 /* IRCConnectionSocketClassic.swift */; };\n\t\t4C46A07620EC68C000094EA4 /* IRCConnectionSocketNWF.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C469FFD20EC626E00094EA4 /* IRCConnectionSocketNWF.swift */; };\n\t\t4C5274DC20F7D49000B18F9D /* ConnectionErrors.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C5274DA20F7D49000B18F9D /* ConnectionErrors.strings */; };\n\t\t4C5274DE20F8D50C00B18F9D /* IRCConnectionErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C5274DD20F8D50C00B18F9D /* IRCConnectionErrors.m */; };\n\t\t4CACDB5820F747710075AFB5 /* TLOLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CACDB5720F747710075AFB5 /* TLOLocalization.m */; };\n\t\t4CACDB5B20F7496D0075AFB5 /* TLOLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CACDB5A20F7496D0075AFB5 /* TLOLocalization.swift */; };\n\t\t4CE144EB20EC04F1000E01C9 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8C72D21F1208F200ED72DB /* CocoaExtensions.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C1406421F11942B00C73D53 /* IRC Connection Host.xpc */ = {isa = PBXFileReference; explicitFileType = \"wrapper.xpc-service\"; includeInIndex = 0; path = \"IRC Connection Host.xpc\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C469FFD20EC626E00094EA4 /* IRCConnectionSocketNWF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRCConnectionSocketNWF.swift; sourceTree = \"<group>\"; };\n\t\t4C469FFE20EC626E00094EA4 /* IRCConnectionSocketClassic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRCConnectionSocketClassic.swift; sourceTree = \"<group>\"; };\n\t\t4C469FFF20EC626E00094EA4 /* IRCConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRCConnection.swift; sourceTree = \"<group>\"; };\n\t\t4C46A00020EC626E00094EA4 /* IRCConnectionSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IRCConnectionSocket.swift; sourceTree = \"<group>\"; };\n\t\t4C46A00320EC626E00094EA4 /* RCMProcessMainPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCMProcessMainPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A00420EC626E00094EA4 /* RCMConnectionManagerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCMConnectionManagerProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C46A00520EC626E00094EA4 /* SwiftBridgingHeaderPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftBridgingHeaderPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A00620EC626E00094EA4 /* RCMProcessDelegatePrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCMProcessDelegatePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A00720EC626E00094EA4 /* RCMProcessPCHPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCMProcessPCHPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A00820EC626E00094EA4 /* IRCConnectionPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCConnectionPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A00A20EC626E00094EA4 /* RCMProcessDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCMProcessDelegate.m; sourceTree = \"<group>\"; };\n\t\t4C46A00B20EC626E00094EA4 /* RCMProcessMain.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCMProcessMain.m; sourceTree = \"<group>\"; };\n\t\t4C46A00C20EC626E00094EA4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t4C46A02220EC677B00094EA4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C46A02B20EC67E300094EA4 /* IRCConnectionConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRCConnectionConfig.m; sourceTree = \"<group>\"; };\n\t\t4C46A02F20EC67E300094EA4 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = \"<group>\"; };\n\t\t4C46A03120EC67E300094EA4 /* GCDAsyncSocketExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocketExtensions.m; sourceTree = \"<group>\"; };\n\t\t4C46A03220EC67E300094EA4 /* TLOTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TLOTimer.m; sourceTree = \"<group>\"; };\n\t\t4C46A03720EC67E300094EA4 /* GCDAsyncSocketExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocketExtensions.h; sourceTree = \"<group>\"; };\n\t\t4C46A03820EC67E300094EA4 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = \"<group>\"; };\n\t\t4C46A03C20EC67E300094EA4 /* IRCConnectionConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCConnectionConfig.h; sourceTree = \"<group>\"; };\n\t\t4C46A03F20EC67E300094EA4 /* IRCConnectionConfigInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRCConnectionConfigInternal.h; sourceTree = \"<group>\"; };\n\t\t4C46A04620EC67E300094EA4 /* NSObjectHelperPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSObjectHelperPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C46A04B20EC67E300094EA4 /* TLOTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TLOTimer.h; sourceTree = \"<group>\"; };\n\t\t4C46A05720EC67E300094EA4 /* NSObjectHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSObjectHelper.m; sourceTree = \"<group>\"; };\n\t\t4C46A06720EC687500094EA4 /* RCMConnectionManagerProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCMConnectionManagerProtocol.h; path = Classes/Headers/Private/RCMConnectionManagerProtocol.h; sourceTree = SOURCE_ROOT; };\n\t\t4C5274DB20F7D49000B18F9D /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/ConnectionErrors.strings; sourceTree = \"<group>\"; };\n\t\t4C5274DD20F8D50C00B18F9D /* IRCConnectionErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRCConnectionErrors.m; sourceTree = \"<group>\"; };\n\t\t4C5274DF20F8D52C00B18F9D /* IRCConnectionErrors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IRCConnectionErrors.h; sourceTree = \"<group>\"; };\n\t\t4C8C72D21F1208F200ED72DB /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CAC2A071F12AFFB00D06046 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };\n\t\t4CAC2A081F12AFFB00D06046 /* SecurityInterface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityInterface.framework; path = System/Library/Frameworks/SecurityInterface.framework; sourceTree = SDKROOT; };\n\t\t4CAC2A0B1F12B01700D06046 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };\n\t\t4CACDB5720F747710075AFB5 /* TLOLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TLOLocalization.m; sourceTree = \"<group>\"; };\n\t\t4CACDB5920F747850075AFB5 /* TLOLocalization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TLOLocalization.h; sourceTree = \"<group>\"; };\n\t\t4CACDB5A20F7496D0075AFB5 /* TLOLocalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TLOLocalization.swift; sourceTree = \"<group>\"; };\n\t\t4CE143F920EBF5DB000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE143FC20EBF5DB000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE143FE20EBF5DB000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1440C20EBF5DB000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1440D20EBF5DB000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1441020EBF5DB000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1441120EBF5DB000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1441320EBF5DB000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1442120EBF5DB000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1442420EBF5DB000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1442620EBF5DB000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1445520EBF641000E01C9 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };\n\t\t4CE1448120EC0209000E01C9 /* Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4C14063F1F11942B00C73D53 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CE144EB20EC04F1000E01C9 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t\t4C06DE7E20EC48560055D09A /* Security.framework in Frameworks */,\n\t\t\t\t4C06DE7F20EC48560055D09A /* SecurityInterface.framework in Frameworks */,\n\t\t\t\t4C06DE8020EC48570055D09A /* SystemConfiguration.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4C1406391F11942B00C73D53 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469FFB20EC626E00094EA4 /* Classes */,\n\t\t\t\t4C1406521F1194E900C73D53 /* Resources */,\n\t\t\t\t4C8C72D71F1208F200ED72DB /* Frameworks */,\n\t\t\t\t4C1406431F11942B00C73D53 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406431F11942B00C73D53 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1406421F11942B00C73D53 /* IRC Connection Host.xpc */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406521F1194E900C73D53 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1406531F1194F100C73D53 /* Build Settings */,\n\t\t\t\t4C46A01C20EC677B00094EA4 /* Language Files */,\n\t\t\t\t4C46A02120EC677B00094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406531F1194F100C73D53 /* Build Settings */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1406541F1194F900C73D53 /* Configurations */,\n\t\t\t);\n\t\t\tname = \"Build Settings\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406541F1194F900C73D53 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE143F520EBF5DB000E01C9 /* Build */,\n\t\t\t\t4CE1442720EBF5DB000E01C9 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C469FFB20EC626E00094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02620EC67E300094EA4 /* Shared */,\n\t\t\t\t4C46A00120EC626E00094EA4 /* Headers */,\n\t\t\t\t4C469FFC20EC626E00094EA4 /* IRC */,\n\t\t\t\t4C46A00920EC626E00094EA4 /* Service */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469FFC20EC626E00094EA4 /* IRC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469FFF20EC626E00094EA4 /* IRCConnection.swift */,\n\t\t\t\t4C46A00020EC626E00094EA4 /* IRCConnectionSocket.swift */,\n\t\t\t\t4C469FFE20EC626E00094EA4 /* IRCConnectionSocketClassic.swift */,\n\t\t\t\t4C469FFD20EC626E00094EA4 /* IRCConnectionSocketNWF.swift */,\n\t\t\t);\n\t\t\tpath = IRC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A00120EC626E00094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A00220EC626E00094EA4 /* Private */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A00220EC626E00094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A00820EC626E00094EA4 /* IRCConnectionPrivate.h */,\n\t\t\t\t4C46A00420EC626E00094EA4 /* RCMConnectionManagerProtocol.h */,\n\t\t\t\t4C46A00620EC626E00094EA4 /* RCMProcessDelegatePrivate.h */,\n\t\t\t\t4C46A00320EC626E00094EA4 /* RCMProcessMainPrivate.h */,\n\t\t\t\t4C46A00720EC626E00094EA4 /* RCMProcessPCHPrivate.h */,\n\t\t\t\t4C46A00520EC626E00094EA4 /* SwiftBridgingHeaderPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A00920EC626E00094EA4 /* Service */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A00C20EC626E00094EA4 /* main.m */,\n\t\t\t\t4C46A00A20EC626E00094EA4 /* RCMProcessDelegate.m */,\n\t\t\t\t4C46A00B20EC626E00094EA4 /* RCMProcessMain.m */,\n\t\t\t);\n\t\t\tpath = Service;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A01C20EC677B00094EA4 /* Language Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C5274DA20F7D49000B18F9D /* ConnectionErrors.strings */,\n\t\t\t);\n\t\t\tpath = \"Language Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A02120EC677B00094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02220EC677B00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A02620EC67E300094EA4 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A03520EC67E300094EA4 /* Headers */,\n\t\t\t\t4C46A05520EC67E300094EA4 /* Helpers */,\n\t\t\t\t4C46A02A20EC67E300094EA4 /* IRC */,\n\t\t\t\t4C46A02C20EC67E300094EA4 /* Library */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tpath = ../../Sources/Shared;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C46A02A20EC67E300094EA4 /* IRC */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02B20EC67E300094EA4 /* IRCConnectionConfig.m */,\n\t\t\t\t4C5274DD20F8D50C00B18F9D /* IRCConnectionErrors.m */,\n\t\t\t);\n\t\t\tpath = IRC;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A02C20EC67E300094EA4 /* Library */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02D20EC67E300094EA4 /* External Libraries */,\n\t\t\t\t4CACDB5720F747710075AFB5 /* TLOLocalization.m */,\n\t\t\t\t4CACDB5A20F7496D0075AFB5 /* TLOLocalization.swift */,\n\t\t\t\t4C46A03220EC67E300094EA4 /* TLOTimer.m */,\n\t\t\t);\n\t\t\tpath = Library;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A02D20EC67E300094EA4 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02E20EC67E300094EA4 /* Sockets */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A02E20EC67E300094EA4 /* Sockets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A02F20EC67E300094EA4 /* GCDAsyncSocket.m */,\n\t\t\t\t4C46A03120EC67E300094EA4 /* GCDAsyncSocketExtensions.m */,\n\t\t\t);\n\t\t\tpath = Sockets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A03520EC67E300094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A03620EC67E300094EA4 /* External Libraries */,\n\t\t\t\t4C46A03D20EC67E300094EA4 /* Internal */,\n\t\t\t\t4C46A04320EC67E300094EA4 /* Private */,\n\t\t\t\t4C46A04C20EC67E300094EA4 /* Services */,\n\t\t\t\t4C46A03C20EC67E300094EA4 /* IRCConnectionConfig.h */,\n\t\t\t\t4C5274DF20F8D52C00B18F9D /* IRCConnectionErrors.h */,\n\t\t\t\t4CACDB5920F747850075AFB5 /* TLOLocalization.h */,\n\t\t\t\t4C46A04B20EC67E300094EA4 /* TLOTimer.h */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A03620EC67E300094EA4 /* External Libraries */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A03820EC67E300094EA4 /* GCDAsyncSocket.h */,\n\t\t\t\t4C46A03720EC67E300094EA4 /* GCDAsyncSocketExtensions.h */,\n\t\t\t);\n\t\t\tpath = \"External Libraries\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A03D20EC67E300094EA4 /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A03F20EC67E300094EA4 /* IRCConnectionConfigInternal.h */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A04320EC67E300094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A04620EC67E300094EA4 /* NSObjectHelperPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A04C20EC67E300094EA4 /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A06720EC687500094EA4 /* RCMConnectionManagerProtocol.h */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A05520EC67E300094EA4 /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A05620EC67E300094EA4 /* Cocoa (Objective-C) */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C46A05620EC67E300094EA4 /* Cocoa (Objective-C) */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C46A05720EC67E300094EA4 /* NSObjectHelper.m */,\n\t\t\t);\n\t\t\tpath = \"Cocoa (Objective-C)\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D31F1208F200ED72DB /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C8C72D21F1208F200ED72DB /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D61F1208F200ED72DB /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1445520EBF641000E01C9 /* Network.framework */,\n\t\t\t\t4CAC2A071F12AFFB00D06046 /* Security.framework */,\n\t\t\t\t4CAC2A081F12AFFB00D06046 /* SecurityInterface.framework */,\n\t\t\t\t4CAC2A0B1F12B01700D06046 /* SystemConfiguration.framework */,\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D71F1208F200ED72DB /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C8C72D31F1208F200ED72DB /* External Frameworks */,\n\t\t\t\t4C8C72D61F1208F200ED72DB /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE143F520EBF5DB000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1440920EBF5DB000E01C9 /* Common */,\n\t\t\t\t4CE1441E20EBF5DB000E01C9 /* Debug */,\n\t\t\t\t4CE143F620EBF5DB000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE143F620EBF5DB000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE143FE20EBF5DB000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE143F920EBF5DB000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE143FC20EBF5DB000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1440920EBF5DB000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1441320EBF5DB000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE1441020EBF5DB000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE1440D20EBF5DB000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE1440C20EBF5DB000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1441120EBF5DB000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1441E20EBF5DB000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1442620EBF5DB000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1442120EBF5DB000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1442420EBF5DB000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1442720EBF5DB000E01C9 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1448120EC0209000E01C9 /* Release.entitlements */,\n\t\t\t);\n\t\t\tname = Sandbox;\n\t\t\tpath = Configurations/Sandbox;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t4C1406411F11942B00C73D53 /* IRC Remote Connection Manager */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4C14064E1F11942B00C73D53 /* Build configuration list for PBXNativeTarget \"IRC Remote Connection Manager\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4C46A02320EC678B00094EA4 /* Resources */,\n\t\t\t\t4C14063F1F11942B00C73D53 /* Frameworks */,\n\t\t\t\t4C14063E1F11942B00C73D53 /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"IRC Remote Connection Manager\";\n\t\t\tproductName = \"Connection Manager\";\n\t\t\tproductReference = 4C1406421F11942B00C73D53 /* IRC Connection Host.xpc */;\n\t\t\tproductType = \"com.apple.product-type.xpc-service\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4C14063A1F11942B00C73D53 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tORGANIZATIONNAME = \"Codeux Software, LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4C1406411F11942B00C73D53 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tLastSwiftMigration = 1100;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4C14063D1F11942B00C73D53 /* Build configuration list for PBXProject \"IRC Remote Connection Manager\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4C1406391F11942B00C73D53;\n\t\t\tproductRefGroup = 4C1406431F11942B00C73D53 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4C1406411F11942B00C73D53 /* IRC Remote Connection Manager */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4C46A02320EC678B00094EA4 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C5274DC20F7D49000B18F9D /* ConnectionErrors.strings in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4C14063E1F11942B00C73D53 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C46A07320EC68C000094EA4 /* IRCConnection.swift in Sources */,\n\t\t\t\t4CACDB5820F747710075AFB5 /* TLOLocalization.m in Sources */,\n\t\t\t\t4C46A07420EC68C000094EA4 /* IRCConnectionSocket.swift in Sources */,\n\t\t\t\t4C46A07520EC68C000094EA4 /* IRCConnectionSocketClassic.swift in Sources */,\n\t\t\t\t4C46A07620EC68C000094EA4 /* IRCConnectionSocketNWF.swift in Sources */,\n\t\t\t\t4C46A06920EC68B800094EA4 /* NSObjectHelper.m in Sources */,\n\t\t\t\t4C46A06A20EC68B800094EA4 /* IRCConnectionConfig.m in Sources */,\n\t\t\t\t4C46A06B20EC68B800094EA4 /* GCDAsyncSocket.m in Sources */,\n\t\t\t\t4C46A06C20EC68B800094EA4 /* GCDAsyncSocketExtensions.m in Sources */,\n\t\t\t\t4C5274DE20F8D50C00B18F9D /* IRCConnectionErrors.m in Sources */,\n\t\t\t\t4C46A06D20EC68B800094EA4 /* TLOTimer.m in Sources */,\n\t\t\t\t4CACDB5B20F7496D0075AFB5 /* TLOLocalization.swift in Sources */,\n\t\t\t\t4C46A07020EC68B800094EA4 /* main.m in Sources */,\n\t\t\t\t4C46A07120EC68B800094EA4 /* RCMProcessDelegate.m in Sources */,\n\t\t\t\t4C46A07220EC68B800094EA4 /* RCMProcessMain.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXVariantGroup section */\n\t\t4C5274DA20F7D49000B18F9D /* ConnectionErrors.strings */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4C5274DB20F7D49000B18F9D /* en */,\n\t\t\t);\n\t\t\tname = ConnectionErrors.strings;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4C14064C1F11942B00C73D53 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1442420EBF5DB000E01C9 /* XPC Services.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C14064D1F11942B00C73D53 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE143FC20EBF5DB000E01C9 /* XPC Services.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/SwiftBridgingHeaderPrivate.h\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C14064F1F11942B00C73D53 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/RCMProcessPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-IRCConnectionHost\";\n\t\t\t\tPRODUCT_NAME = \"IRC Connection Host\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C1406501F11942B00C73D53 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/RCMProcessPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-IRCConnectionHost\";\n\t\t\t\tPRODUCT_NAME = \"IRC Connection Host\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4C14063D1F11942B00C73D53 /* Build configuration list for PBXProject \"IRC Remote Connection Manager\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C14064C1F11942B00C73D53 /* Debug */,\n\t\t\t\t4C14064D1F11942B00C73D53 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4C14064E1F11942B00C73D53 /* Build configuration list for PBXNativeTarget \"IRC Remote Connection Manager\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C14064F1F11942B00C73D53 /* Debug */,\n\t\t\t\t4C1406501F11942B00C73D53 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 4C14063A1F11942B00C73D53 /* Project object */;\n}\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Resources/Language Files/en.lproj/ConnectionErrors.strings",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n *    Copyright (c) 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n\"DNS Error: %@ (%ld)\" = \"DNS Error: %1$@ (%2$ld)\";\n\n\"POSIX Error: %@ (%ld)\" = \"POSIX Error: %1$@ (%2$ld)\";\n"
  },
  {
    "path": "XPC Services/IRC Remote Connection Manager/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>IRC Remote Connection Manager</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>XPC!</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2017 - 2020 Codeux Software, LLC. All rights reserved.</string>\n\t<key>XPCService</key>\n\t<dict>\n\t\t<key>JoinExistingSession</key>\n\t\t<true/>\n\t\t<key>ServiceType</key>\n\t\t<string>Application</string>\n\t</dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Build Scripts/BuildExtensions.sh",
    "content": "#!/bin/sh\n\nset -e\n\nICL_PRODUCT_LOCATION=\"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}\"\nICL_PRODUCT_BINARY=\"${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}\"\n\n# Core Media\ncd \"${PROJECT_DIR}/Extensions/Core Media/\"\n\nxcodebuild -target \"Inline Content Loader Core Media\" \\\n -configuration \"${ICL_EXTENSION_BUILD_SCHEME}\" \\\n ARCHS=\"${ARCHS}\" \\\n CODE_SIGN_IDENTITY=\"${CODE_SIGN_IDENTITY}\" \\\n DEVELOPMENT_TEAM=\"${DEVELOPMENT_TEAM}\" \\\n PROVISIONING_PROFILE_SPECIFIER=\"\" \\\n TEXTUAL_WORKSPACE_DIR=\"${TEXTUAL_WORKSPACE_DIR}\" \\\n TEXTUAL_PRODUCT_LOCATION=\"${TEXTUAL_PRODUCT_LOCATION}\" \\\n ICL_PRODUCT_LOCATION=\"${ICL_PRODUCT_LOCATION}\" \\\n ICL_PRODUCT_BINARY=\"${ICL_PRODUCT_BINARY}\"\n\nexit 0;\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLHelpers.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLHelpers : NSObject\n+ (nullable NSURL *)URLWithString:(NSString *)address;\n@end\n\n@interface ICLHelpers (JSON)\n+ (NSURLSessionDataTask *)requestJSONDataFromURL:(NSURL *)url completionBlock:(void (^)(BOOL success, NSDictionary<NSString *, id> * _Nullable data))completionBlock;\n+ (NSURLSessionDataTask *)requestJSONDataFromAddress:(NSString *)address completionBlock:(void (^)(BOOL success, NSDictionary<NSString *, id> * _Nullable data))completionBlock;\n\n+ (NSURLSessionDataTask *)requestJSONObject:(NSString *)objectKey ofType:(Class)objectType inHierarchy:(nullable NSArray<NSString *> *)hierarchy fromURL:(NSURL *)url completionBlock:(void (^)(id _Nullable object))completionBlock;\n+ (NSURLSessionDataTask *)requestJSONObject:(NSString *)objectKey ofType:(Class)objectType inHierarchy:(nullable NSArray<NSString *> *)hierarchy fromAddress:(NSString *)address completionBlock:(void (^)(id _Nullable object))completionBlock;\n@end\n\n@interface ICLHelpers (Errors)\n@property (copy, readonly, class) NSError *genericValidationFailedError;\n@end\n\n@interface NSString (ICLHelpers)\n/* Given \"youtube.com\" as input, returns if string is\n equal to \"youtube.com\" or has suffix \".youtube.com\" */\n- (BOOL)isDomain:(NSString *)domain;\n- (BOOL)isDomainOrSubdomain:(NSString *)domain;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLInlineContentModule.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLPayload.h\"\n#import \"ICLMediaType.h\"\n\n#import <GRMustache/GRMustache.h>\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class ICLInlineContentModule;\n\n/* See description for -actionBlockForURL: */\ntypedef void (^ICLInlineContentModuleActionBlock)(ICLInlineContentModule *module);\n\n/**\n * Modules are always a subclass, instead of a protocol, to give us\n * greater flexibility when adding private components to the parent.\n */\n@interface ICLInlineContentModule : NSObject\n/**\n * Mutable copy of the payload this module has access to modify.\n * This payload includes the address and the unique identifier.\n */\n@property (readonly, strong) ICLPayloadMutable *payload;\n\n/**\n * Module objects are not allowed to be allocated by a plugin.\n */\n- (instancetype)init NS_UNAVAILABLE;\n\n#pragma mark -\n#pragma mark Rules\n\n/**\n An optional array of domains that the module is specific to.\n\n If this array is non-nil and the domain does not appear in the\n array, then the module is skipped over. One of the action methods\n defined below is never called.\n */\n@property (readonly, copy, nullable, class) NSArray<NSString *> *domains;\n\n#pragma mark -\n#pragma mark Action\n\n/**\n * Returns a block to perform if the module is interested in the URL.\n *\n * The block is passed one argument: a new instance of the module.\n * The block can then use that to do stateful work, or it can\n * disregard the argument and do whatever else it wants.\n *\n * The return value of -actionBlockForURL: is favored over -actionForURL:\n * The latter is never called if -actionBlockForURL: returns a value.\n *\n * nil is returned if this method is not implemented.\n */\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url;\n\n/**\n * Returns a selector to perform if the module is interested in the URL.\n *\n * The selector is performed on a new instance of the module which means\n * the selector returned must be one for an instance method.\n *\n * The selector:\n *   1. Does not return a value (void)\n *   2. Does not take arguments\n *\n * Example:\n *\n * \t\t- (void)performAction\n * \t\t{\n *\n * \t\t}\n *\n * NULL is returned if this method is not implemented.\n */\n+ (nullable SEL)actionForURL:(NSURL *)url;\n\n#pragma mark -\n#pragma mark Context\n\n/**\n Whether the module's content is an image or video.\n This can include video services, not just video files.\n */\n@property (readonly, class) BOOL contentImageOrVideo;\n\n/**\n Whether the module's content is a regular file,\n such as an image or video. Not an iframe, embedded,\n or dynamic content (such as JavaScript).\n */\n@property (readonly, class) BOOL contentIsFile;\n\n/**\n Whether the module might add content to the DOM which\n is not trusted such as HTML downloaded from some website.\n A module that loads remote JavaScript libraries is also\n considered untrusted.\n */\n@property (readonly, class) BOOL contentUntrusted;\n\n/**\n Whether module might load content that is not safe for work.\n */\n@property (readonly, class) BOOL contentNotSafeForWork;\n\n#pragma mark -\n#pragma mark Resources\n\n/* If a non-nil value is returned for any of these properties,\n then that value is inserted into the payload. */\n/* See ICLPayload.h for a description of each property. */\n@property (copy, readonly, nullable) NSArray<NSURL *> *styleResources;\n@property (copy, readonly, nullable) NSArray<NSURL *> *scriptResources;\n@property (copy, readonly, nullable) NSString *entrypoint;\n\n/**\n URL to a file that is a mustache template.\n\n Given a URL, the -template property automatically returns\n a reference to the template.\n\n It is possible to render HTML multiple ways which means you\n do not need a template unless you want one.\n */\n@property (readonly, nullable) NSURL *templateURL;\n\n/**\n Reference to mustache template found at -templateURL\n */\n@property (readonly, nullable) GRMustacheTemplate *template;\n@end\n\n#pragma mark -\n#pragma mark Completion\n\n@interface ICLInlineContentModule (Completion)\n/**\n Called by module to inform the media handler that no\n more modifications will be made to the payload and that\n the contents of it should now be processed.\n\n - Warnings\n\n This method will throw an exception if the module has\n already been finalized by calling this method or a sibling.\n*/\n- (void)finalize;\n\n/**\n Called by module to inform the media handler that no\n more modifications will be made to the payload and that\n the contents of it should now be processed.\n\n - Warnings\n\n This method will throw an exception if the module has\n already been finalized by calling this method or a sibling.\n\n - Arguments\n\n @param error\n  nil to inform the media handler that the media should be\n  inlined or an error describing why that cannot happen.\n */\n- (void)finalizeWithError:(nullable NSError *)error;\n\n/**\n Called by the module to inform the media handler that\n the module wants to cancel performing any work.\n\n - Warnings\n\n This method will throw an exception if the module has\n already been finalized by calling this method or a sibling.\n */\n- (void)cancel;\n\n/**\n A module that is capable of performing work on more than\n one type of media (such as images and videos) can call\n this method when it is sure what type of media it has.\n\n The media will be checked by performing a web request\n to ensure that it is in fact the type described.\n\n - See also\n\n See -deferAsType:performCheck: for a detailed description.\n*/\n- (void)deferAsType:(ICLMediaType)type; // performCheck = YES\n\n/**\n A module that is capable of performing work on more than\n one type of media (such as images and videos) can call\n this method when it is sure what type of media it has.\n\n - Examples\n\n For example, if the module has the URL \"example.com\"\n and believes it is a regular image, then it can call\n this method with the type ICLMediaTypeImage to inform\n the media handler to inline the URL as an image.\n\n - Notes\n\n Calling this method to inline images or other media\n types is only required if the module is not already\n a subclass of one of the root classes responsible for\n handling these types of media.\n\n - Warnings\n\n This method will throw an exception if the module has\n already been finalized by calling this method or a sibling.\n\n - Arguments\n\n @param type\n  The type of media that the content should be treated as.\n  The types supported are:\n  • ICLMediaTypeImage for images,\n  • ICLMediaTypeVideo for videos,\n  • ICLMediaTypeVideoGif for videos presented as a gif\n\n @param performCheck\n  Whether to perform a web request to ensure that\n  it is in fact the type described.\n */\n- (void)deferAsType:(ICLMediaType)type performCheck:(BOOL)performCheck;\n\n/**\n Returns YES if a type is supported by -deferAsType:\n */\n+ (BOOL)isTypeDeferrable:(ICLMediaType)type;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLMediaAssessment.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLMediaType.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface ICLMediaAssessment : XRPortablePropertyObject\n- (instancetype)init NS_UNAVAILABLE;\n\n/**\n Designated initializer\n */\n- (instancetype)initWithURL:(NSURL *)url asType:(ICLMediaType)type NS_DESIGNATED_INITIALIZER;\n\n/**\n The final URL that was assessed.\n\n This URL may be different when compared to that passed\n to the assessor due to HTTP redirects.\n */\n@property (readonly, copy) NSURL *url;\n\n/**\n The type of the media.\n\n The type is determined by the Content-Type header.\n */\n@property (readonly) ICLMediaType type;\n\n/**\n Value of the Content-Type header\n */\n@property (readonly, copy) NSString *contentType;\n\n/**\n Value of the Content-Length header\n */\n@property (readonly) unsigned long long contentLength;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface ICLMediaAssessmentMutable : ICLMediaAssessment\n@property (nonatomic, assign, readwrite) ICLMediaType type;\n@property (nonatomic, copy, readwrite) NSString *contentType; // Defaults to \"application/binary\"\n@property (nonatomic, assign, readwrite) unsigned long long contentLength;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLMediaAssessor.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLMediaType.h\"\n#import \"ICLMediaAssessment.h\"\n\n/* Given a URL, the accessor will load the contents of that URL\n to determine what type of media it is: image, video, or other.\n It will also perform validations, based on user preference.\n For example, if the user doesn't want to see images larger than\n 300 pixels and the image is 400 pixels, then you get an error. */\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Both values will never be nil together.\n There will either be an assessment or an error for why there isn't. */\n/* It is possible for there to be an assessment AND an error.\n If that is the case, the assessor was able to determine the type\n of media, but it was unable to perform extended validation.\n Treat as failure. */\ntypedef void (^ICLMediaAssessorCompletionBlock)(ICLMediaAssessment * _Nullable assessment, NSError * _Nullable error);\n\n@interface ICLMediaAssessor : NSObject\n- (instancetype)init NS_UNAVAILABLE;\n\n/* Use the following two methods to determine what type of media a URL is. */\n+ (instancetype)assessorForURL:(NSURL *)url completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock;\n+ (instancetype)assessorForAddress:(NSString *)address completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock;\n\n/* Use the following two methods to determine whether the URL is the type of media. */\n/* If you are expecting the URL to be a specific type of media, these methods are better. */\n+ (instancetype)assessorForURL:(NSURL *)url withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock;\n+ (instancetype)assessorForAddress:(NSString *)address withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock;\n\n/* Suspend assessment */\n- (void)suspend;\n\n/* Resume assessment */\n- (void)resume;\n\n/* Logging */\n+ (void)logError:(NSError *)error;\n@end\n\n/* Error codes */\ntypedef NS_ENUM(NSUInteger, ICLMediaAssessorErrorCode)\n{\n\t/* Catch all */\n\tICLMediaAssessorErrorCodeAssessmentFailed = 0,\n\n\t/* Endpoint did not respond with OK (200) */\n\tICLMediaAssessorErrorCodeUnexpectedStatusCode = 1001,\n\n\t/* Content-Type header is improperly formatted */\n\tICLMediaAssessorErrorCodeMalformedContentType = 1002,\n\n\t/* Content-Length header is improperly formatted */\n\tICLMediaAssessorErrorCodeMalformedContentLength = 1003,\n\n\t/* Unexpected media type */\n\tICLMediaAssessorErrorCodeUnexpectedType = 1004,\n\n\t/* Unexpected response type (not HTTP) */\n\tICLMediaAssessorErrorCodeUnexpectedResponse = 1005,\n\n\t/* Maximum response size exceeded */\n\tICLMediaAssessorErrorCodeContentLengthExceeded = 1006,\n\n\t/* Image validation: Maximum width exceeded */\n\tICLMediaAssessorErrorCodeMaximumWidthExceeded = 1007,\n\n\t/* Image validation: Maximum height exceeded */\n\tICLMediaAssessorErrorCodeMaximumHeightExceeded = 1008,\n};\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLMediaType.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, ICLMediaType)\n{\n\tICLMediaTypeUnknown = 0,\n\tICLMediaTypeImage,\n\tICLMediaTypeVideo,\n\tICLMediaTypeVideoGif,\n\tICLMediaTypeOther\n};\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLPayload.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma mark -\n#pragma mark Immutable Object\n\n@interface ICLPayload : XRPortablePropertyObject\n/**\n Payload objects are not allowed to be allocated by a plugin.\n Each new instance of ICLContentLoaderModule is given a mutable payload.\n Modify that, then the loader will create an immutable copy when appropriate.\n */\n- (instancetype)init NS_UNAVAILABLE;\n\n/**\n The URL associated with this payload.\n */\n@property (copy, readonly) NSURL *url;\n\n/**\n String value of -url property.\n */\n@property (copy, readonly) NSString *address;\n\n/**\n The URL of the content to inline, such as an image, can be\n different than the value of -url because of redirects or API\n requests. The -urlToInline property can be used to get and set\n this different URL.\n\n If left unchanged, the value of this property mirrors -url\n */\n@property (copy, readonly) NSURL *urlToInline;\n\n/**\n String value of the -urlToInline property.\n */\n@property (copy, readonly) NSString *addressToInline;\n\n/**\n The unique identifier associated with this payload.\n */\n@property (copy, readonly) NSString *uniqueIdentifier;\n\n/**\n The view responsible for this payload.\n */\n@property (copy, readonly) NSString *viewIdentifier;\n\n/**\n The line number associated with this payload.\n */\n@property (copy, readonly) NSString *lineNumber;\n\n/**\n Position of payload in relation to others with same line number.\n */\n@property (readonly) NSUInteger index;\n\n/**\n The length of the content. This value is optional.\n */\n@property (readonly) unsigned long long contentLength;\n\n/**\n The size of the content. This value is optional.\n */\n@property (readonly) NSSize contentSize;\n\n/**\n A collection of paths for .css files that need to be loaded to allow the\n rendered HTML to appear correct.\n */\n@property (copy, readonly) NSArray<NSURL *> *styleResources;\n\n/**\n A collection of paths for .js files that need to be loaded to allow the\n rendered HTML to appear correct.\n\n */\n@property (copy, readonly) NSArray<NSURL *> *scriptResources;\n\n/**\n Rendered HTML or an empty string\n\n - Discussion:\n\n A module does not need to render the HTML through Objective-C.\n It can render it in JavaScript or by some other means.\n\n If a module renders HTML using Objective-C, then the final result\n can be assigned to this property.\n */\n@property (copy, readonly) NSString *html;\n\n#pragma mark -\n#pragma mark Advanced\n\n/**\n The name of a JavaSript object that a function named entrypoint()\n is called on for the purpose of inlining this payload.\n\n - Inheritance\n\n Textual offers a prototype named InlineMediaPrototype that your\n object can inherit from. This prototype already contains an\n entrypoint() function which you can override.\n\n - Function Arguments:\n\n The entrypoint function takes two arguments:\n\n 1. The value of the -entrypointPayload property defined below.\n 2. A callback function which itself takes one argument:\n    The HTML that the entrypoint function wants to insert.\n\n - Requirements:\n\n • If the `html` property of this payload is empty:\n     1. An entrypoint function is REQUIRED.\n • If the `html` property of this payload is NOT empty:\n     1. An entrypoint function is OPTIONAL.\n     2. If an entrypoint function is NOT set, then the value of\n        the `html` property is inserted without assitance.\n     3. If an entrypoin function is set, then the value of\n        the contents of the payload are passed to it without\n        inserting the value of the `html` property.\n        The entrypoint function can then decide to insert the\n        HTML when it wants by calling a callback function.\n\n - Example:\n\n ````\n    MyObject.entrypoint = function(payload, callbackFunction)\n    {\n        // Do work here...\n\n        callbackFunction(\"some HTML to display\");\n    }\n ````\n\n */\n@property (copy, readonly, nullable) NSString *entrypoint;\n\n/**\n A dictionary that is passed as the first argument to -entrypoint.\n\n - Dictionary Contents:\n\n This dictionary is guaranteed to always contain the following keys:\n\n  1. \"html\" (string)\n  2. \"url\" (string)\n  3. \"urlToInline\" (string)\n  4. \"lineNumber\" (string)\n  5. \"uniqueIdentifier\" (string)\n\n The value of these keys mirror the payload's.\n\n ICLPayload will not allow you to override the value of these keys.\n\n - Types:\n\n Types are translated as such:\n\n ````\n Objective-C          JavaScript\n -----------          ----------\n NSArray         =>   array\n BOOL            =>   boolean\n NSNumber        =>   number\n NSDictionary    =>   object\n NSString        =>   string\n NSURL           =>   string\n ````\n\n Custom types are treated as \"undefined\"\n */\n@property (copy, readonly) NSDictionary<NSString *, id <NSCopying>> *entrypointPayload;\n\n/**\n An optional class that is appended to the inlined media.\n\n - Examples\n\n • inlineStreamable is used for Streamable,\n • inlineVimeo is used for Vimeo,\n • inlineYouTube is used for YouTube\n */\n@property (copy, readonly) NSString *classAttribute;\n@end\n\n#pragma mark -\n#pragma mark Mutable Object\n\n@interface ICLPayloadMutable : ICLPayload\n@property (nonatomic, copy, readwrite) NSURL *urlToInline;\n@property (nonatomic, assign, readwrite) unsigned long long contentLength;\n@property (nonatomic, assign, readwrite) NSSize contentSize;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *styleResources;\n@property (nonatomic, copy, readwrite) NSArray<NSURL *> *scriptResources;\n@property (nonatomic, copy, readwrite) NSString *html;\n@property (nonatomic, copy, nullable, readwrite) NSString *entrypoint;\n@property (nonatomic, copy, null_resettable, readwrite) NSDictionary<NSString *, id <NSCopying>> *entrypointPayload;\n@property (nonatomic, copy, readwrite) NSString *classAttribute;\n\n- (instancetype)init;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/ICLPluginProtocol.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <Foundation/Foundation.h>\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/**\n The ICLPluginProtocol protocol defines methods and properties\n that a plugin can implement.\n */\n@protocol ICLPluginProtocol <NSObject>\n\n@required\n\n/**\n An array of classes that are a subclass of ICLInlineContentModule\n\n It is recommended that classes inside a plugin use the prefix ICP\n so that their classes do not conflict with those that already exist.\n */\n@property (readonly, copy, class) NSArray<Class> *modules;\n\n@end\n\nNS_ASSUME_NONNULL_END\n\n/* Import root classes a module can subclass (if they want) */\n#import \"ICMInlineHTML.h\"\n#import \"ICMInlineImage.h\"\n#import \"ICMInlineVideo.h\"\n\n/* Import helpers that a plugin can access */\n#import \"ICLHelpers.h\"\n#import \"ICLMediaAssessor.h\"\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Internal/ICLInlineContentModuleInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModulePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLInlineContentModule ()\n{\n@private\n\tICLProcessMain *_process;\n\tICLPayloadMutable *_payload;\n\tBOOL _moduleFinalized;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Internal/ICLMediaAssessmentInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLMediaAssessment ()\n{\n@protected\n\tNSURL *_url;\n\tICLMediaType _type;\n\tNSString *_contentType;\n\tunsigned long long _contentLength;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Internal/ICLPayloadInternal.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLPayload.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLPayload ()\n{\n@protected\n\tNSURL *_urlToInline;\n\tunsigned long long _contentLength;\n\tNSSize _contentSize;\n\tNSArray<NSURL *> *_styleResources;\n\tNSArray<NSURL *> *_scriptResources;\n\tNSString *_html;\n\tNSString *_entrypoint;\n\tNSDictionary<NSString *, id <NSCopying>> *_entrypointPayload;\n\tNSString *_classAttribute;\n\n@private\n\tNSURL *_url;\n\tNSString *_lineNumber;\n\tNSString *_uniqueIdentifier;\n\tNSString *_viewIdentifier;\n\tNSUInteger _index;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/CoreModulesImportsPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineHTML.h\"\n#import \"ICMInlineVideo.h\"\n#import \"ICMInlineImage.h\"\n\n#import \"ICMAssessedMedia.h\"\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLInlineContentModulePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentProtocol.h\"\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class GRMustacheTemplate, ICLPayloadMutable, ICLProcessMain;\n\n@interface ICLInlineContentModule ()\n- (instancetype)initWithPayload:(ICLPayloadMutable *)payload inProcess:(ICLProcessMain *)process;\n\n- (instancetype)initWithDeferredModule:(ICLInlineContentModule *)module;\n@end\n\n@interface ICLInlineContentModule (CompletionPrivate)\n- (void)finalizePreflight;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLInlineContentProtocol.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* *** XPC PROTOCOL HEADERS ARE PRIVATE *** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class ICLPayload;\n\n#pragma mark -\n#pragma mark Server Protocol\n\n@protocol ICLInlineContentServerProtocol\n@required\n\n- (void)warmServiceByLoadingPluginsAtLocations:(NSArray<NSURL *> *)pluginLocations;\n- (void)warmServiceByRegisteringDefaults:(NSDictionary<NSString *, id> *)defaults;\n\n- (void)processURL:(NSURL *)url withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index inView:(NSString *)viewIdentifier;\n\n- (void)processPayload:(ICLPayload *)payload;\n@end\n\n#pragma mark -\n#pragma mark Client Protocol\n\n@protocol ICLInlineContentClientProtocol\n@required\n\n- (void)processingPayloadSucceeded:(ICLPayload *)payload;\n- (void)processingPayload:(ICLPayload *)payload failedWithError:(NSError *)error;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLPayloadPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLPayload.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLPayload (ICLPayloadPrivate)\n- (nullable instancetype)initWithURL:(NSURL *)url\n\t\t\t\twithUniqueIdentifier:(NSString *)uniqueIdentifier\n\t\t\t\t\t\tatLineNumber:(NSString *)lineNumber\n\t\t\t\t\t\t\t   index:(NSUInteger)index\n\t\t\t\t\t\t\t  inView:(NSString *)viewIdentifier;\n\n- (instancetype)initWithDeferredPayload:(ICLPayload *)payload;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLPluginManagerPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLPluginManager : NSObject\n+ (ICLPluginManager *)sharedPluginManager;\n\n- (void)loadPluginsAtLocations:(NSArray<NSURL *> *)pluginLocations;\n\n@property (readonly, copy) NSArray<Class> *modules;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLProcessDelegatePrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLProcessDelegate : NSObject <NSXPCListenerDelegate>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLProcessMainPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentProtocol.h\"\n#import \"ICLMediaType.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@class ICLInlineContentModule;\n\n@interface ICLProcessMain : NSObject <ICLInlineContentServerProtocol>\n- (instancetype)init NS_UNAVAILABLE;\n- (instancetype)initWithXPCConnection:(NSXPCConnection *)connection NS_DESIGNATED_INITIALIZER;\n\n- (void)_finalizeModule:(ICLInlineContentModule *)module withError:(nullable NSError *)error;\n- (void)_cancelModule:(ICLInlineContentModule *)module;\n- (void)_deferModule:(ICLInlineContentModule *)module asType:(ICLMediaType)type performCheck:(BOOL)performCheck;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Headers/Private/ICLProcessPCHPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CocoaExtensions/CocoaExtensions.h>\n\n#import <GRMustache/GRMustache.h>\n\n#import \"StaticDefinitions.h\"\n\nextern NSErrorDomain const ICLInlineContentErrorDomain;\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Assessed Media/ICMAssessedMedia.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Checks every URL to determine if it is an\n image or video, then delegates responsibility\n for module to an instance of a root class. */\n\n@interface ICMAssessedMedia : ICLInlineContentModule\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Assessed Media/ICMAssessedMedia.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n#import \"ICLMediaAssessor.h\"\n#import \"ICMAssessedMedia.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMAssessedMedia ()\n@property (nonatomic, strong, nullable) ICLMediaAssessor *mediaAssessor;\n@end\n\n@implementation ICMAssessedMedia\n\n- (void)_assessMedia\n{\n\tNSURL *url = self.payload.url;\n\n\tICLMediaAssessor *mediaAssessor =\n\t[ICLMediaAssessor assessorForURL:url\n\t\t\t\t\t completionBlock:^(ICLMediaAssessment *assessment, NSError *error) {\n\t\t\t\t\t\t ICLMediaType type = ((assessment) ? assessment.type : ICLMediaTypeUnknown);\n\t\t\t\t\t\t \n\t\t\t\t\t\t BOOL safeToLoad = (assessment != nil && error == nil && [ICLInlineContentModule isTypeDeferrable:type]);\n\n\t\t\t\t\t\t if (safeToLoad) {\n\t\t\t\t\t\t\t [self _safeToLoadMediaOfType:type atURL:assessment.url];\n\t\t\t\t\t\t } else {\n\t\t\t\t\t\t\t [self _unsafeToLoadMedia];\n\t\t\t\t\t\t }\n\n\t\t\t\t\t\t self.mediaAssessor = nil;\n\t\t\t\t\t }];\n\n\tself.mediaAssessor = mediaAssessor;\n\n\t[mediaAssessor resume];\n}\n\n- (void)_unsafeToLoadMedia\n{\n\t[self cancel];\n}\n\n- (void)_safeToLoadMediaOfType:(ICLMediaType)type atURL:(NSURL *)url\n{\n\tself.payload.urlToInline = url;\n\n\t[self deferAsType:type performCheck:NO];\n}\n\n#pragma mark -\n#pragma mark Action\n\n+ (nullable SEL)actionForURL:(NSURL *)url\n{\n\tif ([TPCPreferences inlineMediaCheckEverything] == NO) {\n\t\treturn NULL;\n\t}\n\n\treturn @selector(_assessMedia);\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (BOOL)contentImageOrVideo\n{\n\treturn YES;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineHTML.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* ICMInlineHTMLFoundation does nothing.\n It exists for internal use. */\n@interface ICMInlineHTMLFoundation : ICLInlineContentModule\n@end\n\n/* Proper class to sublcass if that is your thing. */\n@interface ICMInlineHTML : ICMInlineHTMLFoundation\n- (void)performActionForHTML:(NSString *)unescapedHTML;\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForHTML:(NSString *)unescapedHTML;\n\n- (void)notifyUnableToPresentHTML;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineHTML.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineHTML.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMInlineHTML\n\n- (void)performActionForHTML:(NSString *)unescapedHTML\n{\n\tNSParameterAssert(unescapedHTML != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t\t@\"classAttribute\" : payload.classAttribute,\n\t\t@\"unescapedHTML\" : unescapedHTML,\n\t\t@\"uniqueIdentifier\" : payload.uniqueIdentifier\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n- (void)notifyUnableToPresentHTML\n{\n\t[self cancel];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForHTML:(NSString *)html\n{\n\tNSParameterAssert(html != nil);\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMInlineHTML *moduleTyped = (id)module;\n\n\t\t[moduleTyped performActionForHTML:html];\n\t} copy];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Foundation\n\n@implementation ICMInlineHTMLFoundation\n\n- (nullable NSArray<NSURL *> *)styleResources\n{\n\tstatic NSArray<NSURL *> *styleResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tstyleResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineHTML\" withExtension:@\"css\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn styleResources;\n}\n\n- (nullable NSArray<NSURL *> *)scriptResources\n{\n\tstatic NSArray<NSURL *> *scriptResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tscriptResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineHTML\" withExtension:@\"js\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn scriptResources;\n}\n\n- (nullable NSURL *)templateURL\n{\n\treturn [RZMainBundle() URLForResource:@\"ICMInlineHTML\" withExtension:@\"mustache\" subdirectory:@\"Components\"];\n}\n\n- (nullable NSString *)entrypoint\n{\n\treturn @\"_ICMInlineHTML\";\n}\n\n+ (BOOL)contentUntrusted\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineImage.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* ICMInlineImageFoundation does nothing.\n It exists for internal use. */\n@interface ICMInlineImageFoundation : ICLInlineContentModule\n@end\n\n/* Proper class to sublcass if that is your thing. */\n@interface ICMInlineImage : ICMInlineImageFoundation\n- (void)performAction; // checkImage = YES\n- (void)performActionWithImageCheck:(BOOL)checkImage;\n\n- (void)performActionForURL:(NSURL *)url; // bypassImageCheck = NO\n- (void)performActionForURL:(NSURL *)url bypassImageCheck:(BOOL)bypassImageCheck;\n\n- (void)performActionForAddress:(NSString *)address; // bypassImageCheck = NO\n- (void)performActionForAddress:(NSString *)address bypassImageCheck:(BOOL)bypassImageCheck;\n\n+ (ICLInlineContentModuleActionBlock)actionBlockURL:(NSURL *)url; // bypassImageCheck = NO\n+ (ICLInlineContentModuleActionBlock)actionBlockURL:(NSURL *)url bypassImageCheck:(BOOL)bypassImageCheck;\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address; // bypassImageCheck = NO\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address bypassImageCheck:(BOOL)bypassImageCheck;\n\n- (void)notifyUnsafeToLoadImage;\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineImage.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n#import \"ICLHelpers.h\"\n#import \"ICLMediaAssessor.h\"\n#import \"ICMInlineImage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMInlineImage ()\n@property (nonatomic, strong, nullable) ICLMediaAssessor *imageCheck;\n@end\n\n@implementation ICMInlineImage\n\n- (void)performAction\n{\n\t[self performActionWithImageCheck:YES];\n}\n\n- (void)performActionWithImageCheck:(BOOL)checkImage\n{\n\tif (checkImage) {\n\t\t[self _performImageCheck];\n\t} else {\n\t\t[self _safeToLoadImage];\n\t}\n}\n\n- (void)performActionForURL:(NSURL *)url\n{\n\t[self performActionForURL:url bypassImageCheck:NO];\n}\n\n- (void)performActionForURL:(NSURL *)url bypassImageCheck:(BOOL)bypassImageCheck\n{\n\tNSParameterAssert(url != nil);\n\n\tNSAssert((self.imageCheck == nil), @\"Module already initialized\");\n\n\tself.payload.urlToInline = url;\n\n\t[self performActionWithImageCheck:(bypassImageCheck == NO)];\n}\n\n- (void)performActionForAddress:(NSString *)address\n{\n\t[self performActionForAddress:address bypassImageCheck:NO];\n}\n\n- (void)performActionForAddress:(NSString *)address bypassImageCheck:(BOOL)bypassImageCheck\n{\n\tNSParameterAssert(address != nil);\n\n\tNSURL *url = [ICLHelpers URLWithString:address];\n\n\t[self performActionForURL:url bypassImageCheck:bypassImageCheck];\n}\n\n- (void)_performImageCheck\n{\n\tICLPayload *payload = self.payload;\n\n\tICLMediaAssessor *imageCheck =\n\t[ICLMediaAssessor assessorForURL:payload.urlToInline\n\t\t\t\t\t\t\twithType:ICLMediaTypeImage\n\t\t\t\t\t completionBlock:^(ICLMediaAssessment *assessment, NSError *error) {\n\t\t\t\t\t\t BOOL safeToLoad = (error == nil);\n\n\t\t\t\t\t\t if (safeToLoad) {\n\t\t\t\t\t\t\t [self _safeToLoadImage];\n\t\t\t\t\t\t } else {\n\t\t\t\t\t\t\t [self _unsafeToLoadImage];\n\n\t\t\t\t\t\t\t [ICLMediaAssessor logError:error];\n\t\t\t\t\t\t }\n\n\t\t\t\t\t\t self.imageCheck = nil;\n\t\t\t\t\t }];\n\n\tself.imageCheck = imageCheck;\n\n\t[imageCheck resume];\n}\n\n- (void)_unsafeToLoadImage\n{\n\t[self notifyUnsafeToLoadImage];\n}\n\n- (void)_safeToLoadImage\n{\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t\t@\"anchorLink\" : payload.address,\n\t\t@\"classAttribute\" : payload.classAttribute,\n\t\t@\"imageURL\" : payload.addressToInline,\n\t\t@\"preferredMaximumWidth\" : @([TPCPreferences inlineMediaMaxWidth]),\n\t\t@\"uniqueIdentifier\" : payload.uniqueIdentifier\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n- (void)notifyUnsafeToLoadImage\n{\n\t[self cancel];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (ICLInlineContentModuleActionBlock)actionBlockURL:(NSURL *)url\n{\n\treturn [self actionBlockURL:url bypassImageCheck:NO];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockURL:(NSURL *)url bypassImageCheck:(BOOL)bypassImageCheck\n{\n\tNSParameterAssert(url != nil);\n\n\treturn [self actionBlockForAddress:url.absoluteString bypassImageCheck:bypassImageCheck];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address\n{\n\treturn [self actionBlockForAddress:address bypassImageCheck:NO];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address bypassImageCheck:(BOOL)bypassImageCheck\n{\n\tNSParameterAssert(address != nil);\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMInlineImage *moduleTyped = (id)module;\n\n\t\t[moduleTyped performActionForAddress:address bypassImageCheck:NO];\n\t} copy];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (NSArray<NSString *> *)validImageContentTypes\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"image/gif\",\n\t\t  @\"image/jpeg\",\n\t\t  @\"image/png\",\n\t\t  @\"image/svg+xml\",\n\t\t  @\"image/tiff\",\n\t\t  @\"image/x-ms-bmp\"];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (NSArray<NSString *> *)validVideoContentTypes\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"video/3gpp\",\n\t\t  @\"video/3gpp2\",\n\t\t  @\"video/mp4\",\n\t\t  @\"video/quicktime\",\n\t\t  @\"video/x-m4v\"];\n\t});\n\n\treturn cachedValue;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Foundation\n\n@implementation ICMInlineImageFoundation\n\n+ (BOOL)contentImageOrVideo\n{\n\treturn YES;\n}\n\n- (nullable NSURL *)templateURL\n{\n\treturn [RZMainBundle() URLForResource:@\"ICMInlineImage\" withExtension:@\"mustache\" subdirectory:@\"Components\"];\n}\n\n- (nullable NSArray<NSURL *> *)styleResources\n{\n\tstatic NSArray<NSURL *> *styleResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tstyleResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineImage\" withExtension:@\"css\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn styleResources;\n}\n\n- (nullable NSArray<NSURL *> *)scriptResources\n{\n\tstatic NSArray<NSURL *> *scriptResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tscriptResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"InlineImageLiveResize\" withExtension:@\"js\"],\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineImage\" withExtension:@\"js\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn scriptResources;\n}\n\n- (nullable NSString *)entrypoint\n{\n\treturn @\"_ICMInlineImage\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineVideo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* ICMInlineVideoFoundation does nothing.\n It exists for internal use. */\n@interface ICMInlineVideoFoundation : ICLInlineContentModule\n@property (nonatomic, assign) BOOL videoAutoplayEnabled; // default = NO\n@property (nonatomic, assign) BOOL videoControlsEnabled; // default = YES\n@property (nonatomic, assign) BOOL videoLoopEnabled; // default = NO\n@property (nonatomic, assign) BOOL videoMuteEnabled; // default = NO\n@property (nonatomic, assign) NSTimeInterval videoStartTime; // default = 0\n@property (nonatomic, assign) double videoPlaybackSpeed; // default = 1.0 | >= 0.125 and <= 6.0\n\n+ (NSTimeInterval)parseYouTubeEsqueTimestamp:(NSString *)timestamp;\n@end\n\n/* Proper class to sublcass if that is your thing. */\n@interface ICMInlineVideo : ICMInlineVideoFoundation\n- (void)performAction; // checkVideo = YES\n- (void)performActionWithVideoCheck:(BOOL)checkVideo;\n\n- (void)performActionForAddress:(NSString *)address; // bypassVideoCheck = NO\n- (void)performActionForAddress:(NSString *)address bypassVideoCheck:(BOOL)bypassVideoCheck;\n\n- (void)performActionForURL:(NSURL *)url; // bypassVideoCheck = NO\n- (void)performActionForURL:(NSURL *)url bypassVideoCheck:(BOOL)bypassVideoCheck;\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address; // bypassVideoCheck = NO\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address bypassVideoCheck:(BOOL)bypassVideoCheck;\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForForURL:(NSURL *)url; // bypassVideoCheck = NO\n+ (ICLInlineContentModuleActionBlock)actionBlockForForURL:(NSURL *)url bypassVideoCheck:(BOOL)bypassVideoCheck;\n\n- (void)notifyUnsafeToLoadVideo;\n@end\n\n/* Subclass that can be used for videos that should be treated as such:\n videoAutoplayEnabled = YES,\n videoControlsEnabled = NO,\n videoLoopEnabled = YES,\n videoMuteEnabled = YES */\n@interface ICMInlineGifVideo : ICMInlineVideo\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Modules/Root Classes/ICMInlineVideo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n#import \"ICLHelpers.h\"\n#import \"ICLInlineContentModulePrivate.h\"\n#import \"ICLMediaAssessor.h\"\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMInlineVideo ()\n@property (nonatomic, strong, nullable) ICLMediaAssessor *videoCheck;\n@end\n\n@implementation ICMInlineVideo\n\n- (void)performAction\n{\n\t[self performActionWithVideoCheck:YES];\n}\n\n- (void)performActionWithVideoCheck:(BOOL)checkVideo\n{\n\tif (checkVideo) {\n\t\t[self _performVideoCheck];\n\t} else {\n\t\t[self _safeToLoadVideo];\n\t}\n}\n\n- (void)performActionForURL:(NSURL *)url\n{\n\t[self performActionForURL:url bypassVideoCheck:NO];\n}\n\n- (void)performActionForURL:(NSURL *)url bypassVideoCheck:(BOOL)bypassVideoCheck\n{\n\tNSParameterAssert(url != nil);\n\n\tNSAssert((self.videoCheck == nil), @\"Module already initialized\");\n\n\tself.payload.urlToInline = url;\n\n\t[self performActionWithVideoCheck:(bypassVideoCheck == NO)];\n}\n\n- (void)performActionForAddress:(NSString *)address\n{\n\t[self performActionForAddress:address bypassVideoCheck:NO];\n}\n\n- (void)performActionForAddress:(NSString *)address bypassVideoCheck:(BOOL)bypassVideoCheck\n{\n\tNSParameterAssert(address != nil);\n\n\tNSURL *url = [ICLHelpers URLWithString:address];\n\n\t[self performActionForURL:url bypassVideoCheck:bypassVideoCheck];\n}\n\n- (void)_performVideoCheck\n{\n\tICLPayload *payload = self.payload;\n\n\tICLMediaAssessor *videoCheck =\n\t[ICLMediaAssessor assessorForURL:payload.urlToInline\n\t\t\t\t\t\t\twithType:ICLMediaTypeVideo\n\t\t\t\t\t completionBlock:^(ICLMediaAssessment *assessment, NSError *error) {\n\t\t\t\t\t\t BOOL safeToLoad = (error == nil);\n\n\t\t\t\t\t\t if (safeToLoad) {\n\t\t\t\t\t\t\t [self _safeToLoadVideo];\n\t\t\t\t\t\t } else {\n\t\t\t\t\t\t\t [self _unsafeToLoadVideo];\n\n\t\t\t\t\t\t\t [ICLMediaAssessor logError:error];\n\t\t\t\t\t\t }\n\n\t\t\t\t\t\t self.videoCheck = nil;\n\t\t\t\t\t }];\n\n\tself.videoCheck = videoCheck;\n\n\t[videoCheck resume];\n}\n\n- (void)_unsafeToLoadVideo\n{\n\t[self notifyUnsafeToLoadVideo];\n}\n\n- (void)_safeToLoadVideo\n{\n\tICLPayloadMutable *payload = self.payload;\n\n\tdouble playbackSpeed = self.videoPlaybackSpeed;\n\n\tif (playbackSpeed < 0.125 || playbackSpeed > 6.0) {\n\t\tplaybackSpeed = 1.0;\n\t}\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t\t@\"anchorLink\" : payload.address,\n\t\t@\"classAttribute\" : payload.classAttribute,\n\t\t@\"preferredMaximumWidth\" : @([TPCPreferences inlineMediaMaxWidth]),\n\t\t@\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t\t@\"videoAutoplayEnabled\" : @(self.videoAutoplayEnabled),\n\t\t@\"videoControlsEnabled\" : @(self.videoControlsEnabled),\n\t\t@\"videoLoopEnabled\" : @(self.videoLoopEnabled),\n\t\t@\"videoMuteEnabled\" : @(self.videoMuteEnabled),\n\t\t@\"videoPlaybackSpeed\" : @(playbackSpeed),\n\t\t@\"videoStartTime\" : @(self.videoStartTime),\n\t\t@\"videoURL\" : payload.addressToInline\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n- (void)notifyUnsafeToLoadVideo\n{\n\t[self cancel];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForForURL:(NSURL *)url\n{\n\treturn [self actionBlockForForURL:url bypassVideoCheck:NO];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForForURL:(NSURL *)url bypassVideoCheck:(BOOL)bypassVideoCheck\n{\n\tNSParameterAssert(url != nil);\n\n\treturn [self actionBlockForAddress:url.absoluteString bypassVideoCheck:bypassVideoCheck];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address\n{\n\treturn [self actionBlockForAddress:address bypassVideoCheck:NO];\n}\n\n+ (ICLInlineContentModuleActionBlock)actionBlockForAddress:(NSString *)address bypassVideoCheck:(BOOL)bypassVideoCheck\n{\n\tNSParameterAssert(address != nil);\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMInlineVideo *moduleTyped = (id)module;\n\n\t\t[moduleTyped performActionForAddress:address bypassVideoCheck:bypassVideoCheck];\n\t} copy];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Foundation\n\n@implementation ICMInlineVideoFoundation\n\n- (instancetype)initWithPayload:(ICLPayloadMutable *)payload inProcess:(ICLProcessMain *)process\n{\n\tif ((self = [super initWithPayload:payload inProcess:process])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\tself.videoControlsEnabled = YES;\n\n\tself.videoPlaybackSpeed = 1.0;\n}\n\n+ (BOOL)contentImageOrVideo\n{\n\treturn YES;\n}\n\n- (nullable NSURL *)templateURL\n{\n\treturn [RZMainBundle() URLForResource:@\"ICMInlineVideo\" withExtension:@\"mustache\" subdirectory:@\"Components\"];\n}\n\n- (nullable NSArray<NSURL *> *)styleResources\n{\n\tstatic NSArray<NSURL *> *styleResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tstyleResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineVideo\" withExtension:@\"css\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn styleResources;\n}\n\n- (nullable NSArray<NSURL *> *)scriptResources\n{\n\tstatic NSArray<NSURL *> *scriptResources = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tscriptResources =\n\t\t@[\n\t\t  [RZMainBundle() URLForResource:@\"ICMInlineVideo\" withExtension:@\"js\" subdirectory:@\"Components\"]\n\t\t];\n\t});\n\n\treturn scriptResources;\n}\n\n- (nullable NSString *)entrypoint\n{\n\treturn @\"_ICMInlineVideo\";\n}\n\n+ (NSTimeInterval)parseYouTubeEsqueTimestamp:(NSString *)timestamp\n{\n\tNSParameterAssert(timestamp != nil);\n\t\n\tif (timestamp.isPositiveWholeNumber) {\n\t\treturn timestamp.doubleValue;\n\t}\n\t\n\t__block NSTimeInterval startTime = 0;\n\t\n\t__block BOOL matchedHour = NO;\n\t__block BOOL matchedMinute = NO;\n\t__block BOOL matchedSecond = NO;\n\n\t[timestamp enumerateMatchesOfRegularExpression:@\"[0-9]+[hms]\"\n\t\t\t\t\t\t\t\t\t\t withBlock:^(NSRange range, BOOL *stop)\n\t {\n\t\t NSString *fragment = [timestamp substringWithRange:range];\n\t\t \n\t\t NSString *fragmentUnit = [fragment substringAtIndex:0 toLength:(-1)];\n\t\t NSString *fragmentValue = [fragment substringAtIndex:(-1) toLength:0];\n\t\t \n\t\t /* Could use dictionary to index each formatter, but\n\t\t  that seemed like overkill for this implemention. */\n\t\t if (matchedHour == NO && [fragmentUnit isEqualToString:@\"h\"]) {\n\t\t\t matchedHour = YES;\n\t\t\t startTime += (fragmentValue.integerValue * 3600); // 1 hour\n\t\t } else if (matchedMinute == NO && [fragmentUnit isEqualToString:@\"m\"]) {\n\t\t\t matchedMinute = YES;\n\t\t\t startTime += (fragmentValue.integerValue * 60); // 1 minute\n\t\t } else if (matchedSecond == NO && [fragmentUnit isEqualToString:@\"s\"]) {\n\t\t\t matchedSecond = YES;\n\t\t\t startTime += fragmentValue.integerValue;\n\t\t }\n\t\t \n\t\t if (matchedHour && matchedMinute && matchedSecond) {\n\t\t\t*stop = YES;\n\t\t }\n\t }\n\t\t\t\t\t\t\t\t\t\t   options:NSCaseInsensitiveSearch];\n\t\n\treturn startTime;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Gif Video\n\n@implementation ICMInlineGifVideo\n\n- (instancetype)initWithPayload:(ICLPayloadMutable *)payload inProcess:(ICLProcessMain *)process\n{\n\tif ((self = [super initWithPayload:payload inProcess:process])) {\n\t\t[self prepareInitialState];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareInitialState\n{\n\t[super prepareInitialState];\n\n\tself.videoAutoplayEnabled = YES;\n\tself.videoControlsEnabled = NO;\n\tself.videoLoopEnabled = YES;\n\tself.videoMuteEnabled = YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLHelpers.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLHelpers\n\n+ (nullable NSURL *)URLWithString:(NSString *)address\n{\n\tNSParameterAssert(address != nil);\n\n\tif ([address hasPrefix:@\"//\"]) {\n\t\taddress = [@\"https:\" stringByAppendingString:address];\n\t}\n\n\treturn [NSURL URLWithString:address];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Errors\n\n@implementation ICLHelpers (Errors)\n\n+ (NSError *)genericValidationFailedError\n{\n\tstatic NSError *error = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\terror =\n\t\t[NSError errorWithDomain:ICLInlineContentErrorDomain\n\t\t\t\t\t\t\tcode:1003\n\t\t\t\t\t\tuserInfo:@{\n\t\t\tNSLocalizedDescriptionKey : @\"Validation failed\"\n\t\t}];\n\t});\n\n\treturn error;\n}\n\n@end\n\n#pragma mark -\n#pragma mark JSON\n\n@implementation ICLHelpers (JSON)\n\n+ (NSURLSessionDataTask *)requestJSONObject:(NSString *)objectKey ofType:(Class)objectType inHierarchy:(nullable NSArray<NSString *> *)hierarchy fromURL:(NSURL *)url completionBlock:(void (^)(id _Nullable object))completionBlock\n{\n\tNSParameterAssert(objectKey != nil);\n\tNSParameterAssert(objectType != NULL);\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\treturn [self requestJSONDataFromURL:url completionBlock:^(BOOL success, NSDictionary<NSString *,id> * _Nullable data) {\n\t\t/* Return nothing if underlying request failed. */\n\t\tif (success == NO) {\n\t\t\tcompletionBlock(nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Traverse hiearchy */\n\t\t/* hierarchy is the path we will traverse to find objectKey.\n\t\t All keys assigned to hierarchy are expected to be a dictionary.\n\t\t If a key in hierarchy does not exist or is not a dictionary,\n\t\t then the request exits. */\n\t\tNSDictionary *currentContext = data;\n\n\t\tif (hierarchy) {\n\t\t\tfor (NSString *hierarchyKey in hierarchy) {\n\t\t\t\tid hierarchyContext = [currentContext dictionaryForKey:hierarchyKey];\n\n\t\t\t\t/* Return nothing if we cannot go deeper. */\n\t\t\t\tif (hierarchyContext == nil) {\n\t\t\t\t\tcompletionBlock(nil);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcurrentContext = hierarchyContext;\n\t\t\t}\n\t\t}\n\n\t\t/* Get object value and check type */\n\t\tid objectValue = currentContext[objectKey];\n\n\t\t/* Object is not a type we are interested in */\n\t\tif ([objectValue isKindOfClass:objectType] == NO) {\n\t\t\tcompletionBlock(nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Object is a type we are interested in */\n\t\tcompletionBlock(objectValue);\n\t}];\n}\n\n+ (NSURLSessionDataTask *)requestJSONObject:(NSString *)objectKey ofType:(Class)objectType inHierarchy:(nullable NSArray<NSString *> *)hierarchy fromAddress:(NSString *)address completionBlock:(void (^)(id _Nullable object))completionBlock\n{\n\tNSParameterAssert(objectKey != nil);\n\tNSParameterAssert(objectType != NULL);\n\tNSParameterAssert(address != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSURL *url = [NSURL URLWithString:address];\n\n\treturn [self requestJSONObject:objectKey ofType:objectType inHierarchy:hierarchy fromURL:url completionBlock:completionBlock];\n}\n\n+ (NSURLSessionDataTask *)requestJSONDataFromURL:(NSURL *)url completionBlock:(void (^)(BOOL success, NSDictionary<NSString *, id> * _Nullable data))completionBlock\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSURLSession *session = [NSURLSession sharedSession];\n\n\tNSURLSessionDataTask *sessionTask =\n\t[session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {\n\t\t/* Report error if data is nil or we have a non-OK response from server. */\n\t\tif (data == nil || ((NSHTTPURLResponse *)response).statusCode != 200) {\n\t\t\tif (error) {\n\t\t\t\tLogToConsoleError(\"Request failed with error: %{public}@\",\n\t\t\t\t\terror.localizedDescription);\n\t\t\t}\n\n\t\t\tcompletionBlock(NO, nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Decode JSON data */\n\t\tNSError *decodedJsonError;\n\n\t\tNSDictionary *decodedJson = [NSJSONSerialization JSONObjectWithData:data options:0 error:&decodedJsonError];\n\n\t\tif (decodedJson == nil) {\n\t\t\tLogToConsoleError(\"Failed to decode response: %{public}@\",\n\t\t\t\tdecodedJsonError.localizedDescription);\n\n\t\t\tcompletionBlock(NO, nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ([decodedJson isKindOfClass:[NSDictionary class]] == NO) {\n\t\t\tcompletionBlock(NO, nil);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Post JSON data */\n\t\tcompletionBlock(YES, decodedJson);\n\t}];\n\n\t[sessionTask resume];\n\n\treturn sessionTask;\n}\n\n+ (NSURLSessionDataTask *)requestJSONDataFromAddress:(NSString *)address completionBlock:(void (^)(BOOL success, NSDictionary<NSString *, id> * _Nullable data))completionBlock\n{\n\tNSParameterAssert(address != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSURL *url = [NSURL URLWithString:address];\n\n\treturn [self requestJSONDataFromURL:url completionBlock:completionBlock];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Strings\n\n@implementation NSString (ICLHelpers)\n\n- (BOOL)isDomain:(NSString *)domain\n{\n\tNSParameterAssert(domain != nil);\n\n\treturn [self isEqualToString:domain];\n}\n\n- (BOOL)isDomainOrSubdomain:(NSString *)domain\n{\n\tNSParameterAssert(domain != nil);\n\n\treturn ([self isEqualToString:domain] || [self hasSuffix:[@\".\" stringByAppendingString:domain]]);\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLInlineContentModule.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"ICLPayloadPrivate.h\"\n#import \"ICLProcessMainPrivate.h\"\n#import \"ICLInlineContentModuleInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLInlineContentModule\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithPayload:(ICLPayloadMutable *)payload inProcess:(ICLProcessMain *)process\n{\n\tNSParameterAssert(payload != nil);\n\tNSParameterAssert(process != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_payload = payload;\n\n\t\tself->_process = process;\n\n\t\t[self mergePropertiesIntoPayload];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithDeferredModule:(ICLInlineContentModule *)module\n{\n\tNSParameterAssert(module != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_payload = [[ICLPayloadMutable alloc] initWithDeferredPayload:module.payload];\n\n\t\tself->_process = module->_process;\n\n\t\t[self mergePropertiesIntoPayload];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)mergePropertiesIntoPayload\n{\n\tNSArray *scriptResources = self.scriptResources;\n\n\tif (scriptResources) {\n\t\tself.payload.scriptResources = scriptResources;\n\t}\n\n\tNSArray *styleResources = self.styleResources;\n\n\tif (styleResources) {\n\t\tself.payload.styleResources = styleResources;\n\t}\n\n\tNSString *entrypoint = self.entrypoint;\n\n\tif (entrypoint) {\n\t\tself.payload.entrypoint = entrypoint;\n\t}\n}\n\n- (nullable NSURL *)templateURL\n{\n\treturn nil;\n}\n\n- (nullable GRMustacheTemplate *)template\n{\n\tNSURL *templateURL = self.templateURL;\n\n\tif (templateURL == nil || templateURL.isFileURL == NO) {\n\t\treturn nil;\n\t}\n\n\tNSError *templateLoadError;\n\n\tGRMustacheTemplate *template = [GRMustacheTemplate templateFromContentsOfURL:templateURL error:&templateLoadError];\n\n\tif (template == nil) {\n\t\tLogToConsoleError(\"Failed to load template '%{public}@': %{public}@\",\n\t\t\ttemplateURL.standardizedTildePath, templateLoadError.localizedDescription);\n\t}\n\n\treturn template;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\treturn nil;\n}\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\treturn nil;\n}\n\n+ (nullable SEL)actionForURL:(NSURL *)url\n{\n\treturn NULL;\n}\n\n- (nullable NSArray<NSURL *> *)styleResources\n{\n\treturn nil;\n}\n\n- (nullable NSArray<NSURL *> *)scriptResources\n{\n\treturn nil;\n}\n\n- (nullable NSString *)entrypoint\n{\n\treturn nil;\n}\n\n+ (BOOL)contentImageOrVideo\n{\n\treturn NO;\n}\n\n+ (BOOL)contentUntrusted\n{\n\treturn NO;\n}\n\n+ (BOOL)contentNotSafeForWork\n{\n\treturn NO;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn NO;\n}\n\n@end\n\n#pragma mark -\n#pragma mark Completion\n\n@implementation ICLInlineContentModule (Completion)\n\n- (void)_finalizeAll\n{\n\tself->_moduleFinalized = YES;\n\n\tself->_process = nil;\n}\n\n- (void)finalize\n{\n\t[self finalizeWithError:nil];\n}\n\n- (void)finalizeWithError:(nullable NSError *)error\n{\n\tNSAssert((self->_moduleFinalized == NO), @\"Module already finalized\");\n\n\t[self finalizePreflight];\n\n\t[self->_process _finalizeModule:self withError:error];\n\n\t[self _finalizeAll];\n}\n\n- (void)cancel\n{\n\tNSAssert((self->_moduleFinalized == NO), @\"Module already cancelled\");\n\n\t[self finalizePreflight];\n\n\t[self->_process _cancelModule:self];\n\n\t[self _finalizeAll];\n}\n\n+ (BOOL)isTypeDeferrable:(ICLMediaType)type\n{\n\treturn (type == ICLMediaTypeImage ||\n\t\t\ttype == ICLMediaTypeVideo ||\n\t\t\ttype == ICLMediaTypeVideoGif);\n}\n\n- (void)deferAsType:(ICLMediaType)type\n{\n\t[self deferAsType:type performCheck:YES];\n}\n\n- (void)deferAsType:(ICLMediaType)type performCheck:(BOOL)performCheck\n{\n\tNSAssert((self->_moduleFinalized == NO), @\"Module already deferred\");\n\n\t[self finalizePreflight];\n\n\t[self->_process _deferModule:self asType:type performCheck:performCheck];\n\n\t[self _finalizeAll];\n}\n\n@end\n\n#pragma mark -\n#pragma mark Completion (Private)\n\n@implementation ICLInlineContentModule (CompletionPrivate)\n\n- (void)finalizePreflight\n{\n\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLMediaAssessment.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"ICLMediaAssessment.h\"\n#import \"ICLMediaAssessmentInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLMediaAssessment\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithURL:(NSURL *)url asType:(ICLMediaType)type\n{\n\tNSParameterAssert(url != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_url = [url copy];\n\n\t\tself->_type = type;\n\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)populateWithDecoder:(NSCoder *)aDecoder\n{\n\tself->_url = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@\"url\"];\n\n\tself->_type = [aDecoder decodeUnsignedIntegerForKey:@\"type\"];\n\n\tself->_contentType = [aDecoder decodeStringForKey:@\"contentType\"];\n\tself->_contentLength = [aDecoder decodeUnsignedIntegerForKey:@\"contentLength\"];\n\n\treturn YES;\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder\n{\n\t[aCoder encodeObject:self->_url forKey:@\"url\"];\n\n\t[aCoder encodeUnsignedInteger:self->_type forKey:@\"type\"];\n\n\t[aCoder encodeString:self->_contentType forKey:@\"contentType\"];\n\t[aCoder encodeUnsignedInteger:self->_contentLength forKey:@\"contentLength\"];\n}\n\n+ (BOOL)supportsSecureCoding\n{\n\treturn YES;\n}\n\n- (void)populateDefaultsPostflight\n{\n\tSetVariableIfNil(self->_contentType, @\"application/binary\");\n}\n\n- (void)initializedClassHealthCheck\n{\n\tNSParameterAssert(self->_url != nil);\n\tNSParameterAssert(self->_contentType != nil);\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tICLMediaAssessment *object = [self allocForCopyAsMutable:mutableCopy];\n\n\tobject->_url = self->_url;\n\n\tobject->_type = self->_type;\n\n\tobject->_contentType = self->_contentType;\n\tobject->_contentLength = self->_contentLength;\n\n\treturn [object initOnCopy];\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [ICLMediaAssessmentMutable self];\n}\n\n@end\n\n#pragma mark -\n\n@implementation ICLMediaAssessmentMutable\n\n@dynamic type;\n@dynamic contentType;\n@dynamic contentLength;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [ICLMediaAssessment self];\n}\n\n- (void)setType:(ICLMediaType)type\n{\n\tif (self->_type != type) {\n\t\tself->_type = type;\n\t}\n}\n\n- (void)setContentType:(NSString *)contentType\n{\n\tif (self->_contentType != contentType) {\n\t\tself->_contentType = [contentType copy];\n\t}\n}\n\n- (void)setContentLength:(unsigned long long)contentLength\n{\n\tif (self->_contentLength != contentLength) {\n\t\tself->_contentLength = contentLength;\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLMediaAssessor.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferences.h\"\n#import \"ICLMediaAssessment.h\"\n#import \"ICLMediaAssessor.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n/* Hardcoded maximum width for images (and maybe other media) */\n#define _assessorMaximumImageWidth\t\t\t\t7200\n\nNSString * const ICLMediaAssessorErrorDomain = @\"ICLMediaAssessorErrorDomain\";\n\n@interface ICLMediaAssessorConfiguration : NSObject\n@property (nonatomic, copy) ICLMediaAssessorCompletionBlock completionBlock;\n@property (nonatomic, assign) ICLMediaType expectedType;\n@property (nonatomic, copy) NSURL *url;\n@end\n\n@interface ICLMediaAssessorLimits : NSObject\n@property (nonatomic, assign) NSUInteger imageMaximumWidth;\n@property (nonatomic, assign) NSUInteger imageMaximumHeight;\n@property (nonatomic, assign) unsigned long long imageMaximumFilesize;\n@end\n\n@interface ICLMediaAssessorRequest : NSObject\n@property (nonatomic, strong, nullable) NSURLSession *session;\n@property (nonatomic, strong, nullable) NSURLSessionTask *task;\n@property (nonatomic, copy, nullable) NSError *alternateError;\n@property (nonatomic, assign) BOOL doNotFinalize;\n@end\n\n@interface ICLMediaAssessorState : NSObject\n@property (nonatomic, copy, nullable) ICLMediaAssessment *assessment;\n@property (nonatomic, assign) BOOL performExtendedValidation;\n@end\n\n@interface ICLMediaAssessor ()\n@property (nonatomic, strong, nullable) ICLMediaAssessorConfiguration *config;\n@property (nonatomic, strong, nullable) ICLMediaAssessorLimits *limits;\n@property (nonatomic, strong, nullable) ICLMediaAssessorRequest *request;\n@property (nonatomic, strong, nullable) ICLMediaAssessorState *state;\n@end\n\n@implementation ICLMediaAssessor\n\n#pragma mark -\n#pragma mark Construction\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n+ (instancetype)assessorForAddress:(NSString *)address completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\treturn [self assessorForAddress:address withType:ICLMediaTypeUnknown completionBlock:completionBlock];\n}\n\n+ (instancetype)assessorForURL:(NSURL *)url completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\treturn [self assessorForURL:url withType:ICLMediaTypeUnknown completionBlock:completionBlock];\n}\n\n+ (instancetype)assessorForAddress:(NSString *)address withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\tICLMediaAssessor *object = [[self alloc] initWithAddress:address withType:type completionBlock:completionBlock];\n\n\treturn object;\n}\n\n+ (instancetype)assessorForURL:(NSURL *)url withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\tICLMediaAssessor *object = [[self alloc] initWithURL:url withType:type completionBlock:completionBlock];\n\n\treturn object;\n}\n\n- (instancetype)initWithAddress:(NSString *)address withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\tNSParameterAssert(address != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\tNSURL *url = [NSURL URLWithString:address];\n\n\treturn [self initWithURL:url withType:type completionBlock:completionBlock];\n}\n\n- (instancetype)initWithURL:(NSURL *)url withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(url.isFileURL == NO);\n\tNSParameterAssert(completionBlock != nil);\n\n\tif ((self = [super init])) {\n\t\t[self prepareToAssessURL:url withType:type completionBlock:completionBlock];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (void)prepareToAssessURL:(NSURL *)url withType:(ICLMediaType)type completionBlock:(ICLMediaAssessorCompletionBlock)completionBlock\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(completionBlock != nil);\n\n\t/* Prepare configuration */\n\tICLMediaAssessorConfiguration *config = [ICLMediaAssessorConfiguration new];\n\n\tconfig.completionBlock = completionBlock;\n\n\tconfig.expectedType = type;\n\n\tconfig.url = url;\n\n\tself.config = config;\n}\n\n#pragma mark -\n#pragma mark Actions (Public)\n\n- (void)resume\n{\n\t[self _assess];\n}\n\n- (void)suspend\n{\n\t[self _cancel];\n}\n\n#pragma mark -\n#pragma mark Actions (Private)\n\n- (void)_assess\n{\n\tNSAssert((self.request == nil), @\"An assessment is already in progress\");\n\n\tICLMediaAssessorConfiguration *config = self.config;\n\n\tNSAssert((config != nil), @\"-assess called after an assessment finalized\");\n\n\t/* Prepare request */\n\tICLMediaAssessorRequest *request = [ICLMediaAssessorRequest new];\n\n\tNSURLSession *urlSession = [NSURLSession sessionWithConfiguration:[self.class _sharedSessionConfiguration] delegate:(id)self delegateQueue:nil];\n\n\trequest.session = urlSession;\n\n\t/* We use a data task which is always GET.\n\t Many services block HEAD requests, so we use GET.\n\t When we are only interested in the headers, we close the\n\t connection after receiving them, so we don't waste resources. */\n\tNSURLSessionDataTask *urlSessionTask = [urlSession dataTaskWithURL:config.url];\n\n\trequest.task = urlSessionTask;\n\n\tself.request = request;\n\n\t/* Prepare limits */\n\tICLMediaType expectedType = self.config.expectedType;\n\n\tif (expectedType == ICLMediaTypeUnknown ||\n\t\texpectedType == ICLMediaTypeImage)\n\t{\n\t\tICLMediaAssessorLimits *limits = [ICLMediaAssessorLimits new];\n\n\t\tlimits.imageMaximumWidth = _assessorMaximumImageWidth;\n\t\tlimits.imageMaximumHeight = [TPCPreferences inlineMediaMaxHeight];\n\t\tlimits.imageMaximumFilesize = [TPCPreferences inlineImagesMaxFilesize];\n\n\t\tself.limits = limits;\n\t}\n\n\t/* Perform request */\n\t[urlSessionTask resume];\n}\n\n- (void)_cancel\n{\n\t[self _cancelRequest];\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)_cancelRequest\n{\n\tICLMediaAssessorRequest *request = self.request;\n\n\tif (request == nil) {\n\t\treturn;\n\t}\n\n\trequest.doNotFinalize = YES;\n\n\tNSURLSession *session = request.session;\n\n\t[session invalidateAndCancel];\n}\n\n- (void)_flushRequestState\n{\n\tself.limits = nil;\n\tself.state = nil;\n\tself.request = nil;\n}\n\n- (void)_finalizeAssessmentWithError:(nullable NSError *)error\n{\n\tif (error.isURLSessionCancelError) {\n\t\terror = self.request.alternateError;\n\t}\n\n\t[self _performCompletionBlockWithError:error];\n\n\t[self _flushRequestState];\n\n\tself.config = nil;\n}\n\n- (void)_performCompletionBlockWithError:(nullable NSError *)error\n{\n\tICLMediaAssessorConfiguration *config = self.config;\n\n\tICLMediaAssessment *assessment = self.state.assessment;\n\n\t/* This condition is typically true when we refuse an authentication challenge. */\n\tif (error == nil && assessment == nil) {\n\t\terror = [self _errorWithDescription:@\"Assessment failed\" code:ICLMediaAssessorErrorCodeAssessmentFailed];\n\t}\n\n\tconfig.completionBlock(assessment, error);\n}\n\n- (NSError *)_errorWithDescription:(NSString *)errorDescription code:(ICLMediaAssessorErrorCode)errorCode\n{\n\tNSParameterAssert(errorDescription != nil);\n\n\treturn\n\t[NSError errorWithDomain:ICLMediaAssessorErrorDomain\n\t\t\t\t\t\tcode:errorCode\n\t\t\t\t\tuserInfo:@{\n\t\tNSLocalizedDescriptionKey : errorDescription\n\t}];\n}\n\n#pragma mark -\n#pragma mark URL Session Delegate\n\n+ (NSURLSessionConfiguration *)_sharedSessionConfiguration\n{\n\tstatic NSURLSessionConfiguration *config = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tconfig = [NSURLSessionConfiguration ephemeralSessionConfiguration];\n\n\t\t/* Ignore local caches */\n\t\tconfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;\n\n\t\t/* Do not send cookies from local store */\n\t\tconfig.HTTPShouldSetCookies = NO;\n\n\t\t/* Do not allow cookies to be set */\n\t\tconfig.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyNever;\n\t});\n\n\treturn config;\n}\n\n- (nullable ICLMediaAssessorState *)_readHeadersInWithError:(NSError **)error\n{\n\tNSParameterAssert(error != NULL);\n\n\tNSHTTPURLResponse *response = (id)self.request.task.response;\n\n\t/* Read in status code */\n\tif (response.statusCode != 200) {\n\t\t*error = [self _errorWithDescription:@\"Endpoint did not respond with OK (200)\" code:ICLMediaAssessorErrorCodeUnexpectedStatusCode];\n\n\t\treturn nil;\n\t}\n\n\t/* Read in content type */\n\tNSString *contentType = response.MIMEType;\n\n\tif (contentType.length > 128) {\n\t\t*error = [self _errorWithDescription:@\"Content-Type header is improperly formatted\" code:ICLMediaAssessorErrorCodeMalformedContentType];\n\n\t\treturn nil;\n\t}\n\n\t/* Read in content length */\n\tlong long contentLength = response.expectedContentLength;\n\n\tif (contentLength <= 0) {\n\t\t*error = [self _errorWithDescription:@\"Content-Length header is improperly formatted\" code:ICLMediaAssessorErrorCodeMalformedContentLength];\n\n\t\treturn nil;\n\t}\n\n\t/* Figure out what type of media this is */\n\tICLMediaType mediaType = ICLMediaTypeOther;\n\n\tBOOL performExtendedValidation = NO;\n\n\t/* Content is an image */\n\tif ([[self.class validImageContentTypes] containsObject:contentType])\n\t{\n\t\tmediaType = ICLMediaTypeImage;\n\t}\n\n\t/* Content is a video */\n\telse if ([[self.class validVideoContentTypes] containsObject:contentType])\n\t{\n\t\tmediaType = ICLMediaTypeVideo;\n\t}\n\n\t/* Is this a type we are interested in? */\n\tICLMediaType expectedType = self.config.expectedType;\n\n\tif (expectedType != ICLMediaTypeUnknown &&\n\t\texpectedType != mediaType)\n\t{\n\t\t*error = [self _errorWithDescription:@\"Unexpected media type\" code:ICLMediaAssessorErrorCodeUnexpectedType];\n\n\t\treturn nil;\n\t}\n\n\t/* Perform basic validation */\n\tswitch (mediaType) {\n\t\tcase ICLMediaTypeImage:\n\t\t{\n\t\t\tICLMediaAssessorLimits *limits = self.limits;\n\n\t\t\t/* Limit maximum filesize */\n\t\t\tif (contentLength > limits.imageMaximumFilesize) {\n\t\t\t\t*error = [self _errorWithDescription:@\"Content-Length exceeds maximum allowed\" code:ICLMediaAssessorErrorCodeContentLengthExceeded];\n\n\t\t\t\treturn nil;\n\t\t\t}\n\n\t\t\t/* Limiting the height of an image requires us to download\n\t\t\t the contents of the image first, which we do by setting\n\t\t\t the performExtendedValidation flag on the state. */\n\t\t\tif (limits.imageMaximumHeight > 0) {\n\t\t\t\tperformExtendedValidation = YES;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* Complete read in */\n\tICLMediaAssessmentMutable *assessment =\n\t[[ICLMediaAssessmentMutable alloc] initWithURL:response.URL asType:mediaType];\n\n\tassessment.contentType = contentType;\n\tassessment.contentLength = contentLength;\n\n\tICLMediaAssessorState *state = [ICLMediaAssessorState new];\n\n\tstate.assessment = assessment;\n\n\tstate.performExtendedValidation = performExtendedValidation;\n\n\treturn state;\n}\n\n#pragma mark\n#pragma mark URL Session Delegate Cont.\n\n- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler\n{\n\t/* Response might not be an HTTP response if we\n\t end up receiving a redirect to a data URL. */\n\tif ([response isKindOfClass:[NSHTTPURLResponse class]] == NO) {\n\t\tself.request.alternateError =\n\t\t[self _errorWithDescription:@\"Invalid response type (not HTTP)\" code:ICLMediaAssessorErrorCodeUnexpectedResponse];\n\n\t\tcompletionHandler(NSURLSessionResponseCancel);\n\n\t\treturn;\n\t}\n\n\t/* Perform basic assessment of request.\n\t -readHeadersIn returning a nil value indicates that\n\t something was erroneous and we should not continue. */\n\tNSError *readHeadersInError;\n\n\tICLMediaAssessorState *state = [self _readHeadersInWithError:&readHeadersInError];\n\n\tif (state == nil) {\n\t\tself.request.alternateError = readHeadersInError;\n\n\t\tcompletionHandler(NSURLSessionResponseCancel);\n\n\t\treturn;\n\t}\n\n\tself.state = state;\n\n\t/* Some requests may require us to download the data\n\t of the media to perform extended validation, such\n\t as when the user limits the height of images. */\n\t/* When we don't have to perform extended validation,\n\t we can just cancel any further actions because we\n\t already have enough from the headers. */\n\tif (state.performExtendedValidation == NO) {\n\t\tcompletionHandler(NSURLSessionResponseCancel);\n\n\t\treturn;\n\t}\n\n\t/* Change to download task */\n\tcompletionHandler(NSURLSessionResponseBecomeDownload);\n}\n\n- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse * _Nullable cachedResponse))completionHandler\n{\n\t/* Do not perform caching */\n\n\tcompletionHandler(nil);\n}\n\n- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler\n{\n\t/* Follow redirects */\n\n\tcompletionHandler(request);\n}\n\n- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler\n{\n\t/* Refuse challenge requests */\n\n\tNSString *authenticationMethod = challenge.protectionSpace.authenticationMethod;\n\n\tif ([authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic] ||\n\t\t[authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPDigest])\n\t{\n\t\tcompletionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);\n\n\t\treturn;\n\t}\n\n\tcompletionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);\n}\n\n- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask\n{\n\tself.request.task = downloadTask;\n}\n\n- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location\n{\n\t/* According to the documentation for NSURLSession,\n\t the file at the URL will be deleted once this delegate\n\t call completes which means we do not have to do much:\n\t Just perform our extended validation, then return. */\n\n\tNSError *extendedValidationError;\n\n\tif ([self _performExtendedValidationAtURL:location withError:&extendedValidationError]) {\n\t\treturn; /* Success */\n\t}\n\n\tself.request.alternateError = extendedValidationError;\n\n\t[session invalidateAndCancel];\n}\n\n- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite\n{\n\t/* Don't allow our Content-Length to lie to us/ */\n\n\tif ([self _downloadProgressExceededMaximumFilesize:totalBytesWritten] == NO) {\n\t\treturn; /* Success */\n\t}\n\n\tself.request.alternateError =\n\t[self _errorWithDescription:@\"Maximum response size exceeded\" code:ICLMediaAssessorErrorCodeContentLengthExceeded];\n\n\t[session invalidateAndCancel];\n}\n\n- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error\n{\n\t/* If -suspend was called on this object,\n\t cleanup the request but do not finalize. */\n\tif (self.request.doNotFinalize) {\n\t\t[self _flushRequestState];\n\n\t\treturn;\n\t}\n\n\t[self _finalizeAssessmentWithError:error];\n}\n\n#pragma mark -\n#pragma mark Basic Validation\n\n+ (NSArray<NSString *> *)validImageContentTypes\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"image/gif\",\n\t\t  @\"image/jpeg\",\n\t\t  @\"image/png\",\n\t\t  @\"image/svg+xml\",\n\t\t  @\"image/tiff\",\n\t\t  @\"image/x-ms-bmp\"];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (NSArray<NSString *> *)validVideoContentTypes\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"video/3gpp\",\n\t\t  @\"video/3gpp2\",\n\t\t  @\"video/mp4\",\n\t\t  @\"video/quicktime\",\n\t\t  @\"video/x-m4v\"];\n\t});\n\n\treturn cachedValue;\n}\n\n#pragma mark -\n#pragma mark Extended Validation\n\n- (BOOL)_downloadProgressExceededMaximumFilesize:(unsigned long long)downloadProgress\n{\n\tunsigned long long maximumFilesize = 0;\n\n\tswitch (self.state.assessment.type) {\n\t\tcase ICLMediaTypeImage:\n\t\t{\n\t\t\tmaximumFilesize = self.limits.imageMaximumFilesize;\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (maximumFilesize == 0) {\n\t\treturn NO; /* Success */\n\t}\n\n\treturn (downloadProgress > maximumFilesize);\n}\n\n- (BOOL)_performExtendedValidationAtURL:(NSURL *)url withError:(NSError **)error\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(error != NULL);\n\n\tswitch (self.state.assessment.type) {\n\t\tcase ICLMediaTypeImage:\n\t\t{\n\t\t\treturn [self _performExtendedValidationForImageAtURL:url withError:error];\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn YES; /* Success */\n}\n\n- (BOOL)_performExtendedValidationForImageAtURL:(NSURL *)url withError:(NSError **)error\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(error != NULL);\n\n\tCGImageSourceRef image = CGImageSourceCreateWithURL((__bridge CFURLRef)url, NULL);\n\n\tif (image == NULL) {\n\t\t*error =\n\t\t[self _errorWithDescription:@\"Image validation: CGImageSourceCreateWithURL() returned NULL\" code:ICLMediaAssessorErrorCodeAssessmentFailed];\n\n\t\treturn NO;\n\t}\n\n\tCFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(image, 0, NULL);\n\n\tif (imageProperties == NULL) {\n\t\tCFRelease(image);\n\n\t\t*error =\n\t\t[self _errorWithDescription:@\"Image validation: CGImageSourceCopyPropertiesAtIndex() returned NULL\" code:ICLMediaAssessorErrorCodeAssessmentFailed];\n\n\t\treturn NO;\n\t}\n\n\tNSNumber *imageWidth = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);\n\tNSNumber *imageHeight = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);\n\n\tCFRelease(image);\n\tCFRelease(imageProperties);\n\n\tICLMediaAssessorLimits *limits = self.limits;\n\n\tif (imageWidth.integerValue > limits.imageMaximumWidth)\n\t{\n\t\t*error = [self _errorWithDescription:@\"Image validation: Maximum width exceeded\" code:ICLMediaAssessorErrorCodeMaximumWidthExceeded];\n\n\t\treturn NO;\n\t}\n\telse if (imageHeight.integerValue > limits.imageMaximumHeight)\n\t{\n\t\t*error = [self _errorWithDescription:@\"Image validation: Maximum height exceeded\" code:ICLMediaAssessorErrorCodeMaximumHeightExceeded];\n\n\t\treturn NO;\n\t}\n\n\treturn YES; /* Success */\n}\n\n#pragma mark -\n#pragma mark Logging\n\n+ (void)logError:(NSError *)error\n{\n\tNSParameterAssert(error != nil);\n\n\tif ([error.domain isEqualToString:ICLMediaAssessorErrorDomain] == NO) {\n\t\treturn;\n\t}\n\n\tICLMediaAssessorErrorCode errorCode = error.code;\n\n\tswitch (errorCode) {\n\t\tcase ICLMediaAssessorErrorCodeAssessmentFailed:\n\t\tcase ICLMediaAssessorErrorCodeUnexpectedStatusCode:\n\t\tcase ICLMediaAssessorErrorCodeMalformedContentType:\n\t\tcase ICLMediaAssessorErrorCodeMalformedContentLength:\n\t\tcase ICLMediaAssessorErrorCodeUnexpectedResponse:\n\t\t{\n\t\t\tLogToConsoleDebug(\"Assessor fatal error: %{public}@\",\n\t\t\t\terror.localizedDescription);\n\t\t}\n\t\tcase ICLMediaAssessorErrorCodeUnexpectedType:\n\t\tcase ICLMediaAssessorErrorCodeContentLengthExceeded:\n\t\tcase ICLMediaAssessorErrorCodeMaximumWidthExceeded:\n\t\tcase ICLMediaAssessorErrorCodeMaximumHeightExceeded:\n\t\t{\n\t\t\tLogToConsoleDebug(\"Assessor validation error: %{public}@\",\n\t\t\t\terror.localizedDescription);\n\t\t}\n\t} // switch()\n}\n\n@end\n\n#pragma mark -\n\n@implementation ICLMediaAssessorConfiguration\n@end\n\n@implementation ICLMediaAssessorLimits\n@end\n\n@implementation ICLMediaAssessorRequest\n@end\n\n@implementation ICLMediaAssessorState\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLPayloadLocal.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"ICLPayloadInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLPayload (ICLPayloadPrivate)\n\n- (nullable instancetype)initWithURL:(NSURL *)url\n\t\t\t\twithUniqueIdentifier:(NSString *)uniqueIdentifier\n\t\t\t\t\t\tatLineNumber:(NSString *)lineNumber\n\t\t\t\t\t\t\t   index:(NSUInteger)index\n\t\t\t\t\t\t\t  inView:(NSString *)viewIdentifier\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(viewIdentifier != nil);\n\n\tif ((self = [super init])) {\n\t\tself->_url = [url copy];\n\t\tself->_lineNumber = [lineNumber copy];\n\t\tself->_index = index;\n\t\tself->_uniqueIdentifier = [uniqueIdentifier copy];\n\t\tself->_viewIdentifier = [viewIdentifier copy];\n\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (instancetype)initWithDeferredPayload:(ICLPayload *)payload\n{\n\tNSParameterAssert(payload != nil);\n\n\tif ((self = [super init])) {\n\t\t/* All values are immutable which means we\n\t\t don't need to copy their contents. */\n\t\tself->_url = payload.url;\n\t\tself->_urlToInline = payload.urlToInline;\n\t\tself->_lineNumber = payload.lineNumber;\n\t\tself->_index = payload.index;\n\t\tself->_uniqueIdentifier = payload.uniqueIdentifier;\n\t\tself->_viewIdentifier = payload.viewIdentifier;\n\t\tself->_classAttribute = payload.classAttribute;\n\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLPayloadShared.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"ICLPayload.h\"\n#import \"ICLPayloadInternal.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLPayload\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initOnMutate\n{\n\tif ((self = [super initOnMutate])) {\n\t\t[self populateDefaultsPostflight];\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n- (BOOL)populateWithDecoder:(NSCoder *)aDecoder\n{\n\tself->_contentLength = [aDecoder decodeUnsignedIntegerForKey:@\"contentLength\"];\n\tself->_contentSize = [aDecoder decodeSizeForKey:@\"contentSize\"];\n\n\tself->_styleResources = [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [NSURL class], nil]\n\t\t\t\t\t\t\t\t\t\t\t\t\t forKey:@\"styleResources\"];\n\n\tself->_scriptResources = [aDecoder decodeObjectOfClasses:[NSSet setWithObjects:[NSArray class], [NSURL class], nil]\n\t\t\t\t\t\t\t\t\t\t\t\t\t  forKey:@\"scriptResources\"];\n\n\tself->_html = [aDecoder decodeStringForKey:@\"html\"];\n\n\tself->_entrypoint = [aDecoder decodeStringForKey:@\"entrypoint\"];\n\tself->_entrypointPayload = [aDecoder decodeDictionaryForKey:@\"entrypointPayload\"];\n\n\tself->_url = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@\"url\"];\n\tself->_urlToInline = [aDecoder decodeObjectOfClass:[NSURL class] forKey:@\"urlToInline\"];\n\n\tself->_lineNumber = [aDecoder decodeStringForKey:@\"lineNumber\"];\n\n\tself->_uniqueIdentifier = [aDecoder decodeStringForKey:@\"uniqueIdentifier\"];\n\tself->_viewIdentifier = [aDecoder decodeStringForKey:@\"viewIdentifier\"];\n\n\tself->_index = [aDecoder decodeUnsignedIntegerForKey:@\"index\"];\n\n\tself->_classAttribute = [aDecoder decodeStringForKey:@\"classAttribute\"];\n\n\treturn YES;\n}\n\n- (void)encodeWithCoder:(NSCoder *)aCoder\n{\n\t[aCoder encodeUnsignedInteger:self->_contentLength forKey:@\"contentLength\"];\n\t[aCoder encodeSize:self->_contentSize forKey:@\"contentSize\"];\n\n\t[aCoder maybeEncodeObject:self->_styleResources forKey:@\"styleResources\"];\n\t[aCoder maybeEncodeObject:self->_scriptResources forKey:@\"scriptResources\"];\n\n\t[aCoder encodeString:self->_html forKey:@\"html\"];\n\n\t[aCoder maybeEncodeObject:self->_entrypoint forKey:@\"entrypoint\"];\n\t[aCoder maybeEncodeObject:self->_entrypointPayload forKey:@\"entrypointPayload\"];\n\n\t[aCoder encodeObject:self->_url forKey:@\"url\"];\n\t[aCoder encodeObject:self->_urlToInline forKey:@\"urlToInline\"];\n\n\t[aCoder encodeString:self->_lineNumber forKey:@\"lineNumber\"];\n\n\t[aCoder encodeString:self->_uniqueIdentifier forKey:@\"uniqueIdentifier\"];\n\t[aCoder encodeString:self->_viewIdentifier forKey:@\"viewIdentifier\"];\n\n\t[aCoder encodeUnsignedInteger:self->_index forKey:@\"index\"];\n\n\t[aCoder encodeString:self->_classAttribute forKey:@\"classAttribute\"];\n}\n\n+ (BOOL)supportsSecureCoding\n{\n\treturn YES;\n}\n\n- (void)populateDefaultsPostflight\n{\n\tif (self.initializedAsCopy == NO) {\n\t\tself->_contentSize = NSZeroSize;\n\t}\n\n\tSetVariableIfNil(self->_urlToInline, self->_url);\n\tSetVariableIfNil(self->_styleResources, @[]);\n\tSetVariableIfNil(self->_scriptResources, @[]);\n\tSetVariableIfNil(self->_html, @\"\");\n\tSetVariableIfNil(self->_classAttribute, @\"\");\n}\n\n- (void)initializedClassHealthCheck\n{\n\tNSParameterAssert(self->_html != nil);\n\tNSParameterAssert(self->_url != nil);\n\tNSParameterAssert(self->_urlToInline != nil);\n\tNSParameterAssert(self->_lineNumber != nil);\n\tNSParameterAssert(self->_uniqueIdentifier != nil);\n\tNSParameterAssert(self->_viewIdentifier != nil);\n\tNSParameterAssert(self->_classAttribute != nil);\n}\n\n- (id)copyAsMutable:(BOOL)mutableCopy uniquing:(BOOL)uniquing\n{\n\tICLPayload *object = [self allocForCopyAsMutable:mutableCopy];\n\n\tobject->_contentLength = self->_contentLength;\n\tobject->_contentSize = self->_contentSize;\n\n\tobject->_styleResources = self->_styleResources;\n\tobject->_scriptResources = self->_scriptResources;\n\n\tobject->_html = self->_html;\n\n\tobject->_entrypoint = self->_entrypoint;\n\tobject->_entrypointPayload = self->_entrypointPayload;\n\n\tobject->_url = self->_url;\n\tobject->_urlToInline = self->_urlToInline;\n\n\tobject->_lineNumber = self->_lineNumber;\n\n\tobject->_uniqueIdentifier = self->_uniqueIdentifier;\n\tobject->_viewIdentifier = self->_viewIdentifier;\n\n\tobject->_index = self->_index;\n\n\tobject->_classAttribute = self->_classAttribute;\n\n\treturn [object initOnCopy];\n}\n\n- (__kindof XRPortablePropertyObject *)mutableClass\n{\n\treturn [ICLPayloadMutable self];\n}\n\n- (NSDictionary<NSString *, id<NSCopying>> *)entrypointPayload\n{\n\tNSDictionary *payload = self->_entrypointPayload;\n\n\tif (payload == nil) {\n\t\treturn [self entrypointPayloadDefaultContext];\n\t}\n\n\treturn payload;\n}\n\n- (NSDictionary<NSString *, id<NSCopying>> *)entrypointPayloadDefaultContext\n{\n\treturn @{\n\t\t@\"class\" : self->_classAttribute,\n\t\t@\"html\" : self->_html,\n\t\t@\"url\" : self->_url,\n\t\t@\"urlToInline\" : self->_urlToInline,\n\t\t@\"lineNumber\" : self->_lineNumber,\n\t\t@\"uniqueIdentifier\" : self->_uniqueIdentifier\n\t};\n}\n\n- (void)entrypointPayloadSetContext\n{\n\t/* Set context to payload that module sets. */\n\t/* The values set in the context don't change so we\n\t are safe setting and forgetting. */\n\tNSDictionary *payload = self->_entrypointPayload;\n\n\tif (payload == nil) {\n\t\treturn;\n\t}\n\n\tNSDictionary *payloadToSet = [self entrypointPayloadDefaultContext];\n\n\tself->_entrypointPayload = [payload dictionaryByAddingEntries:payloadToSet];\n}\n\n- (NSString *)address\n{\n\treturn self->_url.absoluteString;\n}\n\n- (NSString *)addressToInline\n{\n\treturn self->_urlToInline.absoluteString;\n}\n\n@end\n\n#pragma mark -\n\n@implementation ICLPayloadMutable\n\n@dynamic urlToInline;\n@dynamic contentLength;\n@dynamic contentSize;\n@dynamic styleResources;\n@dynamic scriptResources;\n@dynamic html;\n@dynamic entrypoint;\n@dynamic entrypointPayload;\n@dynamic classAttribute;\n\n+ (BOOL)isMutable\n{\n\treturn YES;\n}\n\n- (__kindof XRPortablePropertyObject *)immutableClass\n{\n\treturn [ICLPayload self];\n}\n\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_BEGIN\n- (instancetype)init\n{\n\treturn [self initOnMutate];\n}\nDESIGNATED_INITIALIZER_EXCEPTION_BODY_END\n\n- (void)setUrlToInline:(NSURL *)urlToInline\n{\n\tNSParameterAssert(urlToInline != nil);\n\tNSParameterAssert(urlToInline.isFileURL == NO);\n\n\tif (self->_urlToInline != urlToInline) {\n\t\tself->_urlToInline = [urlToInline copy];\n\t}\n}\n\n- (void)setContentLength:(unsigned long long)contentLength\n{\n\tif (self->_contentLength != contentLength) {\n\t\tself->_contentLength = contentLength;\n\t}\n}\n\n- (void)setContentSize:(NSSize)contentSize\n{\n\tself->_contentSize = contentSize;\n}\n\n- (void)setStyleResources:(NSArray<NSURL *> *)styleResources\n{\n\tNSParameterAssert(styleResources != nil);\n\n\tif (self->_styleResources != styleResources) {\n\t\tself->_styleResources = [styleResources copy];\n\t}\n}\n\n- (void)setScriptResources:(NSArray<NSURL *> *)scriptResources\n{\n\tNSParameterAssert(scriptResources != nil);\n\n\tif (self->_scriptResources != scriptResources) {\n\t\tself->_scriptResources = [scriptResources copy];\n\t}\n}\n\n- (void)setHtml:(NSString *)html\n{\n\tNSParameterAssert(html != nil);\n\n\tif (self->_html != html) {\n\t\tself->_html = [html copy];\n\t}\n}\n\n- (void)setEntrypoint:(nullable NSString *)entrypoint\n{\n\tif (self->_entrypoint != entrypoint) {\n\t\tself->_entrypoint = [entrypoint copy];\n\t}\n}\n\n- (void)setEntrypointPayload:(nullable NSDictionary<NSString *, id<NSCopying>> *)entrypointPayload\n{\n\tif (self->_entrypointPayload != entrypointPayload) {\n\t\tself->_entrypointPayload = [entrypointPayload copy];\n\n\t\t[self entrypointPayloadSetContext];\n\t}\n}\n\n- (void)setClassAttribute:(NSString *)classAttribute\n{\n\tNSParameterAssert(classAttribute != nil);\n\n\tif (self->_classAttribute != classAttribute) {\n\t\tself->_classAttribute = [classAttribute copy];\n\t}\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLPluginManager.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* TODO: Entitlements do not allow access to plugins outside app in Standard Release */\n\n#import \"ICLPluginProtocol.h\"\n#import \"ICLPluginManagerPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICLPluginManager ()\n@property (nonatomic, assign) BOOL pluginsLoaded;\n@property (nonatomic, copy) NSArray<NSBundle *> *loadedPlugins;\n@property (nonatomic, copy, nullable) NSArray<Class> *loadedModules;\n@end\n\n@implementation ICLPluginManager\n\n+ (ICLPluginManager *)sharedPluginManager\n{\n\tstatic ICLPluginManager *sharedSelf = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tsharedSelf = [[self alloc] init];\n\t});\n\n\treturn sharedSelf;\n}\n\n- (NSURL *)_bundledPluginsURL\n{\n\treturn [RZMainBundle() URLForResource:@\"Extensions\" withExtension:nil];\n}\n\n- (void)loadPluginsAtLocations:(NSArray<NSURL *> *)pluginLocations\n{\n\tNSParameterAssert(pluginLocations != nil);\n\n\tNSAssert((self.pluginsLoaded == NO), @\"Plugins already loaded\");\n\n\tpluginLocations =\n\t[pluginLocations arrayByAddingObject:[self _bundledPluginsURL]];\n\n\tNSMutableArray<NSBundle *> *loadedPlugins = [NSMutableArray array];\n\n\tfor (NSURL *pluginLocation in pluginLocations) {\n\t\tNSString *pluginPath = pluginLocation.path;\n\n\t\tNSArray *plugins = [self _loadPluginsAtPath:pluginPath];\n\n\t\tif (plugins) {\n\t\t\t[loadedPlugins addObjectsFromArray:plugins];\n\t\t}\n\t}\n\n\tself.loadedPlugins = loadedPlugins;\n\n\tself.pluginsLoaded = YES;\n\n\t[self _populateModules];\n}\n\n- (nullable NSArray<NSBundle *> *)_loadPluginsAtPath:(NSString *)pluginsPath\n{\n\tNSParameterAssert(pluginsPath != nil);\n\n\tNSMutableArray<NSBundle *> *loadedPlugins = [NSMutableArray array];\n\n\tNSError *listedFilesError;\n\t\n\tNSArray *listedFiles = [RZFileManager() contentsOfDirectoryAtPath:pluginsPath error:&listedFilesError];\n\n\tif (listedFiles == nil) {\n\t\tLogToConsoleError(\"Failed to list plugins: %{public}@\",\n\t\t\tlistedFilesError.localizedDescription);\n\n\t\treturn nil;\n\t}\n\n\tfor (NSString *file in listedFiles) {\n\t\tif ([file hasSuffix:@\".mediaPlugin\"] == NO) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tNSString *filePath = [pluginsPath stringByAppendingPathComponent:file];\n\n\t\tNSBundle *bundle = [self _loadPluginAtPath:filePath];\n\n\t\tif (bundle == nil) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t[loadedPlugins addObject:bundle];\n\t}\n\n\treturn loadedPlugins;\n}\n\n- (nullable NSBundle *)_loadPluginAtPath:(NSString *)pluginPath\n{\n\tNSParameterAssert(pluginPath != nil);\n\n\t/* Load bundle */\n\tNSBundle *bundle = [NSBundle bundleWithPath:pluginPath];\n\n\tif (bundle == nil) {\n\t\treturn nil;\n\t}\n\n\t/* Check for a principal class */\n\tClass principalClass = bundle.principalClass;\n\n\tif (principalClass == NULL) {\n\t\tLogToConsoleError(\"Failed to load bundle '%{public}@' because of NULL principal class\", bundle.bundleURL.standardizedTildePath);\n\n\t\treturn nil;\n\t}\n\n\t/* Check for conformity */\n\tif ([principalClass conformsToProtocol:@protocol(ICLPluginProtocol)] == NO) {\n\t\tLogToConsoleError(\"Failed to load bundle '%{public}@' because it does not conform to the ICLPluginProtocol protocol\", bundle.bundleURL.standardizedTildePath);\n\n\t\treturn nil;\n\t}\n\n\t/* Success */\n\treturn bundle;\n}\n\n- (void)_populateModules\n{\n\tNSArray *loadedPlugins = self.loadedPlugins;\n\n\tif (loadedPlugins.count == 0) {\n\t\tLogToConsoleInfo(\"No plugins to load modules from\");\n\n\t\treturn;\n\t}\n\n\tNSMutableArray<Class> *loadedModules = [NSMutableArray array];\n\n\tfor (NSBundle *plugin in loadedPlugins) {\n\t\tNSArray *modules = [self _populateModulesForPlugin:plugin];\n\n\t\t[loadedModules addObjectsFromArray:modules];\n\t}\n\n\tself.loadedModules = loadedModules;\n}\n\n- (NSArray<Class> *)_populateModulesForPlugin:(NSBundle *)plugin\n{\n\tNSParameterAssert(plugin != nil);\n\n\t/* We have already proven in -_loadPluginAtPath: that the plugin\n\t conforms to everything so we don't have to perform validation. */\n\tClass <ICLPluginProtocol> principalClass = plugin.principalClass;\n\n\treturn [principalClass performSelector:@selector(modules)];\n}\n\n- (NSArray<Class> *)modules\n{\n\tNSArray *modules = self.loadedModules;\n\n\tif (modules == nil) {\n\t\treturn @[];\n\t}\n\n\treturn modules;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLProcessDelegate.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentProtocol.h\"\n#import \"ICLProcessMainPrivate.h\"\n#import \"ICLProcessDelegatePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICLProcessDelegate\n\n#pragma mark -\n#pragma mark XPC Delegate\n\n- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection\n{\n\tNSXPCInterface *exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ICLInlineContentServerProtocol)];\n\n\t[exportedInterface setClasses:[NSSet setWithObjects:[NSArray class], [NSURL class], nil]\n\t\t\t\t\t  forSelector:@selector(warmServiceByLoadingPluginsAtLocations:)\n\t\t\t\t\targumentIndex:0\n\t\t\t\t\t\t  ofReply:NO];\n\n\tnewConnection.exportedInterface = exportedInterface;\n\n\tICLProcessMain *exportedObject = [[ICLProcessMain alloc] initWithXPCConnection:newConnection];\n\n\tnewConnection.exportedObject = exportedObject;\n\n\tNSXPCInterface *remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(ICLInlineContentClientProtocol)];\n\n\tnewConnection.remoteObjectInterface = remoteObjectInterface;\n\n\t[newConnection resume];\n\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/ICLProcessMain.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <objc/runtime.h>\n\n#import \"NSObjectHelperPrivate.h\"\n#import \"TPCPreferences.h\"\n#import \"TPCPreferencesUserDefaults.h\"\n#import \"ICLInlineContentModulePrivate.h\"\n#import \"ICLPayloadPrivate.h\"\n#import \"ICLPluginManagerPrivate.h\"\n#import \"CoreModulesImportsPrivate.h\"\n#import \"ICLProcessMainPrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\nNSString * const ICLInlineContentErrorDomain = @\"ICLInlineContentErrorDomain\";\n\n@interface ICLProcessMain ()\n@property (nonatomic, strong) NSXPCConnection *serviceConnection;\n@property (readonly, copy) NSArray<Class> *moduleClasses;\n@property (readonly, copy) NSArray<Class> *moduleClassesInCore;\n@property (readonly, copy) NSDictionary<NSString *, NSArray<Class> *> *modules;\n@property (readonly) NSCache *moduleReferences;\n@end\n\n@implementation ICLProcessMain\n\n- (instancetype)init\n{\n\t[self doesNotRecognizeSelector:_cmd];\n\n\treturn nil;\n}\n\n- (instancetype)initWithXPCConnection:(NSXPCConnection *)connection\n{\n\tNSParameterAssert(connection != nil);\n\n\tif ((self = [super init])) {\n\t\tself.serviceConnection = connection;\n\n\t\tLogToConsoleSetDefaultSubsystemToMainBundle(@\"General\");\n\n\t\treturn self;\n\t}\n\n\treturn nil;\n}\n\n#pragma mark -\n#pragma mark XPC Interface\n\n/* List of module classes that are automatically mapped */\n- (NSArray<Class> *)moduleClassesInCore\n{\n\treturn\n\t@[\n\t\t/* This module should ALWAYS be the last\n\t\t in line because it matches any URL. */\n\t\t[ICMAssessedMedia class]\n\t ];\n}\n\n- (NSArray<Class> *)moduleClasses\n{\n\tNSArray *modules = [[ICLPluginManager sharedPluginManager] modules];\n\n\tmodules = [modules arrayByAddingObjectsFromArray:self.moduleClassesInCore];\n\n\treturn modules;\n}\n\n/* Returns a dictionary with the key equal to the domain a module\n maps to and the value a list of modules that map to that domain. */\n/* If a module does not map to a specific domain, then those can be\n accessed by the wildcard key \"*\" */\n- (NSDictionary<NSString *, NSArray<Class> *> *)modules\n{\n\tstatic NSDictionary<NSString *, NSArray<Class> *> *modules = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t/* Add new modules to this array */\n\t\tNSArray *moduleClasses = self.moduleClasses;\n\n\t\t/* Mapping logic */\n\t\tNSMutableDictionary<NSString *, NSMutableArray<Class> *> *modulesOut = [NSMutableDictionary dictionary];\n\n\t\tvoid (^mapModuleDomain)(Class, NSString *) = ^(Class moduleClass, NSString *moduleDomain) {\n\t\t\tNSMutableArray *mappedDomains = modulesOut[moduleDomain];\n\n\t\t\tif (mappedDomains == nil) {\n\t\t\t\tmappedDomains = [NSMutableArray array];\n\n\t\t\t\tmodulesOut[moduleDomain] = mappedDomains;\n\t\t\t}\n\n\t\t\t[mappedDomains addObject:moduleClass];\n\t\t};\n\n\t\tvoid (^mapModuleDomains)(Class, NSArray *) = ^(Class moduleClass, NSArray<NSString *> * _Nullable moduleDomains) {\n\t\t\t/* If the module does not map to a specific domain,\n\t\t\t then map it to a wildcard for all other classes. */\n\t\t\tif (moduleDomains == nil || moduleDomains.count == 0) {\n\t\t\t\tmapModuleDomain(moduleClass, @\"*\");\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Map domains */\n\t\t\tfor (NSString *moduleDomain in moduleDomains) {\n\t\t\t\tmapModuleDomain(moduleClass, moduleDomain);\n\t\t\t}\n\t\t};\n\n\t\tfor (Class moduleClass in moduleClasses) {\n\t\t\tNSArray *moduleDomains = [moduleClass domains];\n\n\t\t\tmapModuleDomains(moduleClass, moduleDomains);\n\t\t}\n\n\t\t/* Replace mutable arrays with immutable copies */\n\t\t[modulesOut performSelectorOnObjectValueAndReplace:@selector(copy)];\n\n\t\tmodules = [modulesOut copy];\n\t});\n\n\treturn modules;\n}\n\n- (void)processURL:(NSURL *)url withUniqueIdentifier:(NSString *)uniqueIdentifier atLineNumber:(NSString *)lineNumber index:(NSUInteger)index inView:(NSString *)viewIdentifier\n{\n\tNSParameterAssert(url != nil);\n\tNSParameterAssert(url.isFileURL == NO);\n\tNSParameterAssert(uniqueIdentifier != nil);\n\tNSParameterAssert(lineNumber != nil);\n\tNSParameterAssert(viewIdentifier != nil);\n\n\t  ICLPayloadMutable *payload =\n\t[[ICLPayloadMutable alloc] initWithURL:url\n\t\t\t\t\t  withUniqueIdentifier:uniqueIdentifier\n\t\t\t\t\t\t\t  atLineNumber:lineNumber\n\t\t\t\t\t\t\t\t\t index:index\n\t\t\t\t\t\t\t\t\tinView:viewIdentifier];\n\n\t[self processPayload:payload];\n}\n\n- (void)processPayload:(ICLPayload *)payload\n{\n\tNSParameterAssert(payload != nil);\n\n\tNSString *urlScheme = payload.url.scheme;\n\n\tif ([urlScheme isEqualToString:@\"http\"] == NO &&\n\t\t[urlScheme isEqualToString:@\"https\"] == NO)\n\t{\n\t\treturn;\n\t}\n\n\tICLPayloadMutable *payloadIn = nil;\n\n\tif ([payloadIn isKindOfClass:[ICLPayloadMutable class]] == NO) {\n\t\tpayloadIn = [payload mutableCopy];\n\t} else {\n\t\tpayloadIn = (id)payload;\n\t}\n\n\tBOOL (^processModulesWithDomain)(NSString *) = ^BOOL (NSString *domain) {\n\t\tNSParameterAssert(domain != nil);\n\n\t\tNSArray *modules = self.modules[domain];\n\n\t\tfor (Class module in modules) {\n\t\t\tif ([self _processPayload:payloadIn usingModule:module]) {\n\t\t\t\treturn YES;\n\t\t\t}\n\t\t}\n\n\t\treturn NO;\n\t};\n\n\tNSString *urlHost = payloadIn.url.host;\n\n\tif (processModulesWithDomain(urlHost)) {\n\t\treturn;\n\t}\n\n\t/* If no module accepted responsibility for the urlHost,\n\t then we try modules that do not map to a specific domain. */\n\t(void)processModulesWithDomain(@\"*\");\n}\n\n- (BOOL)_processPayload:(ICLPayloadMutable *)payloadIn usingModule:(Class)moduleClass\n{\n\tNSParameterAssert(payloadIn != nil);\n\tNSParameterAssert(moduleClass != NULL);\n\n\t/* Do not allow unsafe content */\n\tif ([moduleClass contentImageOrVideo] == NO && [TPCPreferences inlineMediaLimitToBasics]) {\n\t\treturn NO;\n\t} else if ([moduleClass contentIsFile] == NO && [TPCPreferences inlineMediaLimitToBasics] && [TPCPreferences inlineMediaLimitBasicsToFiles]) {\n\t\treturn NO;\n\t} else if ([moduleClass contentNotSafeForWork] && [TPCPreferences inlineMediaLimitNaughtyContent]) {\n\t\treturn NO;\n\t} else if ([moduleClass contentUntrusted] && [TPCPreferences inlineMediaLimitUnsafeContent]) {\n\t\treturn NO;\n\t}\n\n\t/* Determine whether this module has an action for this URL. */\n\tNSURL *url = payloadIn.url;\n\n\tICLInlineContentModuleActionBlock actionBlock = [moduleClass actionBlockForURL:url];\n\n\tSEL action = NULL;\n\n\tif (actionBlock == nil) {\n\t\taction = [moduleClass actionForURL:url];\n\t}\n\n\tif (actionBlock == nil && (action == NULL /* || [moduleClass instancesRespondToSelector:action] == NO */)) {\n\t\treturn NO;\n\t}\n\n\t/* Create module and call it */\n\tICLInlineContentModule *module = [[moduleClass alloc] initWithPayload:payloadIn inProcess:self];\n\n\t[self _addReferenceForModule:module];\n\n\tif (actionBlock) {\n\t\tactionBlock(module);\n\t} else {\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Warc-performSelector-leaks\"\n\t\t[module performSelector:action];\n#pragma clang diagnostic pop\n\t}\n\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark State\n\n- (void)_finalizeModule:(ICLInlineContentModule *)module withError:(nullable NSError *)error\n{\n\tNSParameterAssert(module != nil);\n\n\tICLPayload *payload = [module.payload copy];\n\n\t/* Remove reference to module */\n\t[self _removeReferenceForModule:module];\n\n\t/* If you are wondering why so much care has been put into these errors\n\t when we control the code, it's because there are plans to support plugins\n\t for modules in the future so future proofing it is best. */\n\tif (payload.html.length == 0 &&\n\t\tpayload.scriptResources.count == 0)\n\t{\n\t\terror =\n\t\t[NSError errorWithDomain:ICLInlineContentErrorDomain\n\t\t\t\t\t\t\tcode:1001\n\t\t\t\t\t\tuserInfo:@{\n\t\t\tNSLocalizedDescriptionKey : @\"-[ICLPayload scriptResources] must contain at least one path if -[ICLPayload html] is empty\"\n\t\t}];\n\t}\n\telse if (payload.html.length == 0 &&\n\t\t\t payload.entrypoint.length == 0)\n\t{\n\t\terror =\n\t\t[NSError errorWithDomain:ICLInlineContentErrorDomain\n\t\t\t\t\t\t\tcode:1002\n\t\t\t\t\t\tuserInfo:@{\n\t\t\tNSLocalizedDescriptionKey : @\"-[ICLPayload html] and -[ICLPayload entrypoint] cannot both be empty\"\n\t\t}];\n\t}\n\n\tif (error) {\n\t\t[[self remoteObjectProxy] processingPayload:payload failedWithError:error];\n\t} else {\n\t\t[[self remoteObjectProxy] processingPayloadSucceeded:payload];\n\t}\n}\n\n- (void)_cancelModule:(ICLInlineContentModule *)module\n{\n\tNSParameterAssert(module != nil);\n\n\t[self _removeReferenceForModule:module];\n}\n\n- (void)_deferModule:(ICLInlineContentModule *)module asType:(ICLMediaType)type performCheck:(BOOL)performCheck\n{\n\tNSParameterAssert(module != nil);\n\tNSParameterAssert(type == ICLMediaTypeImage ||\n\t\t\t\t\t  type == ICLMediaTypeVideo ||\n\t\t\t\t\t  type == ICLMediaTypeVideoGif);\n\n\tswitch (type) {\n\t\tcase ICLMediaTypeImage:\n\t\t{\n\t\t\tICMInlineImage *imageModule = [[ICMInlineImage alloc] initWithDeferredModule:module];\n\n\t\t\t[self _addReferenceForModule:imageModule];\n\n\t\t\t[imageModule performActionWithImageCheck:performCheck];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ICLMediaTypeVideo:\n\t\t{\n\t\t\tICMInlineVideo *videoModule = [[ICMInlineVideo alloc] initWithDeferredModule:module];\n\n\t\t\t[self _addReferenceForModule:videoModule];\n\n\t\t\t[videoModule performActionWithVideoCheck:performCheck];\n\n\t\t\tbreak;\n\t\t}\n\t\tcase ICLMediaTypeVideoGif:\n\t\t{\n\t\t\tICMInlineGifVideo *videoModule = [[ICMInlineGifVideo alloc] initWithDeferredModule:module];\n\n\t\t\t[self _addReferenceForModule:videoModule];\n\n\t\t\t[videoModule performActionWithVideoCheck:performCheck];\n\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t{\n\t\t\tLogToConsoleError(\"Unexpected media type: %{public}lu\", type);\n\n\t\t\tbreak;\n\t\t} // case\n\t} // switch\n}\n\n#pragma mark -\n#pragma mark Memory\n\n- (NSCache *)moduleReferences\n{\n\tstatic NSCache *modules = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tmodules = [NSCache new];\n\t});\n\n\treturn modules;\n}\n\n- (void)_addReferenceForModule:(ICLInlineContentModule *)module\n{\n\tNSParameterAssert(module != nil);\n\n\t[self.moduleReferences setObject:module forKey:module.description];\n}\n\n- (void)_removeReferenceForModule:(ICLInlineContentModule *)module\n{\n\tNSParameterAssert(module != nil);\n\n\t[self.moduleReferences removeObjectForKey:module.description];\n}\n\n#pragma mark -\n#pragma mark Process Management\n\n- (void)warmServiceByLoadingPluginsAtLocations:(NSArray<NSURL *> *)pluginLocations\n{\n\tNSParameterAssert(pluginLocations != nil);\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t[[ICLPluginManager sharedPluginManager] loadPluginsAtLocations:pluginLocations];\n\t});\n}\n\n- (void)warmServiceByRegisteringDefaults:(NSDictionary<NSString *, id> *)defaults\n{\n\tNSParameterAssert(defaults != nil);\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\t[RZUserDefaults() registerDefaults:defaults];\n\t});\n}\n\n#pragma mark -\n#pragma mark XPC Connection\n\n- (id <ICLInlineContentClientProtocol>)remoteObjectProxy\n{\n\treturn self.serviceConnection.remoteObjectProxy;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Classes/Service/main.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLProcessDelegatePrivate.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wnullability-inferred-on-nested-type\"\n\nint main(int argc, const char *argv[])\n{\n\tICLProcessDelegate *delegate = [ICLProcessDelegate new];\n\n\tNSXPCListener *listener = [NSXPCListener serviceListener];\n\n\tlistener.delegate = delegate;\n\n\t[listener resume];\n\n\treturn 0;\n}\n\n#pragma clang diagnostic pop\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Configurations/Sandbox/Release.entitlements",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.security.app-sandbox</key>\n\t<true/>\n\t<key>com.apple.security.application-groups</key>\n\t<array>\n\t\t<string>8482Q6EPL6.com.codeux.apps.textual</string>\n\t</array>\n\t<key>com.apple.security.network.client</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Headers/Private/ICPCoreMediaPCHPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import <CocoaExtensions/CocoaExtensions.h>\n\n#define NSBundleForClass() \t\\\n\t[NSBundle bundleForClass:self.class]\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Headers/Private/ICPCoreMediaPrivate.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLPluginProtocol.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICPCoreMedia : NSObject <ICLPluginProtocol>\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/ICPCoreMedia.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICPCoreMediaPrivate.h\"\n\n#import \"ICMCommonInlineImages.h\"\n#import \"ICMCommonInlineVideos.h\"\n#import \"ICMDailymotion.h\"\n#import \"ICMGyazo.h\"\n#import \"ICMImgurGifv.h\"\n#import \"ICMPornhub.h\"\n#import \"ICMStreamable.h\"\n#import \"ICMTweet.h\"\n#import \"ICMTwitchClips.h\"\n#import \"ICMTwitchLive.h\"\n#import \"ICMVimeo.h\"\n#import \"ICMXkcd.h\"\n#import \"ICMYouTube.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICPCoreMedia\n\n+ (NSArray<Class> *)modules\n{\n\treturn\n\t@[\n\t\t[ICMDailymotion class],\n\t\t[ICMGyazo class],\n\t\t[ICMImgurGifv class],\n\t\t[ICMPornhub class],\n\t\t[ICMStreamable class],\n\t\t[ICMTweet class],\n\n\t\t/* Twitch now requires a parent= argument when embedding content.\n\t\t This argument acts as the domain that the content will be embedded in the\n\t\t context of to allow security headers to be set. Textual is not a\n\t\t web server. It loads files using file:// scheme. Even using \"localhost\"\n\t\t will not allow embeds to work. Is embedding Twitch really worth the\n\t\t cost of hosting a local server to spoof a localhost? Probably not.  */\n//\t\t[ICMTwitchClips class],\n//\t\t[ICMTwitchLive class],\n\n\t\t[ICMVimeo class],\n\t\t[ICMXkcd class],\n\t\t[ICMYouTube class],\n\n\t\t[ICMCommonInlineVideos class],\n\t\t[ICMCommonInlineImages class]\n\t];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Common Images/ICMCommonInlineImages.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineImage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMCommonInlineImages : ICMInlineImage\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Common Images/ICMCommonInlineImages.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2020 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"TPCPreferences.h\"\n#import \"ICLHelpers.h\"\n#import \"ICMCommonInlineImages.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMCommonInlineImages ()\n@property (readonly, copy, class) NSArray<NSString *> *validFileExtensions;\n@end\n\n@implementation ICMCommonInlineImages\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSString *address = [self _finalAddressForURL:url];\n\n\tif (address == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [super actionBlockForAddress:address];\n}\n\n+ (nullable NSString *)_finalAddressForURL:(NSURL *)url\n{\n\tNSString *urlHost = url.host;\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\tNSString *urlPathExtension = urlPath.pathExtension;\n\n\tBOOL hasFileExtension = [self.validFileExtensions containsObject:urlPathExtension];\n\n\tif (hasFileExtension) {\n\t\tif ([urlHost isDomainOrSubdomain:@\"wikipedia.org\"]) {\n\t\t\t/* Wikipedia URLs end with a file extension but tend to be a web page.\n\t\t\t There was no easy way hotlink these images at the time this exception\n\t\t\t was added. This should be revisited at a later time... */\n\n\t\t\treturn nil;\n\t\t} else if ([urlHost isDomainOrSubdomain:@\"dropbox.com\"]) {\n\t\t\t/* Processed below */\n\t\t} else {\n\t\t\treturn url.absoluteString;\n\t\t}\n\t}\n\n\tNSString *urlScheme = url.scheme;\n\tNSString *urlQuery = url.query.percentEncodedURLQuery;\n\n\tNSString *urlPathCombined = urlPath;\n\n\tif (urlQuery) {\n\t\turlPathCombined = [urlPathCombined stringByAppendingFormat:@\"?%@\", urlQuery];\n\t}\n\n\tif ([urlHost isDomainOrSubdomain:@\"dropbox.com\"])\n\t{\n\t\tif ([urlPathCombined hasPrefix:@\"/s/\"] && hasFileExtension) {\n\t\t\treturn [@\"https://dl.dropboxusercontent.com\" stringByAppendingString:urlPathCombined];\n\t\t}\n\t}\n\telse if ([urlHost isDomain:@\"pbs.twimg.com\"])\n\t{\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\turlPath = [urlPath\n\t\t\t\t   stringByReplacingOccurrencesOfString:@\"\\\\:(large|medium|orig|small|thumb)$\"\n\t\t\t\t\t\t\t\t\t\t\t withString:@\"\"\n\t\t\t\t\t\t\t\t\t\t\t\toptions:NSRegularExpressionSearch\n\t\t\t\t\t\t\t\t\t\t\t\t  range:urlPath.range];\n\n\t\treturn [NSString stringWithFormat:@\"https://pbs.twimg.com%@:orig\", urlPath];\n\t}\n\telse if ([urlHost isDomain:@\"docs.google.com\"])\n\t{\n\t\tif ([urlPath hasPrefix:@\"/file/d/\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *photoId = nil;\n\n\t\tNSArray *components = [urlPath componentsSeparatedByString:@\"/\"];\n\n\t\tif (components.count == 5) {\n\t\t\tif ([components[4] isEqualToString:@\"edit\"]) { // Add a little validation\n\t\t\t\tphotoId = components[3];\n\t\t\t}\n\t\t} else if (components.count == 4) {\n\t\t\tphotoId = components[3];\n\t\t} else {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif (photoId) {\n\t\t\treturn [@\"https://docs.google.com/uc?id=\" stringByAppendingString:photoId];\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"twitpic.com\"])\n\t{\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:1];\n\n\t\tif ([s hasSuffix:@\"/full\"]) {\n\t\t\ts = [s substringToIndex:(s.length - 5)];\n\t\t}\n\n\t\tif (s.alphabeticNumericOnly) {\n\t\t\treturn [NSString stringWithFormat:@\"http://twitpic.com/show/large/%@\", s];\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"instagram.com\"] ||\n\t\t\t [urlHost isDomainOrSubdomain:@\"instagr.am\"])\n\t{\n\t\tif ([urlPath hasPrefix:@\"/p/\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:3];\n\n\t\tif ([s onlyContainsCharactersFromCharacterSet:[NSCharacterSet Ato9UnderscoreDash]]) {\n\t\t\treturn [NSString stringWithFormat:@\"https://www.instagram.com/p/%@/media/?size=l\", s];\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"i.4cdn.org\"])\n\t{\n\t\tif ([urlPath hasSuffix:@\".webm\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *filenameWithoutExtension = urlPath.stringByDeletingPathExtension;\n\n\t\treturn [NSString stringWithFormat:@\"%@://%@%@s.jpg\", urlScheme, urlHost, filenameWithoutExtension];\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"8ch.net\"])\n\t{\n\t\tif ([urlPath hasSuffix:@\".webm\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *filename = urlPath.lastPathComponent;\n\n\t\tNSString *filenameWithoutExtension = filename.stringByDeletingPathExtension;\n\n\t\treturn [NSString stringWithFormat:@\"%@://%@/webm/thumb/%@.jpg\", urlScheme, urlHost, filenameWithoutExtension];\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"f.hatena.ne.jp\"])\n\t{\n\t\tNSArray *components = [urlPath componentsSeparatedByString:@\"/\"];\n\n\t\tif (components.count < 3) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *userId = components[1];\n\t\tNSString *photoId = components[2];\n\n\t\tif (userId.length == 0 || photoId.length < 8) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif (photoId.numericOnly == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *userIdHead = [userId substringToIndex:1];\n\t\tNSString *photoIdHead = [photoId substringToIndex:8];\n\n\t\treturn [NSString stringWithFormat:@\"http://img.f.hatena.ne.jp/images/fotolife/%@/%@/%@/%@.jpg\", userIdHead, userId, photoIdHead, photoId];\n\t}\n\telse if ([urlHost isDomain:@\"puu.sh\"])\n\t{\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:1];\n\n\t\tif (s.alphabeticNumericOnly) {\n\t\t\treturn [NSString stringWithFormat:@\"http://puu.sh/%@.jpg\", s];\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"d.pr\"])\n\t{\n\t\tif ([urlPath hasPrefix:@\"/i/\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:3];\n\n\t\tif (s.alphabeticNumericOnly) {\n\t\t\treturn [NSString stringWithFormat:@\"http://d.pr/i/%@.png\", s];\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"nicovideo.jp\"] ||\n\t\t\t [urlHost isDomain:@\"nico.ms\"])\n\t{\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *videoId = nil;\n\n\t\tNSString *s = nil;\n\n\t\tif ([urlHost isDomain:@\"nico.ms\"]) {\n\t\t\ts = [urlPath substringFromIndex:1];\n\t\t} else if ([urlPath hasPrefix:@\"/watch/\"]) {\n\t\t\ts = [urlPath substringFromIndex:7];\n\t\t}\n\n\t\tif ([s hasPrefix:@\"sm\"] || [s hasPrefix:@\"nm\"]) {\n\t\t\tvideoId = s;\n\t\t}\n\n\t\tif (videoId.length < 3) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tlong long videoNumber = [videoId substringFromIndex:2].longLongValue;\n\n\t\treturn [NSString stringWithFormat:@\"http://tn-skr%lli.smilevideo.jp/smile?i=%lli\", ((videoNumber % 4) + 1), videoNumber];\n\t}\n\telse if ([urlHost isDomain:@\"i.reddituploads.com\"])\n\t{\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:1];\n\n\t\tif (s.alphabeticNumericOnly) {\n\t\t\treturn url.absoluteString;\n\t\t}\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"youtube.com\"] ||\n\t\t\t [urlHost isDomain:@\"youtu.be\"])\n\t{\n\t\t/* If we aren't allowed to embed YouTube,\n\t\t at least show show the thumbnail for the video. */\n\t\tif ([TPCPreferences inlineMediaLimitBasicsToFiles] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif (urlPath.length == 0) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *videoId = nil;\n\n\t\tif ([urlHost isDomain:@\"youtu.be\"]) {\n\t\t\tvideoId = [urlPath substringFromIndex:1];\n\t\t} else {\n\t\t\tNSDictionary *queryItems = urlQuery.URLQueryItems;\n\n\t\t\tvideoId = queryItems[@\"v\"];\n\t\t}\n\n\t\tif (videoId.length < 11) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif (videoId.length > 11) {\n\t\t\tvideoId = [videoId substringToIndex:11];\n\t\t}\n\n\t\treturn [NSString stringWithFormat:@\"http://i.ytimg.com/vi/%@/mqdefault.jpg\", videoId];\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"speedtest.net\"])\n\t{\n\t\tNSArray *components = [urlPath componentsSeparatedByString:@\"/\"];\n\n\t\tif (components.count < 3) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tif ([components[1] isEqualToString:@\"result\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *resultId = components[2];\n\n\t\tif (resultId.numericOnly == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\treturn [NSString stringWithFormat:@\"http://www.speedtest.net/result/%@.png\", resultId];\n\t}\n\telse if ([urlHost isDomain:@\"fuelrats.cloud\"])\n\t{\n\t\tif ([urlPath hasPrefix:@\"/s/\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *s = [urlPath substringFromIndex:3];\n\n\t\tif (s.alphabeticNumericOnly) {\n\t\t\treturn [NSString stringWithFormat:@\"https://fuelrats.cloud/s/%@/preview\", s];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n+ (NSArray<NSString *> *)validFileExtensions\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"jpg\",\n\t\t  @\"jpeg\",\n\t\t  @\"png\",\n\t\t  @\"gif\",\n\t\t  @\"tif\",\n\t\t  @\"tiff\",\n\t\t  @\"svg\",\n\t\t  @\"bmp\"];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Common Videos/ICMCommonInlineVideos.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMCommonInlineVideos : ICMInlineVideo\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Common Videos/ICMCommonInlineVideos.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMCommonInlineVideos.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMCommonInlineVideos ()\n@property (readonly, copy, class) NSArray<NSString *> *validFileExtensions;\n@end\n\n@implementation ICMCommonInlineVideos\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSString *address = [self _finalAddressForURL:url];\n\n\tif (address == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [super actionBlockForAddress:address];\n}\n\n+ (nullable NSString *)_finalAddressForURL:(NSURL *)url\n{\n\tNSString *urlHost = url.host;\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\tNSString *urlPathExtension = urlPath.pathExtension;\n\n\tBOOL hasFileExtension = [self.validFileExtensions containsObject:urlPathExtension];\n\n\tif (hasFileExtension) {\n\t\tif ([urlHost isDomain:@\"video.nest.com\"]) {\n\t\t\t/* Processed below */\n\t\t} else {\n\t\t\treturn url.absoluteString;\n\t\t}\n\t}\n\n\tif ([urlHost isDomain:@\"video.nest.com\"])\n\t{\n\t\tif ([urlPath hasPrefix:@\"/clip/\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tNSString *filename = urlPath.lastPathComponent;\n\n\t\tNSString *filenameWithoutExtension = filename.stringByDeletingPathExtension;\n\n\t\tif (filenameWithoutExtension.alphabeticNumericOnly) {\n\t\t\treturn [NSString stringWithFormat:@\"http://clips.dropcam.com/%@\", filename];\n\t\t}\n\t}\n\n\treturn nil;\n}\n\n+ (NSArray<NSString *> *)validFileExtensions\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"mp4\",\n\t\t  @\"mov\",\n\t\t  @\"m4v\",\n\t\t  @\"3gp\",\n\t\t  @\"3g2\"];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Dailymotion/ICMDailymotion.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMDailymotion : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Dailymotion/ICMDailymotion.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMDailymotion.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMDailymotion\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"videoIdentifier\" : videoIdentifier\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMDailymotion *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif ([urlPath hasPrefix:@\"/video/\"] == NO) {\n\t\treturn nil;\n\t}\n\n\turlPath = [urlPath substringFromIndex:7]; // \"/video/\"\n\n\t/* Cut after first underscore so that URLs such as:\n\t http://www.dailymotion.com/video/x19pvwt_the-fantastic-four-1994-unreleased-roger-corman_shortfilms\n\t Automatically translate to their parent:\n\t http://www.dailymotion.com/video/x19pvwt */\n\tNSInteger underscorePosition = [urlPath stringPosition:@\"_\"];\n\n\tif (underscorePosition > 0) {\n\t\turlPath = [urlPath substringToIndex:underscorePosition];\n\t}\n\n\tNSString *videoIdentifier = urlPath;\n\n\tif (videoIdentifier.isAlphabeticNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"dailymotion.com\",\n\t\t  @\"www.dailymotion.com\",\n\t\t  @\"mobile.dailymotion.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMDailymotion\" withExtension:@\"mustache\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Gyazo/ICMGyazo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLInlineContentModule.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMGyazo : ICLInlineContentModule\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Gyazo/ICMGyazo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMGyazo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMGyazo ()\n@property (nonatomic, copy) NSString *contentIdentifier;\n@end\n\n@implementation ICMGyazo\n\n- (void)_loadContent\n{\n\tNSString *contentAddress = self.payload.address;\n\n\tNSURLComponents *requestComponents = [NSURLComponents componentsWithString:@\"https://api.gyazo.com/api/oembed\"];\n\n\trequestComponents.queryItems =\n\t@[\n\t  [NSURLQueryItem queryItemWithName:@\"url\" value:contentAddress]\n\t];\n\n\tNSURL *requestURL = requestComponents.URL;\n\n\t[ICLHelpers requestJSONDataFromURL:requestURL\n\t\t\t\t\t   completionBlock:^(BOOL success, NSDictionary<NSString *, id> *data) {\n\t\t\t\t\t\t   if (success == NO) {\n\t\t\t\t\t\t\t   [self _unsafeToLoadMedia];\n\n\t\t\t\t\t\t\t   return;\n\t\t\t\t\t\t   }\n\n\t\t\t\t\t\t   [self _processJSONData:data];\n\t\t\t\t\t   }];\n}\n\n- (void)_processJSONData:(NSDictionary<NSString *, id> *)data\n{\n\tNSParameterAssert(data != nil);\n\n\t/* Get \"type\" */\n\tNSString *typeString = data[@\"type\"];\n\n\tif (typeString == nil || [typeString isKindOfClass:[NSString class]] == NO) {\n\t\t[self _unsafeToLoadMedia];\n\n\t\treturn;\n\t}\n\n\t/* Check \"type\" */\n\tif ([typeString isEqualToString:@\"photo\"]) {\n\t\t[self _processJSONDataForImage:data];\n\t} else if ([typeString isEqualToString:@\"video\"]) {\n\t\t[self _processJSONDataForVideo:data];\n\t} else {\n\t\t[self _unsafeToLoadMedia];\n\t}\n}\n\n- (void)_processJSONDataForImage:(NSDictionary<NSString *, id> *)data\n{\n\tNSParameterAssert(data != nil);\n\n\t/* Get \"url\" */\n\tNSString *urlString = data[@\"url\"];\n\n\tif (urlString == nil || [urlString isKindOfClass:[NSString class]] == NO) {\n\t\t[self _unsafeToLoadMedia];\n\n\t\treturn;\n\t}\n\n\t/* Check \"url\" */\n\tNSURL *url = [ICLHelpers URLWithString:urlString];\n\n\tif (url == nil) {\n\t\t[self _unsafeToLoadMedia];\n\n\t\treturn;\n\t}\n\n\t/* Finish */\n\t[self _safeToLoadMediaOfType:ICLMediaTypeImage atURL:url];\n}\n\n- (void)_processJSONDataForVideo:(NSDictionary<NSString *, id> *)data\n{\n\tNSParameterAssert(data != nil);\n\n\t/* Get \"url\" */\n\tNSString *urlString = [NSString stringWithFormat:@\"https://i.gyazo.com/%@.mp4\", self.contentIdentifier];\n\n\t/* Check \"url\" */\n\tNSURL *url = [ICLHelpers URLWithString:urlString];\n\n\tif (url == nil) {\n\t\t[self _unsafeToLoadMedia];\n\n\t\treturn;\n\t}\n\n\t/* Finish */\n\t[self _safeToLoadMediaOfType:ICLMediaTypeVideoGif atURL:url];\n}\n\n- (void)_safeToLoadMediaOfType:(ICLMediaType)type atURL:(NSURL *)url\n{\n\tself.payload.urlToInline = url;\n\n\t[self deferAsType:type];\n}\n\n- (void)_unsafeToLoadMedia\n{\n\t[self cancel];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *contentIdentifier = [self _contentIdentifierForURL:url];\n\n\tif (contentIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMGyazo *moduleTyped = (id)module;\n\n\t\tmoduleTyped.contentIdentifier = contentIdentifier;\n\n\t\t[moduleTyped _loadContent];\n\t} copy];\n}\n\n+ (nullable NSString *)_contentIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length != 33) { // Includes leading slash\n\t\treturn nil;\n\t}\n\n\tNSString *contentIdentifier = [urlPath substringFromIndex:1];\n\n\tif (contentIdentifier.alphabeticNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn contentIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"gyazo.com\",\n\t\t  @\"www.gyazo.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n+ (BOOL)contentImageOrVideo\n{\n\treturn YES;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n- (void)finalizePreflight\n{\n\tself.payload.classAttribute = @\"inlineGyazo\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Imgur .gifv/ICMImgurGifv.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMImgurGifv : ICMInlineGifVideo\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Imgur .gifv/ICMImgurGifv.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMImgurGifv.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMImgurGifv ()\n@property (readonly, copy, class) NSArray<NSString *> *validFileExtensions;\n@end\n\n@implementation ICMImgurGifv\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSString *address = [self _finalAddressForURL:url];\n\n\tif (address == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [super actionBlockForAddress:address];\n}\n\n+ (nullable NSString *)_finalAddressForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\turlPath = [urlPath substringFromIndex:1]; // \"/\"\n\n\tNSString *fileExtension = urlPath.pathExtension;\n\n\tif ([self.validFileExtensions containsObject:fileExtension] == NO) {\n\t\treturn nil;\n\t}\n\n\tNSString *videoIdentifier = urlPath.stringByDeletingPathExtension;\n\n\tif (videoIdentifier.isAlphabeticNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn [NSString stringWithFormat:@\"https://i.imgur.com/%@.mp4\", videoIdentifier];\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"i.imgur.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n+ (NSArray<NSString *> *)validFileExtensions\n{\n\tstatic NSArray<NSString *> *cachedValue = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tcachedValue =\n\t\t@[@\"mp4\",\n\t\t  @\"gif\",\n\t\t  @\"gifv\",\n\t\t  @\"webp\"];\n\t});\n\n\treturn cachedValue;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n- (void)finalizePreflight\n{\n\tself.payload.classAttribute = @\"inlineImgurGifv\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Pornhub/ICMPornhub.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMPornhub : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Pornhub/ICMPornhub.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMPornhub.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMPornhub\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"videoIdentifier\" : videoIdentifier\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMPornhub *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif ([urlPath hasPrefix:@\"/view_video.php\"] == NO) {\n\t\treturn nil;\n\t}\n\n\tNSString *urlQuery = url.query.percentEncodedURLQuery;\n\n\tNSDictionary *queryItems = urlQuery.URLQueryItems;\n\n\tNSString *videoIdentifier = queryItems[@\"viewkey\"];\n\n\tif (videoIdentifier.isAlphabeticNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"pornhub.com\",\n\t\t  @\"www.pornhub.com\",\n\t\t  @\"pornhubpremium.com\",\n\t\t  @\"www.pornhubpremium.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMPornhub\" withExtension:@\"mustache\"];\n}\n\n+ (BOOL)contentNotSafeForWork\n{\n\treturn YES;\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Streamable/ICMStreamable.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMStreamable : ICMInlineVideo\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Streamable/ICMStreamable.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMStreamable.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMStreamable\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tNSString *addressToRequest = [@\"https://api.streamable.com/videos/\" stringByAppendingString:videoIdentifier];\n\n\t[ICLHelpers requestJSONObject:@\"url\"\n\t\t\t\t\t\t   ofType:[NSString class]\n\t\t\t\t\t  inHierarchy:@[@\"files\", @\"mp4\"]\n\t\t\t\t\t  fromAddress:addressToRequest\n\t\t\t\t  completionBlock:^(id object)\n\t{\n\t\tif (object == nil) {\n\t\t\t[self notifyUnsafeToLoadVideo];\n\n\t\t\treturn;\n\t\t}\n\n\t\t[self performActionForAddress:object];\n\t}];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMStreamable *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\tNSString *videoIdentifier = [urlPath trimCharacters:@\"/\"];\n\n\tif (videoIdentifier.isAlphabeticNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"streamable.com\",\n\t\t  @\"www.streamable.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)finalizePreflight\n{\n\tself.payload.classAttribute = @\"inlineStreamable\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitch Clips/ICMTwitchClips.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMTwitchClips : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitch Clips/ICMTwitchClips.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMTwitchClips.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMTwitchClips\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"videoIdentifier\" : videoIdentifier\n\t};\n \n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMTwitchClips *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\turlPath = [urlPath substringFromIndex:1]; // \"/\"\n\n\t// old: /username/NameOfClip\n\t// new: /NameOfClip\n\t//      /NameOfClip/edit\n\tif ([urlPath hasSuffix:@\"/edit\"]) {\n\t\turlPath = [urlPath substringToIndex:(urlPath.length - 5)]; // \"/edit\"\n\t}\n\n\tNSString *videoIdentifier = urlPath;\n\n\tif ([videoIdentifier onlyContainsCharactersFromCharacterSet:\n\t\t [NSCharacterSet Ato9UnderscoreDashForwardSlash]] == NO)\n\t{\n\t\treturn nil;\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"clips.twitch.tv\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMTwitchClips\" withExtension:@\"mustache\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitch Live/ICMTwitchLive.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMTwitchLive : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitch Live/ICMTwitchLive.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMTwitchLive.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\ntypedef NS_ENUM(NSUInteger, ICMTwitchLiveContentTypeContent)\n{\n\tICMTwitchLiveContentTypeUnknown = 0,\n\tICMTwitchLiveContentTypeChannel,\n\tICMTwitchLiveContentTypeVideo\n};\n\n@implementation ICMTwitchLive\n\n- (void)_performActionForContent:(NSString *)contentIdentifier type:(ICMTwitchLiveContentTypeContent)contentType\n{\n\tNSParameterAssert(contentIdentifier != nil);\n\tNSParameterAssert(contentType == ICMTwitchLiveContentTypeChannel ||\n\t\t\t\t\t  contentType == ICMTwitchLiveContentTypeVideo);\n\n\tNSString *contentArgument = nil;\n\n\tif (contentType == ICMTwitchLiveContentTypeChannel) {\n\t\tcontentArgument = @\"channel\";\n\t} else if (contentType == ICMTwitchLiveContentTypeVideo) {\n\t\tcontentArgument = @\"video\";\n\t}\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"contentIdentifier\" : contentIdentifier,\n\t  @\"contentArgument\" : contentArgument\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tICMTwitchLiveContentTypeContent contentType = ICMTwitchLiveContentTypeUnknown;\n\n\tNSString *contentIdentifier = [self _contentIdentifierForURL:url type:&contentType];\n\n\tif (contentIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMTwitchLive *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForContent:contentIdentifier type:contentType];\n\t} copy];\n}\n\n+ (nullable NSString *)_contentIdentifierForURL:(NSURL *)url type:(ICMTwitchLiveContentTypeContent *)contentTypeIn\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\turlPath = [urlPath substringFromIndex:1]; // \"/\"\n\n\t/* These exceptions cover all domains */\n\tif ([urlPath isEqualToString:@\"directory\"] ||\n\t\t[urlPath hasPrefix:@\"directory/\"] ||\n\t\t[urlPath isEqualToString:@\"store\"] ||\n\t\t[urlPath hasPrefix:@\"store/\"])\n\t{\n\t\treturn nil;\n\t}\n\n\t/* Match videos */\n\tif ([urlPath hasPrefix:@\"videos/\"]) {\n\t\turlPath = [urlPath substringFromIndex:7];\n\n\t\tNSString *contentIdentifier = [urlPath trimCharacters:@\"/\"];\n\n\t\tif (contentIdentifier.isNumericOnly == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\t*contentTypeIn = ICMTwitchLiveContentTypeVideo;\n\n\t\treturn contentIdentifier;\n\t}\n\n\t/* Consider any other match a channel */\n\t{\n\t\tNSString *contentIdentifier = [urlPath trimCharacters:@\"/\"];\n\n\t\tif (contentIdentifier.length < 4 ||\n\t\t\tcontentIdentifier.length > 25)\n\t\t{\n\t\t\treturn nil;\n\t\t}\n\n\t\tif ([contentIdentifier onlyContainsCharactersFromCharacterSet:[NSCharacterSet Ato9Underscore]] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\t*contentTypeIn = ICMTwitchLiveContentTypeChannel;\n\n\t\treturn contentIdentifier;\n\t}\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"twitch.tv\",\n\t\t  @\"www.twitch.tv\",\n\t\t  @\"go.twitch.tv\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMTwitchLive\" withExtension:@\"mustache\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitter/ICMTweet.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineHTML.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMTweet : ICMInlineHTML\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Twitter/ICMTweet.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMTweet.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMTweet\n\n- (void)_loadTweetContents\n{\n\tNSString *tweetAddress = self.payload.address;\n\n\tNSURLComponents *requestComponents = [NSURLComponents componentsWithString:@\"https://publish.twitter.com/oembed\"];\n\n\trequestComponents.queryItems =\n\t@[\n\t  [NSURLQueryItem queryItemWithName:@\"dnt\" value:@\"true\"], /* DO NOT TRACK */\n\t  [NSURLQueryItem queryItemWithName:@\"maxwidth\" value:@\"500\"],\n\t  [NSURLQueryItem queryItemWithName:@\"omit_script\" value:@\"true\"],\n\t  [NSURLQueryItem queryItemWithName:@\"url\" value:tweetAddress]\n\t];\n\n\tNSURL *requestURL = requestComponents.URL;\n\n\t[ICLHelpers requestJSONObject:@\"html\"\n\t\t\t\t\t\t   ofType:[NSString class]\n\t\t\t\t\t  inHierarchy:nil\n\t\t\t\t\t\t  fromURL:requestURL\n\t\t\t\t  completionBlock:^(id object) {\n\t\t\t\tif (object == nil) {\n\t\t\t\t\t[self notifyUnableToPresentHTML];\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t[self performActionForHTML:object];\n\t\t\t}];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable SEL)actionForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tif ([self _URLIsTweet:url] == NO) {\n\t\treturn NULL;\n\t}\n\n\treturn @selector(_loadTweetContents);\n}\n\n+ (BOOL)_URLIsTweet:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn NO;\n\t}\n\n\turlPath = [urlPath substringFromIndex:1]; // \"/\"\n\n\tNSArray<NSString *> *components = [urlPath componentsSeparatedByString:@\"/\"];\n\n\tif (components.count < 3) {\n\t\treturn NO;\n\t}\n\n\tif ([components[1] isEqualToString:@\"status\"] == NO) {\n\t\treturn NO;\n\t}\n\n\tif (components[2].isNumericOnly == NO) {\n\t\treturn NO;\n\t}\n\n\treturn YES;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"twitter.com\",\n\t\t  @\"www.twitter.com\",\n\t\t  @\"mobile.twitter.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSArray<NSURL *> *)scriptResources\n{\n\treturn\n\t[[super scriptResources] arrayByAddingObjectsFromArray:\n\t@[\n\t  [NSURL URLWithString:@\"https://platform.twitter.com/widgets.js\"],\n\t  [NSBundleForClass() URLForResource:@\"ICMTweet\" withExtension:@\"js\"]\n\t]];\n}\n\n- (nullable NSString *)entrypoint\n{\n\treturn @\"_ICMTweet\";\n}\n\n- (void)finalizePreflight\n{\n\tself.payload.classAttribute = @\"inlineTweet\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Vimeo/ICMVimeo.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMVimeo : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/Vimeo/ICMVimeo.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMVimeo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMVimeo\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"videoIdentifier\" : videoIdentifier\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMVimeo *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\tNSString *videoIdentifier = [urlPath trimCharacters:@\"/\"];\n\n\tif (videoIdentifier.isNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"vimeo.com\",\n\t\t  @\"www.vimeo.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMVimeo\" withExtension:@\"mustache\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/YouTube/ICMYouTube.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineVideo.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMYouTube : ICMInlineVideoFoundation\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/YouTube/ICMYouTube.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMYouTube.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMYouTube\n\n- (void)_performActionForVideo:(NSString *)videoIdentifier\n{\n\tNSParameterAssert(videoIdentifier != nil);\n\n\tICLPayloadMutable *payload = self.payload;\n\n\tNSDictionary *templateAttributes =\n\t@{\n\t  @\"uniqueIdentifier\" : payload.uniqueIdentifier,\n\t  @\"videoIdentifier\" : videoIdentifier,\n\t  @\"videoStartTime\" : @(self.videoStartTime)\n\t};\n\n\tNSError *templateRenderError = nil;\n\n\tNSString *html = [self.template renderObject:templateAttributes error:&templateRenderError];\n\n\tpayload.html = html;\n\n\t[self finalizeWithError:templateRenderError];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\t\n\tNSTimeInterval startPosition = 0;\n\n\tNSString *videoIdentifier = [self _videoIdentifierForURL:url startPosition:&startPosition];\n\n\tif (videoIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMYouTube *moduleTyped = (id)module;\n\n\t\tmoduleTyped.videoStartTime = startPosition;\n\t\t\n\t\t[moduleTyped _performActionForVideo:videoIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_videoIdentifierForURL:(NSURL *)url startPosition:(NSTimeInterval *)startPosition\n{\n\tNSString *videoIdentifier = nil;\n\n\tNSString *urlHost = url.host;\n\tNSString *urlQuery = url.query.percentEncodedURLQuery;\n\t\n\tNSDictionary *queryItems = urlQuery.URLQueryItems;\n\n\tif ([urlHost isEqualToString:@\"youtu.be\"])\n\t{\n\t\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\t\tif (urlPath.length <= 1) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tvideoIdentifier = [urlPath substringFromIndex:1];\n\t}\n\telse if ([urlHost isDomainOrSubdomain:@\"youtube.com\"])\n\t{\n\t\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\t\tif ([urlPath isEqualToString:@\"/watch\"] == NO) {\n\t\t\treturn nil;\n\t\t}\n\n\t\tvideoIdentifier = queryItems[@\"v\"];\n\t}\n\n\tif (videoIdentifier.length < 11) {\n\t\treturn nil;\n\t}\n\n\tif (videoIdentifier.length > 11) {\n\t\tvideoIdentifier = [videoIdentifier substringToIndex:11];\n\t}\n\n\tNSString *timestamp = queryItems[@\"t\"];\n\n\tif (timestamp) {\n\t\t*startPosition = [self parseYouTubeEsqueTimestamp:timestamp];\n\t}\n\n\treturn videoIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"youtube.com\",\n\t\t  @\"www.youtube.com\",\n\t\t  @\"m.youtube.com\",\n\t\t  @\"youtu.be\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (nullable NSURL *)templateURL\n{\n\treturn [NSBundleForClass() URLForResource:@\"ICMYouTube\" withExtension:@\"mustache\"];\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/xkcd/ICMXkcd.h",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICMInlineImage.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@interface ICMXkcd : ICMInlineImage\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Classes/Modules/xkcd/ICMXkcd.m",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n#import \"ICLHelpers.h\"\n#import \"ICMXkcd.h\"\n\nNS_ASSUME_NONNULL_BEGIN\n\n@implementation ICMXkcd\n\n- (void)_performActionForComic:(NSString *)comicIdentifier\n{\n\tNSParameterAssert(comicIdentifier != nil);\n\n\tNSString *addressToRequest = [NSString stringWithFormat:@\"https://xkcd.com/%@/info.0.json\", comicIdentifier];\n\n\t[ICLHelpers requestJSONObject:@\"img\"\n\t\t\t\t\t\t   ofType:[NSString class]\n\t\t\t\t\t  inHierarchy:nil\n\t\t\t\t\t  fromAddress:addressToRequest\n\t\t\t\t  completionBlock:^(id object)\n\t {\n\t\t if (object == nil) {\n\t\t\t [self notifyUnsafeToLoadImage];\n\n\t\t\t return;\n\t\t }\n\n\t\t [self performActionForAddress:object];\n\t }];\n}\n\n#pragma mark -\n#pragma mark Action Block\n\n+ (nullable ICLInlineContentModuleActionBlock)actionBlockForURL:(NSURL *)url\n{\n\tNSParameterAssert(url != nil);\n\n\tNSString *comicIdentifier = [self _comicIdentifierForURL:url];\n\n\tif (comicIdentifier == nil) {\n\t\treturn nil;\n\t}\n\n\treturn [^(ICLInlineContentModule *module) {\n\t\t__weak ICMXkcd *moduleTyped = (id)module;\n\n\t\t[moduleTyped _performActionForComic:comicIdentifier];\n\t} copy];\n}\n\n+ (nullable NSString *)_comicIdentifierForURL:(NSURL *)url\n{\n\tNSString *urlPath = url.path.percentEncodedURLPath;\n\n\tif (urlPath.length <= 1) {\n\t\treturn nil;\n\t}\n\n\tNSString *comicIdentifier = [urlPath trimCharacters:@\"/\"];\n\n\tif (comicIdentifier.isNumericOnly == NO) {\n\t\treturn nil;\n\t}\n\n\treturn comicIdentifier;\n}\n\n+ (nullable NSArray<NSString *> *)domains\n{\n\tstatic NSArray<NSString *> *domains = nil;\n\n\tstatic dispatch_once_t onceToken;\n\n\tdispatch_once(&onceToken, ^{\n\t\tdomains =\n\t\t@[\n\t\t  @\"xkcd.com\",\n\t\t  @\"www.xkcd.com\"\n\t\t];\n\t});\n\n\treturn domains;\n}\n\n+ (BOOL)contentIsFile\n{\n\treturn YES;\n}\n\n#pragma mark -\n#pragma mark Utilities\n\n- (void)finalizePreflight\n{\n\tself.payload.classAttribute = @\"inlineXkcd\";\n}\n\n@end\n\nNS_ASSUME_NONNULL_END\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Inline Content Loader Core Media.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C469ED520EC600900094EA4 /* ICPCoreMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EA620EC600900094EA4 /* ICPCoreMedia.m */; };\n\t\t4C469ED620EC600900094EA4 /* ICMCommonInlineVideos.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EA920EC600900094EA4 /* ICMCommonInlineVideos.m */; };\n\t\t4C469ED720EC600900094EA4 /* ICMTweet.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EAC20EC600900094EA4 /* ICMTweet.m */; };\n\t\t4C469EDA20EC600900094EA4 /* ICMGyazo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EB620EC600900094EA4 /* ICMGyazo.m */; };\n\t\t4C469EDB20EC600900094EA4 /* ICMStreamable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EB920EC600900094EA4 /* ICMStreamable.m */; };\n\t\t4C469EDC20EC600900094EA4 /* ICMVimeo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EBC20EC600900094EA4 /* ICMVimeo.m */; };\n\t\t4C469EDD20EC600900094EA4 /* ICMPornhub.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EBE20EC600900094EA4 /* ICMPornhub.m */; };\n\t\t4C469EDE20EC600900094EA4 /* ICMImgurGifv.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EC120EC600900094EA4 /* ICMImgurGifv.m */; };\n\t\t4C469EDF20EC600900094EA4 /* ICMYouTube.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EC420EC600900094EA4 /* ICMYouTube.m */; };\n\t\t4C469EE020EC600900094EA4 /* ICMDailymotion.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469EC820EC600900094EA4 /* ICMDailymotion.m */; };\n\t\t4C469EE120EC600900094EA4 /* ICMTwitchClips.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469ECA20EC600900094EA4 /* ICMTwitchClips.m */; };\n\t\t4C469EE220EC600900094EA4 /* ICMTwitchLive.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469ECD20EC600900094EA4 /* ICMTwitchLive.m */; };\n\t\t4C469EE320EC600900094EA4 /* ICMCommonInlineImages.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469ED020EC600900094EA4 /* ICMCommonInlineImages.m */; };\n\t\t4C469EE420EC600900094EA4 /* ICMXkcd.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469ED320EC600900094EA4 /* ICMXkcd.m */; };\n\t\t4C469F3720EC608E00094EA4 /* ICMTweet.js in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F2620EC608E00094EA4 /* ICMTweet.js */; };\n\t\t4C469F3920EC608E00094EA4 /* ICMVimeo.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F2A20EC608E00094EA4 /* ICMVimeo.mustache */; };\n\t\t4C469F3A20EC608E00094EA4 /* ICMPornhub.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F2C20EC608E00094EA4 /* ICMPornhub.mustache */; };\n\t\t4C469F3B20EC608E00094EA4 /* ICMYouTube.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F2E20EC608E00094EA4 /* ICMYouTube.mustache */; };\n\t\t4C469F3C20EC608E00094EA4 /* ICMDailymotion.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F3020EC608E00094EA4 /* ICMDailymotion.mustache */; };\n\t\t4C469F3D20EC608E00094EA4 /* ICMTwitchClips.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F3220EC608E00094EA4 /* ICMTwitchClips.mustache */; };\n\t\t4C469F3E20EC608E00094EA4 /* ICMTwitchLive.mustache in Resources */ = {isa = PBXBuildFile; fileRef = 4C469F3420EC608E00094EA4 /* ICMTwitchLive.mustache */; };\n\t\t4CE144E820EC0448000E01C9 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE144E720EC0448000E01C9 /* CocoaExtensions.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\t4C469EA420EC600900094EA4 /* ICPCoreMediaPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICPCoreMediaPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469EA520EC600900094EA4 /* ICPCoreMediaPCHPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICPCoreMediaPCHPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469EA620EC600900094EA4 /* ICPCoreMedia.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICPCoreMedia.m; sourceTree = \"<group>\"; };\n\t\t4C469EA920EC600900094EA4 /* ICMCommonInlineVideos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMCommonInlineVideos.m; sourceTree = \"<group>\"; };\n\t\t4C469EAA20EC600900094EA4 /* ICMCommonInlineVideos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMCommonInlineVideos.h; sourceTree = \"<group>\"; };\n\t\t4C469EAC20EC600900094EA4 /* ICMTweet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMTweet.m; sourceTree = \"<group>\"; };\n\t\t4C469EAD20EC600900094EA4 /* ICMTweet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMTweet.h; sourceTree = \"<group>\"; };\n\t\t4C469EB520EC600900094EA4 /* ICMGyazo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMGyazo.h; sourceTree = \"<group>\"; };\n\t\t4C469EB620EC600900094EA4 /* ICMGyazo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMGyazo.m; sourceTree = \"<group>\"; };\n\t\t4C469EB820EC600900094EA4 /* ICMStreamable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMStreamable.h; sourceTree = \"<group>\"; };\n\t\t4C469EB920EC600900094EA4 /* ICMStreamable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMStreamable.m; sourceTree = \"<group>\"; };\n\t\t4C469EBB20EC600900094EA4 /* ICMVimeo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMVimeo.h; sourceTree = \"<group>\"; };\n\t\t4C469EBC20EC600900094EA4 /* ICMVimeo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMVimeo.m; sourceTree = \"<group>\"; };\n\t\t4C469EBE20EC600900094EA4 /* ICMPornhub.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMPornhub.m; sourceTree = \"<group>\"; };\n\t\t4C469EBF20EC600900094EA4 /* ICMPornhub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMPornhub.h; sourceTree = \"<group>\"; };\n\t\t4C469EC120EC600900094EA4 /* ICMImgurGifv.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMImgurGifv.m; sourceTree = \"<group>\"; };\n\t\t4C469EC220EC600900094EA4 /* ICMImgurGifv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMImgurGifv.h; sourceTree = \"<group>\"; };\n\t\t4C469EC420EC600900094EA4 /* ICMYouTube.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMYouTube.m; sourceTree = \"<group>\"; };\n\t\t4C469EC520EC600900094EA4 /* ICMYouTube.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMYouTube.h; sourceTree = \"<group>\"; };\n\t\t4C469EC720EC600900094EA4 /* ICMDailymotion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMDailymotion.h; sourceTree = \"<group>\"; };\n\t\t4C469EC820EC600900094EA4 /* ICMDailymotion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMDailymotion.m; sourceTree = \"<group>\"; };\n\t\t4C469ECA20EC600900094EA4 /* ICMTwitchClips.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMTwitchClips.m; sourceTree = \"<group>\"; };\n\t\t4C469ECB20EC600900094EA4 /* ICMTwitchClips.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMTwitchClips.h; sourceTree = \"<group>\"; };\n\t\t4C469ECD20EC600900094EA4 /* ICMTwitchLive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMTwitchLive.m; sourceTree = \"<group>\"; };\n\t\t4C469ECE20EC600900094EA4 /* ICMTwitchLive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMTwitchLive.h; sourceTree = \"<group>\"; };\n\t\t4C469ED020EC600900094EA4 /* ICMCommonInlineImages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMCommonInlineImages.m; sourceTree = \"<group>\"; };\n\t\t4C469ED120EC600900094EA4 /* ICMCommonInlineImages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMCommonInlineImages.h; sourceTree = \"<group>\"; };\n\t\t4C469ED320EC600900094EA4 /* ICMXkcd.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMXkcd.m; sourceTree = \"<group>\"; };\n\t\t4C469ED420EC600900094EA4 /* ICMXkcd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMXkcd.h; sourceTree = \"<group>\"; };\n\t\t4C469F0120EC601B00094EA4 /* TPCPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPCPreferences.h; sourceTree = \"<group>\"; };\n\t\t4C469F2620EC608E00094EA4 /* ICMTweet.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ICMTweet.js; sourceTree = \"<group>\"; };\n\t\t4C469F2A20EC608E00094EA4 /* ICMVimeo.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMVimeo.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F2C20EC608E00094EA4 /* ICMPornhub.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMPornhub.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F2E20EC608E00094EA4 /* ICMYouTube.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMYouTube.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F3020EC608E00094EA4 /* ICMDailymotion.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMDailymotion.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F3220EC608E00094EA4 /* ICMTwitchClips.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMTwitchClips.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F3420EC608E00094EA4 /* ICMTwitchLive.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMTwitchLive.mustache; sourceTree = \"<group>\"; };\n\t\t4C469F3620EC608E00094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4CA1FE581FA606890095901F /* Core Media.mediaPlugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = \"Core Media.mediaPlugin\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4CE144E720EC0448000E01C9 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CE145B220EC0D5A000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145B620EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145B720EC0D5A000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145C520EC0D5A000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145C620EC0D5A000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145C920EC0D5A000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145CB20EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145CC20EC0D5A000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145DA20EC0D5A000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE145DE20EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL Extensions.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE145DF20EC0D5A000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4CA1FE551FA606890095901F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CE144E820EC0448000E01C9 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4C03B65B1FA6518A00748FE7 /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C03B6731FA6566200748FE7 /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE144E720EC0448000E01C9 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EA120EC600900094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EA220EC600900094EA4 /* Headers */,\n\t\t\t\t4C469EA720EC600900094EA4 /* Modules */,\n\t\t\t\t4C469EE520EC601B00094EA4 /* Shared */,\n\t\t\t\t4C469EA620EC600900094EA4 /* ICPCoreMedia.m */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EA220EC600900094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EA320EC600900094EA4 /* Private */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EA320EC600900094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EA420EC600900094EA4 /* ICPCoreMediaPrivate.h */,\n\t\t\t\t4C469EA520EC600900094EA4 /* ICPCoreMediaPCHPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EA720EC600900094EA4 /* Modules */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469ECF20EC600900094EA4 /* Common Images */,\n\t\t\t\t4C469EA820EC600900094EA4 /* Common Videos */,\n\t\t\t\t4C469EC620EC600900094EA4 /* Dailymotion */,\n\t\t\t\t4C469EB420EC600900094EA4 /* Gyazo */,\n\t\t\t\t4C469EC020EC600900094EA4 /* Imgur .gifv */,\n\t\t\t\t4C469EBD20EC600900094EA4 /* Pornhub */,\n\t\t\t\t4C469EB720EC600900094EA4 /* Streamable */,\n\t\t\t\t4C469EC920EC600900094EA4 /* Twitch Clips */,\n\t\t\t\t4C469ECC20EC600900094EA4 /* Twitch Live */,\n\t\t\t\t4C469EAB20EC600900094EA4 /* Twitter */,\n\t\t\t\t4C469EBA20EC600900094EA4 /* Vimeo */,\n\t\t\t\t4C469ED220EC600900094EA4 /* xkcd */,\n\t\t\t\t4C469EC320EC600900094EA4 /* YouTube */,\n\t\t\t);\n\t\t\tpath = Modules;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EA820EC600900094EA4 /* Common Videos */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EA920EC600900094EA4 /* ICMCommonInlineVideos.m */,\n\t\t\t\t4C469EAA20EC600900094EA4 /* ICMCommonInlineVideos.h */,\n\t\t\t);\n\t\t\tpath = \"Common Videos\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EAB20EC600900094EA4 /* Twitter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EAC20EC600900094EA4 /* ICMTweet.m */,\n\t\t\t\t4C469EAD20EC600900094EA4 /* ICMTweet.h */,\n\t\t\t);\n\t\t\tpath = Twitter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EB420EC600900094EA4 /* Gyazo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EB520EC600900094EA4 /* ICMGyazo.h */,\n\t\t\t\t4C469EB620EC600900094EA4 /* ICMGyazo.m */,\n\t\t\t);\n\t\t\tpath = Gyazo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EB720EC600900094EA4 /* Streamable */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EB820EC600900094EA4 /* ICMStreamable.h */,\n\t\t\t\t4C469EB920EC600900094EA4 /* ICMStreamable.m */,\n\t\t\t);\n\t\t\tpath = Streamable;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EBA20EC600900094EA4 /* Vimeo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EBB20EC600900094EA4 /* ICMVimeo.h */,\n\t\t\t\t4C469EBC20EC600900094EA4 /* ICMVimeo.m */,\n\t\t\t);\n\t\t\tpath = Vimeo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EBD20EC600900094EA4 /* Pornhub */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EBE20EC600900094EA4 /* ICMPornhub.m */,\n\t\t\t\t4C469EBF20EC600900094EA4 /* ICMPornhub.h */,\n\t\t\t);\n\t\t\tpath = Pornhub;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EC020EC600900094EA4 /* Imgur .gifv */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EC120EC600900094EA4 /* ICMImgurGifv.m */,\n\t\t\t\t4C469EC220EC600900094EA4 /* ICMImgurGifv.h */,\n\t\t\t);\n\t\t\tpath = \"Imgur .gifv\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EC320EC600900094EA4 /* YouTube */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EC420EC600900094EA4 /* ICMYouTube.m */,\n\t\t\t\t4C469EC520EC600900094EA4 /* ICMYouTube.h */,\n\t\t\t);\n\t\t\tpath = YouTube;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EC620EC600900094EA4 /* Dailymotion */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EC720EC600900094EA4 /* ICMDailymotion.h */,\n\t\t\t\t4C469EC820EC600900094EA4 /* ICMDailymotion.m */,\n\t\t\t);\n\t\t\tpath = Dailymotion;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EC920EC600900094EA4 /* Twitch Clips */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469ECA20EC600900094EA4 /* ICMTwitchClips.m */,\n\t\t\t\t4C469ECB20EC600900094EA4 /* ICMTwitchClips.h */,\n\t\t\t);\n\t\t\tpath = \"Twitch Clips\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469ECC20EC600900094EA4 /* Twitch Live */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469ECD20EC600900094EA4 /* ICMTwitchLive.m */,\n\t\t\t\t4C469ECE20EC600900094EA4 /* ICMTwitchLive.h */,\n\t\t\t);\n\t\t\tpath = \"Twitch Live\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469ECF20EC600900094EA4 /* Common Images */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469ED020EC600900094EA4 /* ICMCommonInlineImages.m */,\n\t\t\t\t4C469ED120EC600900094EA4 /* ICMCommonInlineImages.h */,\n\t\t\t);\n\t\t\tpath = \"Common Images\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469ED220EC600900094EA4 /* xkcd */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469ED320EC600900094EA4 /* ICMXkcd.m */,\n\t\t\t\t4C469ED420EC600900094EA4 /* ICMXkcd.h */,\n\t\t\t);\n\t\t\tpath = xkcd;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469EE520EC601B00094EA4 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EF420EC601B00094EA4 /* Headers */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tpath = ../../../../Sources/Shared;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C469EF420EC601B00094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F0120EC601B00094EA4 /* TPCPreferences.h */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2420EC608E00094EA4 /* Modules */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F2520EC608E00094EA4 /* Twitter */,\n\t\t\t\t4C469F2920EC608E00094EA4 /* Vimeo */,\n\t\t\t\t4C469F2B20EC608E00094EA4 /* Pornhub */,\n\t\t\t\t4C469F2D20EC608E00094EA4 /* YouTube */,\n\t\t\t\t4C469F2F20EC608E00094EA4 /* Dailymotion */,\n\t\t\t\t4C469F3120EC608E00094EA4 /* Twitch Clips */,\n\t\t\t\t4C469F3320EC608E00094EA4 /* Twitch Live */,\n\t\t\t);\n\t\t\tpath = Modules;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2520EC608E00094EA4 /* Twitter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F2620EC608E00094EA4 /* ICMTweet.js */,\n\t\t\t);\n\t\t\tpath = Twitter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2920EC608E00094EA4 /* Vimeo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F2A20EC608E00094EA4 /* ICMVimeo.mustache */,\n\t\t\t);\n\t\t\tpath = Vimeo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2B20EC608E00094EA4 /* Pornhub */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F2C20EC608E00094EA4 /* ICMPornhub.mustache */,\n\t\t\t);\n\t\t\tpath = Pornhub;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2D20EC608E00094EA4 /* YouTube */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F2E20EC608E00094EA4 /* ICMYouTube.mustache */,\n\t\t\t);\n\t\t\tpath = YouTube;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F2F20EC608E00094EA4 /* Dailymotion */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F3020EC608E00094EA4 /* ICMDailymotion.mustache */,\n\t\t\t);\n\t\t\tpath = Dailymotion;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F3120EC608E00094EA4 /* Twitch Clips */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F3220EC608E00094EA4 /* ICMTwitchClips.mustache */,\n\t\t\t);\n\t\t\tpath = \"Twitch Clips\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F3320EC608E00094EA4 /* Twitch Live */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F3420EC608E00094EA4 /* ICMTwitchLive.mustache */,\n\t\t\t);\n\t\t\tpath = \"Twitch Live\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F3520EC608E00094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F3620EC608E00094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE4F1FA606890095901F = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469EA120EC600900094EA4 /* Classes */,\n\t\t\t\t4CA1FE611FA6069D0095901F /* Resources */,\n\t\t\t\t4CA1FE671FA608E70095901F /* Frameworks */,\n\t\t\t\t4CA1FE591FA606890095901F /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE591FA606890095901F /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CA1FE581FA606890095901F /* Core Media.mediaPlugin */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE611FA6069D0095901F /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CA1FE621FA607390095901F /* Build Settings */,\n\t\t\t\t4C469F2420EC608E00094EA4 /* Modules */,\n\t\t\t\t4C469F3520EC608E00094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE621FA607390095901F /* Build Settings */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CA1FE631FA607450095901F /* Configurations */,\n\t\t\t);\n\t\t\tname = \"Build Settings\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE631FA607450095901F /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145AE20EC0D5A000E01C9 /* Build */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../../../../Configurations;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE671FA608E70095901F /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C03B6731FA6566200748FE7 /* External Frameworks */,\n\t\t\t\t4C03B65B1FA6518A00748FE7 /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145AE20EC0D5A000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145C220EC0D5A000E01C9 /* Common */,\n\t\t\t\t4CE145D720EC0D5A000E01C9 /* Debug */,\n\t\t\t\t4CE145AF20EC0D5A000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145AF20EC0D5A000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145B720EC0D5A000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE145B220EC0D5A000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE145B620EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145C220EC0D5A000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145CC20EC0D5A000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE145C920EC0D5A000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE145C620EC0D5A000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE145C520EC0D5A000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE145CB20EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE145D720EC0D5A000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE145DF20EC0D5A000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE145DA20EC0D5A000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE145DE20EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t4CA1FE571FA606890095901F /* Inline Content Loader Core Media */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4CA1FE5E1FA606890095901F /* Build configuration list for PBXNativeTarget \"Inline Content Loader Core Media\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4CA1FE561FA606890095901F /* Resources */,\n\t\t\t\t4CA1FE551FA606890095901F /* Frameworks */,\n\t\t\t\t4CA1FE541FA606890095901F /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Inline Content Loader Core Media\";\n\t\t\tproductName = \"Core Media\";\n\t\t\tproductReference = 4CA1FE581FA606890095901F /* Core Media.mediaPlugin */;\n\t\t\tproductType = \"com.apple.product-type.bundle\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4CA1FE501FA606890095901F /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tCLASSPREFIX = ICP;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tORGANIZATIONNAME = \"Codeux Software, LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4CA1FE571FA606890095901F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4CA1FE531FA606890095901F /* Build configuration list for PBXProject \"Inline Content Loader Core Media\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4CA1FE4F1FA606890095901F;\n\t\t\tproductRefGroup = 4CA1FE591FA606890095901F /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4CA1FE571FA606890095901F /* Inline Content Loader Core Media */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4CA1FE561FA606890095901F /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469F3920EC608E00094EA4 /* ICMVimeo.mustache in Resources */,\n\t\t\t\t4C469F3E20EC608E00094EA4 /* ICMTwitchLive.mustache in Resources */,\n\t\t\t\t4C469F3B20EC608E00094EA4 /* ICMYouTube.mustache in Resources */,\n\t\t\t\t4C469F3A20EC608E00094EA4 /* ICMPornhub.mustache in Resources */,\n\t\t\t\t4C469F3720EC608E00094EA4 /* ICMTweet.js in Resources */,\n\t\t\t\t4C469F3D20EC608E00094EA4 /* ICMTwitchClips.mustache in Resources */,\n\t\t\t\t4C469F3C20EC608E00094EA4 /* ICMDailymotion.mustache in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4CA1FE541FA606890095901F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469ED720EC600900094EA4 /* ICMTweet.m in Sources */,\n\t\t\t\t4C469EDF20EC600900094EA4 /* ICMYouTube.m in Sources */,\n\t\t\t\t4C469EDA20EC600900094EA4 /* ICMGyazo.m in Sources */,\n\t\t\t\t4C469EE220EC600900094EA4 /* ICMTwitchLive.m in Sources */,\n\t\t\t\t4C469EE320EC600900094EA4 /* ICMCommonInlineImages.m in Sources */,\n\t\t\t\t4C469EDB20EC600900094EA4 /* ICMStreamable.m in Sources */,\n\t\t\t\t4C469EE420EC600900094EA4 /* ICMXkcd.m in Sources */,\n\t\t\t\t4C469EE020EC600900094EA4 /* ICMDailymotion.m in Sources */,\n\t\t\t\t4C469EE120EC600900094EA4 /* ICMTwitchClips.m in Sources */,\n\t\t\t\t4C469ED520EC600900094EA4 /* ICPCoreMedia.m in Sources */,\n\t\t\t\t4C469EDC20EC600900094EA4 /* ICMVimeo.m in Sources */,\n\t\t\t\t4C469EDD20EC600900094EA4 /* ICMPornhub.m in Sources */,\n\t\t\t\t4C469EDE20EC600900094EA4 /* ICMImgurGifv.m in Sources */,\n\t\t\t\t4C469ED620EC600900094EA4 /* ICMCommonInlineVideos.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4CA1FE5C1FA606890095901F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE145DE20EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4CA1FE5D1FA606890095901F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE145B620EC0D5A000E01C9 /* XPC Service - ICL Extensions.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4CA1FE5F1FA606890095901F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/ICPCoreMediaPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.InlineContentLoader-CoreMedia\";\n\t\t\t\tPRODUCT_NAME = \"Core Media\";\n\t\t\t\tWRAPPER_EXTENSION = mediaPlugin;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4CA1FE601FA606890095901F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/ICPCoreMediaPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-extensions.InlineContentLoader-CoreMedia\";\n\t\t\t\tPRODUCT_NAME = \"Core Media\";\n\t\t\t\tWRAPPER_EXTENSION = mediaPlugin;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4CA1FE531FA606890095901F /* Build configuration list for PBXProject \"Inline Content Loader Core Media\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4CA1FE5C1FA606890095901F /* Debug */,\n\t\t\t\t4CA1FE5D1FA606890095901F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4CA1FE5E1FA606890095901F /* Build configuration list for PBXNativeTarget \"Inline Content Loader Core Media\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4CA1FE5F1FA606890095901F /* Debug */,\n\t\t\t\t4CA1FE601FA606890095901F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 4CA1FE501FA606890095901F /* Project object */;\n}\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Dailymotion/ICMDailymotion.mustache",
    "content": "\n<span class=\"inlineVideoService inlineDailymotion\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"560\"\n\t\theight=\"315\"\n\t\tsrc=\"https://www.dailymotion.com/embed/video/{{videoIdentifier}}\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Pornhub/ICMPornhub.mustache",
    "content": "\n<span class=\"inlineVideoService inlinePornhub\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"560\"\n\t\theight=\"315\"\n\t\tsrc=\"https://www.pornhub.com/embed/{{videoIdentifier}}\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Twitch Clips/ICMTwitchClips.mustache",
    "content": "\n<span class=\"inlineVideoService inlineTwitchClips\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"560\"\n\t\theight=\"315\"\n\t\tsrc=\"https://clips.twitch.tv/embed?clip={{videoIdentifier}}&autoplay=false\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Twitch Live/ICMTwitchLive.mustache",
    "content": "\n<span class=\"inlineVideoService inlineTwitchLive\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"560\"\n\t\theight=\"315\"\n\t\tsrc=\"http://player.twitch.tv/?{{contentArgument}}={{contentIdentifier}}&autoplay=false\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Twitter/ICMTweet.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nwindow.twttr = (function() { /* cancer */\n\tvar t = window.twttr;\n\n\tif (t) {\n\t\treturn t;\n\t}\n\n\tt = {};\n\n\tt._e = [];\n\n\tt.ready = function(f) {\n\t\tt._e.push(f);\n\t};\n\n\treturn t;\n}());\n\nvar _ICMTweetPrototypeParent = _ICMInlineHTMLPrototype;\n\nvar _ICMTweetPrototype = function() {\n\t_ICMTweetPrototypeParent.call(this);\n}\n\n_ICMTweetPrototype.prototype = Object.create(_ICMInlineHTMLPrototype.prototype);\n_ICMTweetPrototype.prototype.constructor = _ICMTweetPrototype;\n_ICMTweetPrototype.prototype.superClass = _ICMTweetPrototypeParent.prototype;\n\n_ICMTweetPrototype.prototype.didLoadMedia = function(mediaId, mediaElement)\n{\n\t/* We do not have enough context in the module itself to set \n\tthe appearance of it, but we do once we reach the entrypoint. */\n\tvar themeAppearance = document.body.dataset.appearance;\n\n\tif (themeAppearance === \"dark\") {\n\t\tvar tweet = mediaElement.querySelector(\"blockquote.twitter-tweet\");\n\n\t\ttweet.dataset.theme = \"dark\";\n\t}\n\n\ttwttr.widgets.load(mediaElement);\n};\n\n_ICMTweetPrototype.prototype.tweetRendered = function(event)\n{\n\tTextualScroller.restoreScrolledToBottom();\n};\n\nvar _ICMTweet = null;\n\ntwttr.ready(\n\tfunction(twttr) {\n\t\t_ICMTweet = new _ICMTweetPrototype();\n\n\t\ttwttr.events.bind(\"rendered\", _ICMTweet.tweetRendered);\n\t}\n);\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/Vimeo/ICMVimeo.mustache",
    "content": "\n<span class=\"inlineVideoService inlineVimeo\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"540\"\n\t\theight=\"304\"\n\t\tsrc=\"https://player.vimeo.com/video/{{videoIdentifier}}\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Modules/YouTube/ICMYouTube.mustache",
    "content": "\n<span class=\"inlineVideoService inlineYouTube\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<iframe\n\t\twidth=\"560\"\n\t\theight=\"315\"\n\t\tsrc=\"https://www.youtube.com/embed/{{videoIdentifier}}?start={{videoStartTime}}\"\n\t\tframeborder=\"0\"\n\t\tallowfullscreen\n\t\tclass=\"content\"></iframe>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Extensions/Core Media/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2017, 2018 Codeux Software, LLC. All rights reserved.</string>\n\t<key>NSPrincipalClass</key>\n\t<string>ICPCoreMedia</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Inline Content Loader.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4C469F6C20EC60F000094EA4 /* ICLHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4220EC60F000094EA4 /* ICLHelpers.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F6D20EC60F000094EA4 /* ICLPayloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4420EC60F000094EA4 /* ICLPayloadInternal.h */; };\n\t\t4C469F6E20EC60F100094EA4 /* ICLInlineContentModuleInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4520EC60F000094EA4 /* ICLInlineContentModuleInternal.h */; };\n\t\t4C469F6F20EC60F100094EA4 /* ICLMediaAssessmentInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4620EC60F000094EA4 /* ICLMediaAssessmentInternal.h */; };\n\t\t4C469F7020EC60F100094EA4 /* ICLMediaType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4720EC60F000094EA4 /* ICLMediaType.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7120EC60F100094EA4 /* ICLMediaAssessment.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4820EC60F000094EA4 /* ICLMediaAssessment.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7220EC60F100094EA4 /* ICLPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4920EC60F000094EA4 /* ICLPayload.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7320EC60F100094EA4 /* ICLPluginProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4A20EC60F000094EA4 /* ICLPluginProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7420EC60F100094EA4 /* ICLProcessDelegatePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4C20EC60F000094EA4 /* ICLProcessDelegatePrivate.h */; };\n\t\t4C469F7520EC60F100094EA4 /* ICLPayloadPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4D20EC60F000094EA4 /* ICLPayloadPrivate.h */; };\n\t\t4C469F7620EC60F100094EA4 /* ICLProcessMainPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4E20EC60F000094EA4 /* ICLProcessMainPrivate.h */; };\n\t\t4C469F7720EC60F100094EA4 /* ICLProcessPCHPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F4F20EC60F000094EA4 /* ICLProcessPCHPrivate.h */; };\n\t\t4C469F7820EC60F100094EA4 /* ICLInlineContentProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5020EC60F000094EA4 /* ICLInlineContentProtocol.h */; };\n\t\t4C469F7920EC60F100094EA4 /* ICLPluginManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5120EC60F000094EA4 /* ICLPluginManagerPrivate.h */; };\n\t\t4C469F7A20EC60F100094EA4 /* ICLInlineContentModulePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5220EC60F000094EA4 /* ICLInlineContentModulePrivate.h */; };\n\t\t4C469F7B20EC60F100094EA4 /* CoreModulesImportsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5320EC60F000094EA4 /* CoreModulesImportsPrivate.h */; };\n\t\t4C469F7C20EC60F100094EA4 /* ICLMediaAssessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5420EC60F000094EA4 /* ICLMediaAssessor.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7D20EC60F100094EA4 /* ICLInlineContentModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F5520EC60F000094EA4 /* ICLInlineContentModule.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F7E20EC60F100094EA4 /* ICLInlineContentModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5720EC60F000094EA4 /* ICLInlineContentModule.m */; };\n\t\t4C469F7F20EC60F100094EA4 /* ICLMediaAssessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5820EC60F000094EA4 /* ICLMediaAssessor.m */; };\n\t\t4C469F8020EC60F100094EA4 /* ICLPayloadLocal.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5920EC60F000094EA4 /* ICLPayloadLocal.m */; };\n\t\t4C469F8120EC60F100094EA4 /* ICLProcessMain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5A20EC60F000094EA4 /* ICLProcessMain.m */; };\n\t\t4C469F8220EC60F100094EA4 /* ICLProcessDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5B20EC60F000094EA4 /* ICLProcessDelegate.m */; };\n\t\t4C469F8320EC60F100094EA4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5C20EC60F000094EA4 /* main.m */; };\n\t\t4C469F8420EC60F100094EA4 /* ICLHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5D20EC60F000094EA4 /* ICLHelpers.m */; };\n\t\t4C469F8520EC60F100094EA4 /* ICLPayloadShared.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5E20EC60F000094EA4 /* ICLPayloadShared.m */; };\n\t\t4C469F8620EC60F100094EA4 /* ICLPluginManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F5F20EC60F000094EA4 /* ICLPluginManager.m */; };\n\t\t4C469F8720EC60F100094EA4 /* ICLMediaAssessment.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F6020EC60F000094EA4 /* ICLMediaAssessment.m */; };\n\t\t4C469F8820EC60F100094EA4 /* ICMAssessedMedia.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F6320EC60F000094EA4 /* ICMAssessedMedia.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F8920EC60F100094EA4 /* ICMAssessedMedia.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F6420EC60F000094EA4 /* ICMAssessedMedia.m */; };\n\t\t4C469F8A20EC60F100094EA4 /* ICMInlineVideo.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F6620EC60F000094EA4 /* ICMInlineVideo.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F8B20EC60F100094EA4 /* ICMInlineHTML.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F6720EC60F000094EA4 /* ICMInlineHTML.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F8C20EC60F100094EA4 /* ICMInlineImage.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469F6820EC60F000094EA4 /* ICMInlineImage.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4C469F8D20EC60F100094EA4 /* ICMInlineVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F6920EC60F000094EA4 /* ICMInlineVideo.m */; };\n\t\t4C469F8E20EC60F100094EA4 /* ICMInlineImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F6A20EC60F000094EA4 /* ICMInlineImage.m */; };\n\t\t4C469F8F20EC60F100094EA4 /* ICMInlineHTML.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F6B20EC60F000094EA4 /* ICMInlineHTML.m */; };\n\t\t4C469FC220EC610000094EA4 /* TPCPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F9220EC610000094EA4 /* TPCPreferences.m */; };\n\t\t4C469FC320EC610000094EA4 /* TPCPreferencesUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C469F9320EC610000094EA4 /* TPCPreferencesUserDefaults.m */; };\n\t\t4C469FCF20EC610000094EA4 /* TPCPreferencesUserDefaults.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469FA520EC610000094EA4 /* TPCPreferencesUserDefaults.h */; };\n\t\t4C469FD520EC610000094EA4 /* TPCPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C469FAC20EC610000094EA4 /* TPCPreferences.h */; };\n\t\t4C469FF820EC61C900094EA4 /* InlineImageLiveResize.js in Resources */ = {isa = PBXBuildFile; fileRef = 4C469FEC20EC61C900094EA4 /* InlineImageLiveResize.js */; };\n\t\t4C46A01220EC666400094EA4 /* ICMInlineImage.css in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE420EC61C900094EA4 /* ICMInlineImage.css */; };\n\t\t4C46A01320EC666400094EA4 /* ICMInlineImage.js in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE520EC61C900094EA4 /* ICMInlineImage.js */; };\n\t\t4C46A01420EC666400094EA4 /* ICMInlineVideo.js in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE620EC61C900094EA4 /* ICMInlineVideo.js */; };\n\t\t4C46A01520EC666400094EA4 /* ICMInlineHTML.mustache in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE720EC61C900094EA4 /* ICMInlineHTML.mustache */; };\n\t\t4C46A01620EC666400094EA4 /* ICMInlineHTML.css in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE820EC61C900094EA4 /* ICMInlineHTML.css */; };\n\t\t4C46A01720EC666400094EA4 /* ICMInlineVideo.css in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FE920EC61C900094EA4 /* ICMInlineVideo.css */; };\n\t\t4C46A01820EC666400094EA4 /* ICMInlineImage.mustache in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FEA20EC61C900094EA4 /* ICMInlineImage.mustache */; };\n\t\t4C46A01920EC666400094EA4 /* ICMInlineHTML.js in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FEB20EC61C900094EA4 /* ICMInlineHTML.js */; };\n\t\t4C46A01A20EC666400094EA4 /* InlineImageLiveResize.js in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FEC20EC61C900094EA4 /* InlineImageLiveResize.js */; };\n\t\t4C46A01B20EC666400094EA4 /* ICMInlineVideo.mustache in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 4C469FED20EC61C900094EA4 /* ICMInlineVideo.mustache */; };\n\t\t4C8C84391F8E5AEC00062FFD /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8C84381F8E5AE400062FFD /* ImageIO.framework */; };\n\t\t4C9A933A1FA65970003C3DB5 /* Core Media.mediaPlugin in Copy Extensions */ = {isa = PBXBuildFile; fileRef = 4C9A93391FA65970003C3DB5 /* Core Media.mediaPlugin */; };\n\t\t4CE1448020EC01AD000E01C9 /* CocoaExtensions.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE1447F20EC01AD000E01C9 /* CocoaExtensions.framework */; };\n\t\t4CE58BAA1F8A5FB800493E7C /* GRMustache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CE58BA91F8A5F8500493E7C /* GRMustache.framework */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXCopyFilesBuildPhase section */\n\t\t4C03B6781FA656CE00748FE7 /* Copy Extensions */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Extensions;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C9A933A1FA65970003C3DB5 /* Core Media.mediaPlugin in Copy Extensions */,\n\t\t\t);\n\t\t\tname = \"Copy Extensions\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4C8C842B1F8E347500062FFD /* Copy Bundle Resources */ = {\n\t\t\tisa = PBXCopyFilesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tdstPath = Components;\n\t\t\tdstSubfolderSpec = 7;\n\t\t\tfiles = (\n\t\t\t\t4C46A01220EC666400094EA4 /* ICMInlineImage.css in Copy Bundle Resources */,\n\t\t\t\t4C46A01320EC666400094EA4 /* ICMInlineImage.js in Copy Bundle Resources */,\n\t\t\t\t4C46A01420EC666400094EA4 /* ICMInlineVideo.js in Copy Bundle Resources */,\n\t\t\t\t4C46A01520EC666400094EA4 /* ICMInlineHTML.mustache in Copy Bundle Resources */,\n\t\t\t\t4C46A01620EC666400094EA4 /* ICMInlineHTML.css in Copy Bundle Resources */,\n\t\t\t\t4C46A01720EC666400094EA4 /* ICMInlineVideo.css in Copy Bundle Resources */,\n\t\t\t\t4C46A01820EC666400094EA4 /* ICMInlineImage.mustache in Copy Bundle Resources */,\n\t\t\t\t4C46A01920EC666400094EA4 /* ICMInlineHTML.js in Copy Bundle Resources */,\n\t\t\t\t4C46A01A20EC666400094EA4 /* InlineImageLiveResize.js in Copy Bundle Resources */,\n\t\t\t\t4C46A01B20EC666400094EA4 /* ICMInlineVideo.mustache in Copy Bundle Resources */,\n\t\t\t);\n\t\t\tname = \"Copy Bundle Resources\";\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXCopyFilesBuildPhase section */\n\n/* Begin PBXFileReference section */\n\t\t4C1406421F11942B00C73D53 /* Inline Content Loader.xpc */ = {isa = PBXFileReference; explicitFileType = \"wrapper.xpc-service\"; includeInIndex = 0; path = \"Inline Content Loader.xpc\"; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4C1EAB161F89F2BF00A4E647 /* BuildConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BuildConfig.h; path = ../../.tmp/BuildConfig.h; sourceTree = SOURCE_ROOT; };\n\t\t4C469F4220EC60F000094EA4 /* ICLHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLHelpers.h; sourceTree = \"<group>\"; };\n\t\t4C469F4420EC60F000094EA4 /* ICLPayloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayloadInternal.h; sourceTree = \"<group>\"; };\n\t\t4C469F4520EC60F000094EA4 /* ICLInlineContentModuleInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLInlineContentModuleInternal.h; sourceTree = \"<group>\"; };\n\t\t4C469F4620EC60F000094EA4 /* ICLMediaAssessmentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLMediaAssessmentInternal.h; sourceTree = \"<group>\"; };\n\t\t4C469F4720EC60F000094EA4 /* ICLMediaType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLMediaType.h; sourceTree = \"<group>\"; };\n\t\t4C469F4820EC60F000094EA4 /* ICLMediaAssessment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLMediaAssessment.h; sourceTree = \"<group>\"; };\n\t\t4C469F4920EC60F000094EA4 /* ICLPayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayload.h; sourceTree = \"<group>\"; };\n\t\t4C469F4A20EC60F000094EA4 /* ICLPluginProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPluginProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C469F4C20EC60F000094EA4 /* ICLProcessDelegatePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLProcessDelegatePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F4D20EC60F000094EA4 /* ICLPayloadPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPayloadPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F4E20EC60F000094EA4 /* ICLProcessMainPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLProcessMainPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F4F20EC60F000094EA4 /* ICLProcessPCHPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLProcessPCHPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F5020EC60F000094EA4 /* ICLInlineContentProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLInlineContentProtocol.h; sourceTree = \"<group>\"; };\n\t\t4C469F5120EC60F000094EA4 /* ICLPluginManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLPluginManagerPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F5220EC60F000094EA4 /* ICLInlineContentModulePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLInlineContentModulePrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F5320EC60F000094EA4 /* CoreModulesImportsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoreModulesImportsPrivate.h; sourceTree = \"<group>\"; };\n\t\t4C469F5420EC60F000094EA4 /* ICLMediaAssessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLMediaAssessor.h; sourceTree = \"<group>\"; };\n\t\t4C469F5520EC60F000094EA4 /* ICLInlineContentModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICLInlineContentModule.h; sourceTree = \"<group>\"; };\n\t\t4C469F5720EC60F000094EA4 /* ICLInlineContentModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLInlineContentModule.m; sourceTree = \"<group>\"; };\n\t\t4C469F5820EC60F000094EA4 /* ICLMediaAssessor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLMediaAssessor.m; sourceTree = \"<group>\"; };\n\t\t4C469F5920EC60F000094EA4 /* ICLPayloadLocal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLPayloadLocal.m; sourceTree = \"<group>\"; };\n\t\t4C469F5A20EC60F000094EA4 /* ICLProcessMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLProcessMain.m; sourceTree = \"<group>\"; };\n\t\t4C469F5B20EC60F000094EA4 /* ICLProcessDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLProcessDelegate.m; sourceTree = \"<group>\"; };\n\t\t4C469F5C20EC60F000094EA4 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\t4C469F5D20EC60F000094EA4 /* ICLHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLHelpers.m; sourceTree = \"<group>\"; };\n\t\t4C469F5E20EC60F000094EA4 /* ICLPayloadShared.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLPayloadShared.m; sourceTree = \"<group>\"; };\n\t\t4C469F5F20EC60F000094EA4 /* ICLPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLPluginManager.m; sourceTree = \"<group>\"; };\n\t\t4C469F6020EC60F000094EA4 /* ICLMediaAssessment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICLMediaAssessment.m; sourceTree = \"<group>\"; };\n\t\t4C469F6320EC60F000094EA4 /* ICMAssessedMedia.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMAssessedMedia.h; sourceTree = \"<group>\"; };\n\t\t4C469F6420EC60F000094EA4 /* ICMAssessedMedia.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMAssessedMedia.m; sourceTree = \"<group>\"; };\n\t\t4C469F6620EC60F000094EA4 /* ICMInlineVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMInlineVideo.h; sourceTree = \"<group>\"; };\n\t\t4C469F6720EC60F000094EA4 /* ICMInlineHTML.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMInlineHTML.h; sourceTree = \"<group>\"; };\n\t\t4C469F6820EC60F000094EA4 /* ICMInlineImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICMInlineImage.h; sourceTree = \"<group>\"; };\n\t\t4C469F6920EC60F000094EA4 /* ICMInlineVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMInlineVideo.m; sourceTree = \"<group>\"; };\n\t\t4C469F6A20EC60F000094EA4 /* ICMInlineImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMInlineImage.m; sourceTree = \"<group>\"; };\n\t\t4C469F6B20EC60F000094EA4 /* ICMInlineHTML.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ICMInlineHTML.m; sourceTree = \"<group>\"; };\n\t\t4C469F9220EC610000094EA4 /* TPCPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPCPreferences.m; sourceTree = \"<group>\"; };\n\t\t4C469F9320EC610000094EA4 /* TPCPreferencesUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPCPreferencesUserDefaults.m; sourceTree = \"<group>\"; };\n\t\t4C469FA520EC610000094EA4 /* TPCPreferencesUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPCPreferencesUserDefaults.h; sourceTree = \"<group>\"; };\n\t\t4C469FAC20EC610000094EA4 /* TPCPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPCPreferences.h; sourceTree = \"<group>\"; };\n\t\t4C469FE420EC61C900094EA4 /* ICMInlineImage.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = ICMInlineImage.css; sourceTree = \"<group>\"; };\n\t\t4C469FE520EC61C900094EA4 /* ICMInlineImage.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ICMInlineImage.js; sourceTree = \"<group>\"; };\n\t\t4C469FE620EC61C900094EA4 /* ICMInlineVideo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ICMInlineVideo.js; sourceTree = \"<group>\"; };\n\t\t4C469FE720EC61C900094EA4 /* ICMInlineHTML.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMInlineHTML.mustache; sourceTree = \"<group>\"; };\n\t\t4C469FE820EC61C900094EA4 /* ICMInlineHTML.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = ICMInlineHTML.css; sourceTree = \"<group>\"; };\n\t\t4C469FE920EC61C900094EA4 /* ICMInlineVideo.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = ICMInlineVideo.css; sourceTree = \"<group>\"; };\n\t\t4C469FEA20EC61C900094EA4 /* ICMInlineImage.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMInlineImage.mustache; sourceTree = \"<group>\"; };\n\t\t4C469FEB20EC61C900094EA4 /* ICMInlineHTML.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = ICMInlineHTML.js; sourceTree = \"<group>\"; };\n\t\t4C469FEC20EC61C900094EA4 /* InlineImageLiveResize.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = InlineImageLiveResize.js; sourceTree = \"<group>\"; };\n\t\t4C469FED20EC61C900094EA4 /* ICMInlineVideo.mustache */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ICMInlineVideo.mustache; sourceTree = \"<group>\"; };\n\t\t4C469FEF20EC61C900094EA4 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4C8C84381F8E5AE400062FFD /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };\n\t\t4C9A93391FA65970003C3DB5 /* Core Media.mediaPlugin */ = {isa = PBXFileReference; lastKnownFileType = folder; name = \"Core Media.mediaPlugin\"; path = \"../../../.tmp/SharedBuildProducts-ICLExtension/Core Media.mediaPlugin\"; sourceTree = \"<group>\"; };\n\t\t4CA1FE8D1FA6261A0095901F /* BuildExtensions.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = BuildExtensions.sh; sourceTree = \"<group>\"; };\n\t\t4CE1447F20EC01AD000E01C9 /* CocoaExtensions.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaExtensions.framework; path = \"../../.tmp/SharedBuildProducts-Frameworks/CocoaExtensions.framework\"; sourceTree = SOURCE_ROOT; };\n\t\t4CE1448720EC02A3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1448920EC02A3000E01C9 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1448A20EC02A3000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1448C20EC02A3000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1449A20EC02A3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1449B20EC02A3000E01C9 /* Preserve Symbols.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Preserve Symbols.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1449D20EC02A3000E01C9 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE1449E20EC02A3000E01C9 /* Foundation.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Foundation.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE1449F20EC02A3000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE144A120EC02A3000E01C9 /* Foundation Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Foundation Debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE144AF20EC02A3000E01C9 /* Textual.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Textual.xcconfig; sourceTree = \"<group>\"; };\n\t\t4CE144B120EC02A3000E01C9 /* XPC Service - ICL.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Service - ICL.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE144B220EC02A3000E01C9 /* XPC Services.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"XPC Services.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE144B420EC02A3000E01C9 /* Enabled Features.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = \"Enabled Features.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t4CE144E420EC02BD000E01C9 /* Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = \"<group>\"; };\n\t\t4CE144E520EC0381000E01C9 /* ICLInlineContentProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ICLInlineContentProtocol.h; path = Classes/Headers/Private/ICLInlineContentProtocol.h; sourceTree = SOURCE_ROOT; };\n\t\t4CE58BA91F8A5F8500493E7C /* GRMustache.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GRMustache.framework; path = \"../../Frameworks/Static Libraries/Libraries/GRMustache.framework\"; sourceTree = SOURCE_ROOT; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4C14063F1F11942B00C73D53 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4CE58BAA1F8A5FB800493E7C /* GRMustache.framework in Frameworks */,\n\t\t\t\t4C8C84391F8E5AEC00062FFD /* ImageIO.framework in Frameworks */,\n\t\t\t\t4CE1448020EC01AD000E01C9 /* CocoaExtensions.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4C1406391F11942B00C73D53 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F4020EC60F000094EA4 /* Classes */,\n\t\t\t\t4C1406521F1194E900C73D53 /* Resources */,\n\t\t\t\t4C8C72D71F1208F200ED72DB /* Frameworks */,\n\t\t\t\t4C1406431F11942B00C73D53 /* Products */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406431F11942B00C73D53 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1406421F11942B00C73D53 /* Inline Content Loader.xpc */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406521F1194E900C73D53 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C1406531F1194F100C73D53 /* Build Settings */,\n\t\t\t\t4C9A93381FA65960003C3DB5 /* Extensions */,\n\t\t\t\t4C469FE320EC61C900094EA4 /* Modules */,\n\t\t\t\t4C469FEE20EC61C900094EA4 /* Property Lists */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406531F1194F100C73D53 /* Build Settings */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CA1FE8E1FA6261D0095901F /* Build Scripts */,\n\t\t\t\t4C1406541F1194F900C73D53 /* Configurations */,\n\t\t\t\t4C1EAB161F89F2BF00A4E647 /* BuildConfig.h */,\n\t\t\t);\n\t\t\tname = \"Build Settings\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C1406541F1194F900C73D53 /* Configurations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1448320EC02A3000E01C9 /* Build */,\n\t\t\t\t4CE144B520EC02A3000E01C9 /* Sandbox */,\n\t\t\t);\n\t\t\tname = Configurations;\n\t\t\tpath = ../../Configurations;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C469F4020EC60F000094EA4 /* Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F4120EC60F000094EA4 /* Headers */,\n\t\t\t\t4C469F6120EC60F000094EA4 /* Modules */,\n\t\t\t\t4C469F5620EC60F000094EA4 /* Service */,\n\t\t\t\t4C469F9020EC610000094EA4 /* Shared */,\n\t\t\t);\n\t\t\tpath = Classes;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F4120EC60F000094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F4320EC60F000094EA4 /* Internal */,\n\t\t\t\t4C469F4B20EC60F000094EA4 /* Private */,\n\t\t\t\t4C469F4220EC60F000094EA4 /* ICLHelpers.h */,\n\t\t\t\t4C469F5520EC60F000094EA4 /* ICLInlineContentModule.h */,\n\t\t\t\t4C469F4820EC60F000094EA4 /* ICLMediaAssessment.h */,\n\t\t\t\t4C469F5420EC60F000094EA4 /* ICLMediaAssessor.h */,\n\t\t\t\t4C469F4720EC60F000094EA4 /* ICLMediaType.h */,\n\t\t\t\t4C469F4920EC60F000094EA4 /* ICLPayload.h */,\n\t\t\t\t4C469F4A20EC60F000094EA4 /* ICLPluginProtocol.h */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F4320EC60F000094EA4 /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F4420EC60F000094EA4 /* ICLPayloadInternal.h */,\n\t\t\t\t4C469F4520EC60F000094EA4 /* ICLInlineContentModuleInternal.h */,\n\t\t\t\t4C469F4620EC60F000094EA4 /* ICLMediaAssessmentInternal.h */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F4B20EC60F000094EA4 /* Private */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F4C20EC60F000094EA4 /* ICLProcessDelegatePrivate.h */,\n\t\t\t\t4C469F4D20EC60F000094EA4 /* ICLPayloadPrivate.h */,\n\t\t\t\t4C469F4E20EC60F000094EA4 /* ICLProcessMainPrivate.h */,\n\t\t\t\t4C469F4F20EC60F000094EA4 /* ICLProcessPCHPrivate.h */,\n\t\t\t\t4C469F5020EC60F000094EA4 /* ICLInlineContentProtocol.h */,\n\t\t\t\t4C469F5120EC60F000094EA4 /* ICLPluginManagerPrivate.h */,\n\t\t\t\t4C469F5220EC60F000094EA4 /* ICLInlineContentModulePrivate.h */,\n\t\t\t\t4C469F5320EC60F000094EA4 /* CoreModulesImportsPrivate.h */,\n\t\t\t);\n\t\t\tpath = Private;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F5620EC60F000094EA4 /* Service */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F5D20EC60F000094EA4 /* ICLHelpers.m */,\n\t\t\t\t4C469F5720EC60F000094EA4 /* ICLInlineContentModule.m */,\n\t\t\t\t4C469F6020EC60F000094EA4 /* ICLMediaAssessment.m */,\n\t\t\t\t4C469F5820EC60F000094EA4 /* ICLMediaAssessor.m */,\n\t\t\t\t4C469F5920EC60F000094EA4 /* ICLPayloadLocal.m */,\n\t\t\t\t4C469F5E20EC60F000094EA4 /* ICLPayloadShared.m */,\n\t\t\t\t4C469F5F20EC60F000094EA4 /* ICLPluginManager.m */,\n\t\t\t\t4C469F5B20EC60F000094EA4 /* ICLProcessDelegate.m */,\n\t\t\t\t4C469F5A20EC60F000094EA4 /* ICLProcessMain.m */,\n\t\t\t\t4C469F5C20EC60F000094EA4 /* main.m */,\n\t\t\t);\n\t\t\tpath = Service;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F6120EC60F000094EA4 /* Modules */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F6220EC60F000094EA4 /* Assessed Media */,\n\t\t\t\t4C469F6520EC60F000094EA4 /* Root Classes */,\n\t\t\t);\n\t\t\tpath = Modules;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F6220EC60F000094EA4 /* Assessed Media */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F6320EC60F000094EA4 /* ICMAssessedMedia.h */,\n\t\t\t\t4C469F6420EC60F000094EA4 /* ICMAssessedMedia.m */,\n\t\t\t);\n\t\t\tpath = \"Assessed Media\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F6520EC60F000094EA4 /* Root Classes */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F6620EC60F000094EA4 /* ICMInlineVideo.h */,\n\t\t\t\t4C469F6720EC60F000094EA4 /* ICMInlineHTML.h */,\n\t\t\t\t4C469F6820EC60F000094EA4 /* ICMInlineImage.h */,\n\t\t\t\t4C469F6920EC60F000094EA4 /* ICMInlineVideo.m */,\n\t\t\t\t4C469F6A20EC60F000094EA4 /* ICMInlineImage.m */,\n\t\t\t\t4C469F6B20EC60F000094EA4 /* ICMInlineHTML.m */,\n\t\t\t);\n\t\t\tpath = \"Root Classes\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F9020EC610000094EA4 /* Shared */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F9120EC610000094EA4 /* Preferences */,\n\t\t\t\t4C469F9F20EC610000094EA4 /* Headers */,\n\t\t\t);\n\t\t\tname = Shared;\n\t\t\tpath = ../../Sources/Shared;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4C469F9120EC610000094EA4 /* Preferences */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469F9220EC610000094EA4 /* TPCPreferences.m */,\n\t\t\t\t4C469F9320EC610000094EA4 /* TPCPreferencesUserDefaults.m */,\n\t\t\t);\n\t\t\tpath = Preferences;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469F9F20EC610000094EA4 /* Headers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469FB420EC610000094EA4 /* Services */,\n\t\t\t\t4C469FAC20EC610000094EA4 /* TPCPreferences.h */,\n\t\t\t\t4C469FA520EC610000094EA4 /* TPCPreferencesUserDefaults.h */,\n\t\t\t);\n\t\t\tpath = Headers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469FB420EC610000094EA4 /* Services */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE144E520EC0381000E01C9 /* ICLInlineContentProtocol.h */,\n\t\t\t);\n\t\t\tpath = Services;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469FE320EC61C900094EA4 /* Modules */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469FE420EC61C900094EA4 /* ICMInlineImage.css */,\n\t\t\t\t4C469FE520EC61C900094EA4 /* ICMInlineImage.js */,\n\t\t\t\t4C469FE620EC61C900094EA4 /* ICMInlineVideo.js */,\n\t\t\t\t4C469FE720EC61C900094EA4 /* ICMInlineHTML.mustache */,\n\t\t\t\t4C469FE820EC61C900094EA4 /* ICMInlineHTML.css */,\n\t\t\t\t4C469FE920EC61C900094EA4 /* ICMInlineVideo.css */,\n\t\t\t\t4C469FEA20EC61C900094EA4 /* ICMInlineImage.mustache */,\n\t\t\t\t4C469FEB20EC61C900094EA4 /* ICMInlineHTML.js */,\n\t\t\t\t4C469FEC20EC61C900094EA4 /* InlineImageLiveResize.js */,\n\t\t\t\t4C469FED20EC61C900094EA4 /* ICMInlineVideo.mustache */,\n\t\t\t);\n\t\t\tpath = Modules;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C469FEE20EC61C900094EA4 /* Property Lists */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C469FEF20EC61C900094EA4 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"Property Lists\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D31F1208F200ED72DB /* External Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE58BA91F8A5F8500493E7C /* GRMustache.framework */,\n\t\t\t\t4CE1447F20EC01AD000E01C9 /* CocoaExtensions.framework */,\n\t\t\t);\n\t\t\tname = \"External Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D61F1208F200ED72DB /* System Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C8C84381F8E5AE400062FFD /* ImageIO.framework */,\n\t\t\t);\n\t\t\tname = \"System Frameworks\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C8C72D71F1208F200ED72DB /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C8C72D31F1208F200ED72DB /* External Frameworks */,\n\t\t\t\t4C8C72D61F1208F200ED72DB /* System Frameworks */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4C9A93381FA65960003C3DB5 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4C9A93391FA65970003C3DB5 /* Core Media.mediaPlugin */,\n\t\t\t);\n\t\t\tname = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CA1FE8E1FA6261D0095901F /* Build Scripts */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CA1FE8D1FA6261A0095901F /* BuildExtensions.sh */,\n\t\t\t);\n\t\t\tpath = \"Build Scripts\";\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\t4CE1448320EC02A3000E01C9 /* Build */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1449720EC02A3000E01C9 /* Common */,\n\t\t\t\t4CE144AC20EC02A3000E01C9 /* Debug */,\n\t\t\t\t4CE1448420EC02A3000E01C9 /* Standard Release */,\n\t\t\t);\n\t\t\tpath = Build;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1448420EC02A3000E01C9 /* Standard Release */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE1448C20EC02A3000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE1448720EC02A3000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1448920EC02A3000E01C9 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4CE1448A20EC02A3000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = \"Standard Release\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE1449720EC02A3000E01C9 /* Common */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE144A120EC02A3000E01C9 /* Foundation Debug.xcconfig */,\n\t\t\t\t4CE1449E20EC02A3000E01C9 /* Foundation.xcconfig */,\n\t\t\t\t4CE1449B20EC02A3000E01C9 /* Preserve Symbols.xcconfig */,\n\t\t\t\t4CE1449A20EC02A3000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE1449D20EC02A3000E01C9 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4CE1449F20EC02A3000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Common;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE144AC20EC02A3000E01C9 /* Debug */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE144B420EC02A3000E01C9 /* Enabled Features.xcconfig */,\n\t\t\t\t4CE144AF20EC02A3000E01C9 /* Textual.xcconfig */,\n\t\t\t\t4CE144B120EC02A3000E01C9 /* XPC Service - ICL.xcconfig */,\n\t\t\t\t4CE144B220EC02A3000E01C9 /* XPC Services.xcconfig */,\n\t\t\t);\n\t\t\tpath = Debug;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4CE144B520EC02A3000E01C9 /* Sandbox */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4CE144E420EC02BD000E01C9 /* Release.entitlements */,\n\t\t\t);\n\t\t\tname = Sandbox;\n\t\t\tpath = Configurations/Sandbox;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t4CB5C5411FA225EA00E65FB5 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469F8C20EC60F100094EA4 /* ICMInlineImage.h in Headers */,\n\t\t\t\t4C469FCF20EC610000094EA4 /* TPCPreferencesUserDefaults.h in Headers */,\n\t\t\t\t4C469F6C20EC60F000094EA4 /* ICLHelpers.h in Headers */,\n\t\t\t\t4C469FD520EC610000094EA4 /* TPCPreferences.h in Headers */,\n\t\t\t\t4C469F7620EC60F100094EA4 /* ICLProcessMainPrivate.h in Headers */,\n\t\t\t\t4C469F7420EC60F100094EA4 /* ICLProcessDelegatePrivate.h in Headers */,\n\t\t\t\t4C469F7D20EC60F100094EA4 /* ICLInlineContentModule.h in Headers */,\n\t\t\t\t4C469F7820EC60F100094EA4 /* ICLInlineContentProtocol.h in Headers */,\n\t\t\t\t4C469F6E20EC60F100094EA4 /* ICLInlineContentModuleInternal.h in Headers */,\n\t\t\t\t4C469F6F20EC60F100094EA4 /* ICLMediaAssessmentInternal.h in Headers */,\n\t\t\t\t4C469F8A20EC60F100094EA4 /* ICMInlineVideo.h in Headers */,\n\t\t\t\t4C469F7920EC60F100094EA4 /* ICLPluginManagerPrivate.h in Headers */,\n\t\t\t\t4C469F7320EC60F100094EA4 /* ICLPluginProtocol.h in Headers */,\n\t\t\t\t4C469F7120EC60F100094EA4 /* ICLMediaAssessment.h in Headers */,\n\t\t\t\t4C469F6D20EC60F000094EA4 /* ICLPayloadInternal.h in Headers */,\n\t\t\t\t4C469F7720EC60F100094EA4 /* ICLProcessPCHPrivate.h in Headers */,\n\t\t\t\t4C469F7C20EC60F100094EA4 /* ICLMediaAssessor.h in Headers */,\n\t\t\t\t4C469F7A20EC60F100094EA4 /* ICLInlineContentModulePrivate.h in Headers */,\n\t\t\t\t4C469F8820EC60F100094EA4 /* ICMAssessedMedia.h in Headers */,\n\t\t\t\t4C469F7020EC60F100094EA4 /* ICLMediaType.h in Headers */,\n\t\t\t\t4C469F7B20EC60F100094EA4 /* CoreModulesImportsPrivate.h in Headers */,\n\t\t\t\t4C469F7220EC60F100094EA4 /* ICLPayload.h in Headers */,\n\t\t\t\t4C469F7520EC60F100094EA4 /* ICLPayloadPrivate.h in Headers */,\n\t\t\t\t4C469F8B20EC60F100094EA4 /* ICMInlineHTML.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t4C1406411F11942B00C73D53 /* Inline Content Loader */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4C14064E1F11942B00C73D53 /* Build configuration list for PBXNativeTarget \"Inline Content Loader\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4C1406401F11942B00C73D53 /* Resources */,\n\t\t\t\t4C8C842B1F8E347500062FFD /* Copy Bundle Resources */,\n\t\t\t\t4C14063F1F11942B00C73D53 /* Frameworks */,\n\t\t\t\t4C14063E1F11942B00C73D53 /* Sources */,\n\t\t\t\t4CB5C5411FA225EA00E65FB5 /* Headers */,\n\t\t\t\t4C03B5311FA6277A00748FE7 /* Build Extensions */,\n\t\t\t\t4C03B6781FA656CE00748FE7 /* Copy Extensions */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"Inline Content Loader\";\n\t\t\tproductName = \"Connection Manager\";\n\t\t\tproductReference = 4C1406421F11942B00C73D53 /* Inline Content Loader.xpc */;\n\t\t\tproductType = \"com.apple.product-type.xpc-service\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4C14063A1F11942B00C73D53 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastUpgradeCheck = 1600;\n\t\t\t\tORGANIZATIONNAME = \"Codeux Software, LLC\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4C1406411F11942B00C73D53 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 8.0;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4C14063D1F11942B00C73D53 /* Build configuration list for PBXProject \"Inline Content Loader\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4C1406391F11942B00C73D53;\n\t\t\tproductRefGroup = 4C1406431F11942B00C73D53 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4C1406411F11942B00C73D53 /* Inline Content Loader */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4C1406401F11942B00C73D53 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469FF820EC61C900094EA4 /* InlineImageLiveResize.js in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t4C03B5311FA6277A00748FE7 /* Build Extensions */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = \"Build Extensions\";\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\nexec \\\"${PROJECT_DIR}/Build Scripts/BuildExtensions.sh\\\" | tee \\\"${TEXTUAL_WORKSPACE_TEMP_DIR}/Script-Logs/BuildExtensions (ICL).txt\\\"\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4C14063E1F11942B00C73D53 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4C469F7F20EC60F100094EA4 /* ICLMediaAssessor.m in Sources */,\n\t\t\t\t4C469FC220EC610000094EA4 /* TPCPreferences.m in Sources */,\n\t\t\t\t4C469FC320EC610000094EA4 /* TPCPreferencesUserDefaults.m in Sources */,\n\t\t\t\t4C469F8520EC60F100094EA4 /* ICLPayloadShared.m in Sources */,\n\t\t\t\t4C469F8420EC60F100094EA4 /* ICLHelpers.m in Sources */,\n\t\t\t\t4C469F8D20EC60F100094EA4 /* ICMInlineVideo.m in Sources */,\n\t\t\t\t4C469F7E20EC60F100094EA4 /* ICLInlineContentModule.m in Sources */,\n\t\t\t\t4C469F8020EC60F100094EA4 /* ICLPayloadLocal.m in Sources */,\n\t\t\t\t4C469F8720EC60F100094EA4 /* ICLMediaAssessment.m in Sources */,\n\t\t\t\t4C469F8620EC60F100094EA4 /* ICLPluginManager.m in Sources */,\n\t\t\t\t4C469F8220EC60F100094EA4 /* ICLProcessDelegate.m in Sources */,\n\t\t\t\t4C469F8120EC60F100094EA4 /* ICLProcessMain.m in Sources */,\n\t\t\t\t4C469F8920EC60F100094EA4 /* ICMAssessedMedia.m in Sources */,\n\t\t\t\t4C469F8F20EC60F100094EA4 /* ICMInlineHTML.m in Sources */,\n\t\t\t\t4C469F8E20EC60F100094EA4 /* ICMInlineImage.m in Sources */,\n\t\t\t\t4C469F8320EC60F100094EA4 /* main.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4C14064C1F11942B00C73D53 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE144B120EC02A3000E01C9 /* XPC Service - ICL.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C14064D1F11942B00C73D53 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 4CE1448920EC02A3000E01C9 /* XPC Service - ICL.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4C14064F1F11942B00C73D53 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/ICLProcessPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-InlineContentLoader\";\n\t\t\t\tPRODUCT_NAME = \"Inline Content Loader\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4C1406501F11942B00C73D53 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \"${PROJECT_DIR}/Configurations/Sandbox/Release.entitlements\";\n\t\t\t\tGCC_PREFIX_HEADER = \"${PROJECT_DIR}/Classes/Headers/Private/ICLProcessPCHPrivate.h\";\n\t\t\t\tINFOPLIST_FILE = \"Resources/Property Lists/Info.plist\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.codeux.app-utilities.Textual-InlineContentLoader\";\n\t\t\t\tPRODUCT_NAME = \"Inline Content Loader\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4C14063D1F11942B00C73D53 /* Build configuration list for PBXProject \"Inline Content Loader\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C14064C1F11942B00C73D53 /* Debug */,\n\t\t\t\t4C14064D1F11942B00C73D53 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4C14064E1F11942B00C73D53 /* Build configuration list for PBXNativeTarget \"Inline Content Loader\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4C14064F1F11942B00C73D53 /* Debug */,\n\t\t\t\t4C1406501F11942B00C73D53 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 4C14063A1F11942B00C73D53 /* Project object */;\n}\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineHTML.css",
    "content": "\n.inlineHTML {\n\toverflow: auto;\n\tdisplay: block;\n\tmargin-top: 12px;\n\tmargin-bottom: 12px;\n\ttext-indent: 0;\n}\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineHTML.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nvar _ICMInlineHTMLPrototypeParent = InlineMediaPrototype;\n\nvar _ICMInlineHTMLPrototype = function() {\n\t_ICMInlineHTMLPrototypeParent.call(this);\n}\n\n_ICMInlineHTMLPrototype.prototype = Object.create(InlineMediaPrototype.prototype);\n_ICMInlineHTMLPrototype.prototype.constructor = _ICMInlineHTMLPrototype;\n_ICMInlineHTMLPrototype.prototype.superClass = _ICMInlineHTMLPrototypeParent.prototype;\n\nvar _ICMInlineHTML = new _ICMInlineHTMLPrototype();\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineHTML.mustache",
    "content": "\n<span class=\"inlineHTML {{classAttribute}}\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineHTML.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<span class=\"content\">\n\t\t{{{unescapedHTML}}}\n\t</span>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineImage.css",
    "content": "\n.inlineImage {\n\toverflow: auto;\n\tdisplay: block;\n\tmargin-top: 12px;\n\tmargin-bottom: 12px;\n}\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineImage.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nvar _ICMInlineImagePrototypeParent = InlineMediaPrototype;\n\nvar _ICMInlineImagePrototype = function() {  \n\t_ICMInlineImagePrototypeParent.call(this);\n}\n\n_ICMInlineImagePrototype.prototype = Object.create(InlineMediaPrototype.prototype);\n_ICMInlineImagePrototype.prototype.constructor = _ICMInlineImagePrototype;\n_ICMInlineImagePrototype.prototype.superClass = _ICMInlineImagePrototypeParent.prototype;\n\nvar _ICMInlineImage = new _ICMInlineImagePrototype();\n\n_ICMInlineImagePrototype.prototype.willShowMedia = function(mediaId, mediaElement) /* PUBLIC */\n{\n\t/* Do not allow user to show the image if this attribute is set. */\n\tif (mediaElement.dataset.disabled === \"true\") {\n\t\treturn false;\n\t}\n\n\treturn this.superClass.willShowMedia.call(this, mediaId, mediaElement);\n};\n\n_ICMInlineImagePrototype.prototype.entrypoint = function(payload, insertHTMLCallback)\n{\n\t/* Call super to insert the HTML for us. */\n\tthis.superClass.entrypoint.call(this, payload, insertHTMLCallback);\n\n\t/* Show the image when finishes loading. */\n\tthis.showImageWhenLoadedWithPayload(payload);\n};\n\n_ICMInlineImagePrototype.prototype.showImageWhenLoadedWithPayload = function(payload)\n{\n\tthis.showImageWhenLoaded(payload.uniqueIdentifier);\n};\n\n_ICMInlineImagePrototype.prototype.showImageWhenLoaded = function(mediaId)\n{\n\tvar imageContainer = document.getInlineMediaById(mediaId);\n\n\tif (!imageContainer) {\t\t\n\t\tconsole.error(\"Failed to find inline media element that matches ID: \" + mediaId);\n\n\t\treturn;\n\t}\n\n\t/* If the image is not already loaded, then we observe \n\tchanges to that so that we only reveal once it is. */\n\tvar imageElement = imageContainer.querySelector(\"a .content\");\n\n\tvar imageComplete = imageElement.complete;\n\n\tvar imageCompleteCallback = (function() {\n\t\tif (imageContainer.dataset.disabled) {\n\t\t\tdelete imageContainer.dataset.disabled;\n\t\t}\n\n\t\timageElement.addEventListener(\"mousedown\", InlineImageLiveResize.onMouseDown, false);\n\n\t\tthis.show(mediaId);\n\t}).bind(this);\n\n\tif (imageComplete) {\n\t\timageCompleteCallback();\n\t} else {\n\t\timageContainer.dataset.disabled = \"true\";\n\n\t\timageElement.addEventListener(\"load\", { handleEvent: imageCompleteCallback }, false);\n\t}\n};\n\nvar _ICMInlineImage = new _ICMInlineImagePrototype();\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineImage.mustache",
    "content": "\n<span class=\"inlineImage {{classAttribute}}\" id=\"inlineMedia-{{uniqueIdentifier}}\" style=\"display: none;\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineImage.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<a href=\"{{anchorLink}}\" onclick=\"return InlineImageLiveResize.negateAnchorOpen()\">\n\t\t<img src=\"{{imageURL}}\" class=\"content\" style=\"max-width: {{preferredMaximumWidth}}px;\" />\n\t</a>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineVideo.css",
    "content": "\n.inlineVideo,\n.inlineVideoService {\n\toverflow: auto;\n\tdisplay: block;\n\tmargin-top: 12px;\n\tmargin-bottom: 12px;\n\ttext-indent: 0;\n}\n\n.inlineVideo video {\n\tbackground-color: #000;\n}\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineVideo.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2017, 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\nvar _ICMInlineVideoPrototypeParent = InlineMediaPrototype;\n\nvar _ICMInlineVideoPrototype = function() {  \n\t_ICMInlineVideoPrototypeParent.call(this);\n}\n\n_ICMInlineVideoPrototype.prototype = Object.create(InlineMediaPrototype.prototype);\n_ICMInlineVideoPrototype.prototype.constructor = _ICMInlineVideoPrototype;\n_ICMInlineVideoPrototype.prototype.superClass = _ICMInlineVideoPrototypeParent.prototype;\n\nvar _ICMInlineVideo = new _ICMInlineVideoPrototype();\n\n_ICMInlineVideo.metadataLoadedCallback = function()\n{\n\tvar video = event.target;\n\n\t/* Video start time */\n\tvar startTime = parseFloat(video.dataset.start);\n\n\tif (startTime > 0.0) {\n\t\tvideo.currentTime = startTime;\n\t}\n\n\t/* Video playback speed (rate) */\n\tvar playbackSpeed = parseFloat(video.dataset.speed);\n\n\tif (playbackSpeed !== 1.0) {\n\t\tvideo.playbackRate = playbackSpeed;\n\t}\n};\n\n_ICMInlineVideo.dataLoadedCallback = function()\n{\n\t/* Loading data can change the height of the video once \n\twe know what it truly will be. We therefore have to tell\n\tthe scroller to restore the scroll position. */\n\n\tTextualScroller.restoreScrolledToBottom();\n};\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/ICMInlineVideo.mustache",
    "content": "\n<span class=\"inlineVideo {{classAttribute}}\" id=\"inlineMedia-{{uniqueIdentifier}}\">\n\t<span class=\"closeButton\" href=\"#\" onclick=\"_ICMInlineVideo.hideOnClick('{{uniqueIdentifier}}');\">×</span>\n\n\t<video\n\n{{#videoAutoplayEnabled}}\n\t\tautoplay\n{{/videoAutoplayEnabled}}\n\n{{#videoControlsEnabled}}\n\t\tcontrols\n{{/videoControlsEnabled}}\n\n{{#videoLoopEnabled}}\n\t\tloop\n{{/videoLoopEnabled}}\n\n{{#videoMuteEnabled}}\n\t\tmuted\n{{/videoMuteEnabled}}\n\n\t\tdata-speed=\"{{videoPlaybackSpeed}}\"\n\t\tdata-start=\"{{videoStartTime}}\"\n\t\tsrc=\"{{videoURL}}\"\n\t\tclass=\"content\"\n\t\tstyle=\"max-width: {{preferredMaximumWidth}}px;\"\n\t\tonloadedmetadata=\"_ICMInlineVideo.metadataLoadedCallback()\"\n\t\tonloadeddata=\"_ICMInlineVideo.dataLoadedCallback()\"></video>\n</span>\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Modules/InlineImageLiveResize.js",
    "content": "/* *********************************************************************\n *                  _____         _               _\n *                 |_   _|____  _| |_ _   _  __ _| |\n *                   | |/ _ \\ \\/ / __| | | |/ _` | |\n *                   | |  __/>  <| |_| |_| | (_| | |\n *                   |_|\\___/_/\\_\\\\__|\\__,_|\\__,_|_|\n *\n * Copyright (c) 2014 Alex Sørlie.\n * Copyright (c) 2010 - 2018 Codeux Software, LLC & respective contributors.\n *       Please see Acknowledgements.pdf for additional information.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n *  * Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *  * Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in the\n *    documentation and/or other materials provided with the distribution.\n *  * Neither the name of Textual, \"Codeux Software, LLC\", nor the\n *    names of its contributors may be used to endorse or promote products\n *    derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n *\n *********************************************************************** */\n\n/* ************************************************** */\n/*                                                    */\n/* DO NOT OVERRIDE ANYTHING BELOW THIS LINE           */\n/*                                                    */\n/* ************************************************** */\n\nvar InlineImageLiveResize = (function () {\n\tfunction InlineImageLiveResize() {\n\t}\n\n\tInlineImageLiveResize.dragElement = null;\n\tInlineImageLiveResize.previousX = null;\n\tInlineImageLiveResize.previousY = null;\n\tInlineImageLiveResize.previousMouseActionWasForResizing = false;\n\n\t/* When the mouse down event is triggered on an element we set the target and record X,Y coordinates.\n\t using preventDefault we halt the default actions taken by the browser, the user can use the shift\n\t key to override InlineImageLiveResize behavior. */\n\tInlineImageLiveResize.onMouseDown = function (e) {\n\t\tif (window.event.shiftKey === false) {\n\t\t\tInlineImageLiveResize.dragElement = e.target;\n\n\t\t\tInlineImageLiveResize.previousX = e.clientX;\n\t\t\tInlineImageLiveResize.previousY = e.clientY;\n\n\t\t\tvar computedSize = window.getComputedStyle(e.target, null);\n\n\t\t\tInlineImageLiveResize.dragElement.style.height = computedSize.getPropertyValue(\"height\");\n\t\t\tInlineImageLiveResize.dragElement.style.width = computedSize.getPropertyValue(\"width\");\n\n\t\t\tInlineImageLiveResize.dragElement.style.maxWidth = null;\n\n\t\t\te.preventDefault();\n\t\t}\n\t};\n\n\t/* The browser has given us a frame to our work on, we will compare the new coordinates of the mouse\n\t the old ones and resize the element accordingly */\n\tInlineImageLiveResize.updateImage = function (x, y) {\n\t\tif (InlineImageLiveResize.dragElement === null ||\n\t\t\tInlineImageLiveResize.dragElement === undefined)\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (InlineImageLiveResize.previousMouseActionWasForResizing === false) {\n\t\t\tInlineImageLiveResize.previousMouseActionWasForResizing = true;\n\t\t}\n\n\t\tif (x > InlineImageLiveResize.previousX && y >= InlineImageLiveResize.previousY) {\n\t\t\tInlineImageLiveResize.dragElement.style.width = (InlineImageLiveResize.dragElement.offsetWidth + (x - InlineImageLiveResize.previousX));\n\t\t\tInlineImageLiveResize.dragElement.style.height = \"auto\";\n\t\t} else if (x < InlineImageLiveResize.previousX && y <= InlineImageLiveResize.previousY) {\n\t\t\tInlineImageLiveResize.dragElement.style.width = (InlineImageLiveResize.dragElement.offsetWidth - (InlineImageLiveResize.previousX - x));\n\t\t\tInlineImageLiveResize.dragElement.style.height = \"auto\";\n\t\t} else if (y > InlineImageLiveResize.previousY && x >= InlineImageLiveResize.previousX) {\n\t\t\tInlineImageLiveResize.dragElement.style.height = (InlineImageLiveResize.dragElement.offsetHeight + (y - InlineImageLiveResize.previousY));\n\t\t\tInlineImageLiveResize.dragElement.style.width = \"auto\";\n\t\t} else if (y < InlineImageLiveResize.previousY && x <= InlineImageLiveResize.previousX) {\n\t\t\tInlineImageLiveResize.dragElement.style.height = (InlineImageLiveResize.dragElement.offsetHeight - (InlineImageLiveResize.previousY - y));\n\t\t\tInlineImageLiveResize.dragElement.style.width = \"auto\";\n\t\t}\n\n\t\tInlineImageLiveResize.previousX = x;\n\t\tInlineImageLiveResize.previousY = y;\n\t};\n\n\t/* Document state tracking. */\n\tInlineImageLiveResize.onMouseDownGeneric = function (e) {\n\t\tInlineImageLiveResize.previousMouseActionWasForResizing = false;\n\t};\n\n\t/* When mouse movement is done we check if the user has clicked on an element previously.\n\t We then request the next rendering frame of the browser to call our event to limit the\n\t amount of resize calculations done to 60fps. */\n\tInlineImageLiveResize.onMouseMove = function (e) {\n\t\tif (InlineImageLiveResize.dragElement) {\n\t\t\trequestAnimationFrame(function () {\n\t\t\t\tInlineImageLiveResize.updateImage(e.clientX, e.clientY);\n\t\t\t});\n\n\t\t\te.preventDefault();\n\t\t}\n\t};\n\n\t/* When the user releases their mouse button we abort the drag action and reset all variables */\n\tInlineImageLiveResize.onMouseUp = function (e) {\n\t\tif (InlineImageLiveResize.dragElement) {\n\t\t\tInlineImageLiveResize.dragElement = null;\n\t\t\tInlineImageLiveResize.previousX = null;\n\t\t\tInlineImageLiveResize.previousY = null;\n\n\t\t\te.preventDefault();\n\t\t}\n\t};\n\n\t/* Called by image anchors to know whether to open link. */\n\tInlineImageLiveResize.negateAnchorOpen = function () {\n\t\tif (InlineImageLiveResize.previousMouseActionWasForResizing === true) {\n\t\t\treturn false;\n\t\t} else {\n\t\t\treturn true;\n\t\t}\n\t};\n\n\treturn InlineImageLiveResize;\n})();\n\n/* Bind to events */\ndocument.addEventListener(\"mousedown\", InlineImageLiveResize.onMouseDownGeneric, false);\ndocument.addEventListener(\"mousemove\", InlineImageLiveResize.onMouseMove, false);\ndocument.addEventListener(\"mouseup\", InlineImageLiveResize.onMouseUp, false);\n"
  },
  {
    "path": "XPC Services/Inline Content Loader/Resources/Property Lists/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>NSAppTransportSecurity</key>\n\t<dict>\n\t\t<key>NSAllowsArbitraryLoads</key>\n\t\t<true/>\n\t</dict>\n\t<key>CFBundleDisplayName</key>\n\t<string>Inline Content Loader</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>XPC!</string>\n\t<key>CFBundleVersion</key>\n\t<string>1.0.0</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2017, 2018 Codeux Software, LLC. All rights reserved.</string>\n\t<key>XPCService</key>\n\t<dict>\n\t\t<key>ServiceType</key>\n\t\t<string>Application</string>\n\t</dict>\n</dict>\n</plist>\n"
  }
]